Merge tag 'mmc-for-2026.10-rc2' of https://git.u-boot-project.org/u-boot/custodians/u-boot-mmc
CI: https://git.u-boot-project.org/u-boot/custodians/u-boot-mmc/-/pipelines/781 - Enable MMC CMD23 for multi-block transfers - Various fixes to mmc core - Add PF9453 pmic/regulator driver - Support SCP 4.36 map for renesas-r8a78000
This commit is contained in:
+32
-13
@@ -325,7 +325,7 @@ int mmc_poll_for_busy(struct mmc *mmc, int timeout_ms)
|
||||
if ((status & MMC_STATUS_RDY_FOR_DATA) &&
|
||||
(status & MMC_STATUS_CURR_STATE) !=
|
||||
MMC_STATE_PRG)
|
||||
break;
|
||||
return 0;
|
||||
|
||||
if (status & MMC_STATUS_MASK) {
|
||||
#if !defined(CONFIG_XPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
|
||||
@@ -340,14 +340,10 @@ int mmc_poll_for_busy(struct mmc *mmc, int timeout_ms)
|
||||
udelay(1000);
|
||||
}
|
||||
|
||||
if (timeout_ms <= 0) {
|
||||
#if !defined(CONFIG_XPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
|
||||
log_err("Timeout waiting card ready\n");
|
||||
log_err("Timeout waiting card ready\n");
|
||||
#endif
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
int mmc_set_blocklen(struct mmc *mmc, int len)
|
||||
@@ -461,6 +457,14 @@ static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start,
|
||||
struct mmc_cmd cmd;
|
||||
struct mmc_data data;
|
||||
|
||||
if (blkcnt > 1 && (mmc->host_caps & MMC_CAP_CMD23)) {
|
||||
cmd.cmdidx = MMC_CMD_SET_BLOCK_COUNT;
|
||||
cmd.cmdarg = blkcnt & 0x0000ffff;
|
||||
cmd.resp_type = MMC_RSP_R1;
|
||||
if (mmc_send_cmd(mmc, &cmd, NULL))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (blkcnt > 1)
|
||||
cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
|
||||
else
|
||||
@@ -481,7 +485,7 @@ static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start,
|
||||
if (mmc_send_cmd(mmc, &cmd, &data))
|
||||
return 0;
|
||||
|
||||
if (blkcnt > 1) {
|
||||
if (blkcnt > 1 && !(mmc->host_caps & MMC_CAP_CMD23)) {
|
||||
if (mmc_send_stop_transmission(mmc, false)) {
|
||||
#if !defined(CONFIG_XPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
|
||||
log_err("mmc fail to send stop cmd\n");
|
||||
@@ -494,7 +498,7 @@ static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start,
|
||||
}
|
||||
|
||||
#if !CONFIG_IS_ENABLED(DM_MMC)
|
||||
static int mmc_get_b_max(struct mmc *mmc, void *dst, lbaint_t blkcnt)
|
||||
int mmc_get_b_max(struct mmc *mmc, void *dst, lbaint_t blkcnt)
|
||||
{
|
||||
if (mmc->cfg->ops->get_b_max)
|
||||
return mmc->cfg->ops->get_b_max(mmc, dst, blkcnt);
|
||||
@@ -1037,6 +1041,10 @@ static int mmc_get_capabilities(struct mmc *mmc)
|
||||
|
||||
mmc->card_caps = MMC_MODE_1BIT | MMC_CAP(MMC_LEGACY);
|
||||
|
||||
/* CMD23(SET_BLOCK_COUNT) requires eMMC spec v3.1 or above */
|
||||
if (mmc->version < MMC_VERSION_3)
|
||||
mmc->host_caps &= ~MMC_CAP_CMD23;
|
||||
|
||||
if (mmc_host_is_spi(mmc))
|
||||
return 0;
|
||||
|
||||
@@ -1436,6 +1444,8 @@ static int sd_get_capabilities(struct mmc *mmc)
|
||||
|
||||
if (mmc->scr[0] & SD_DATA_4BIT)
|
||||
mmc->card_caps |= MMC_MODE_4BIT;
|
||||
if (!(mmc->scr[0] & SD_SCR_CMD23_SUPPORT))
|
||||
mmc->host_caps &= ~MMC_CAP_CMD23;
|
||||
|
||||
/* Version 1.0 doesn't support switching */
|
||||
if (mmc->version == SD_VERSION_1_0)
|
||||
@@ -3177,10 +3187,19 @@ int mmc_deinit(struct mmc *mmc)
|
||||
return 0;
|
||||
|
||||
if (IS_SD(mmc)) {
|
||||
caps_filtered = mmc->card_caps &
|
||||
~(MMC_CAP(UHS_SDR12) | MMC_CAP(UHS_SDR25) |
|
||||
MMC_CAP(UHS_SDR50) | MMC_CAP(UHS_DDR50) |
|
||||
MMC_CAP(UHS_SDR104));
|
||||
u32 uhs_mask = UHS_CAPS;
|
||||
|
||||
#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
|
||||
/*
|
||||
* Per SD spec, once a card enters 1.8V signaling it
|
||||
* cannot revert to 3.3V without a power cycle.
|
||||
* If the card is operating at 1.8V, keep UHS_SDR12
|
||||
* as the minimum fallback mode.
|
||||
*/
|
||||
if (mmc_sd_card_using_v18(mmc))
|
||||
uhs_mask &= ~MMC_CAP(UHS_SDR12);
|
||||
#endif
|
||||
caps_filtered = mmc->card_caps & ~uhs_mask;
|
||||
|
||||
return sd_select_mode_and_width(mmc, caps_filtered);
|
||||
} else {
|
||||
|
||||
@@ -17,6 +17,10 @@ int mmc_poll_for_busy(struct mmc *mmc, int timeout);
|
||||
|
||||
int mmc_set_blocklen(struct mmc *mmc, int len);
|
||||
|
||||
#if !CONFIG_IS_ENABLED(DM_MMC)
|
||||
int mmc_get_b_max(struct mmc *mmc, void *dst, lbaint_t blkcnt);
|
||||
#endif
|
||||
|
||||
#if CONFIG_IS_ENABLED(BLK)
|
||||
ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt,
|
||||
void *dst);
|
||||
|
||||
+19
-6
@@ -165,7 +165,15 @@ static ulong mmc_write_blocks(struct mmc *mmc, lbaint_t start,
|
||||
|
||||
if (blkcnt == 0)
|
||||
return 0;
|
||||
else if (blkcnt == 1)
|
||||
if (blkcnt > 1 && mmc->host_caps & MMC_CAP_CMD23) {
|
||||
cmd.cmdidx = MMC_CMD_SET_BLOCK_COUNT;
|
||||
cmd.cmdarg = blkcnt & 0x0000ffff;
|
||||
cmd.resp_type = MMC_RSP_R1;
|
||||
if (mmc_send_cmd(mmc, &cmd, NULL))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (blkcnt == 1)
|
||||
cmd.cmdidx = MMC_CMD_WRITE_SINGLE_BLOCK;
|
||||
else
|
||||
cmd.cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK;
|
||||
@@ -191,10 +199,13 @@ static ulong mmc_write_blocks(struct mmc *mmc, lbaint_t start,
|
||||
*/
|
||||
}
|
||||
|
||||
/* SPI multiblock writes terminate using a special
|
||||
* token, not a STOP_TRANSMISSION request.
|
||||
/*
|
||||
* SPI multiblock writes terminate using a special token, not CMD12.
|
||||
* When CMD23 was issued the card auto-terminates, so CMD12 is also
|
||||
* skipped in that case.
|
||||
*/
|
||||
if (!mmc_host_is_spi(mmc) && blkcnt > 1) {
|
||||
if (!mmc_host_is_spi(mmc) && blkcnt > 1 &&
|
||||
!(mmc->host_caps & MMC_CAP_CMD23)) {
|
||||
cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
|
||||
cmd.cmdarg = 0;
|
||||
cmd.resp_type = MMC_RSP_R1b;
|
||||
@@ -228,6 +239,7 @@ ulong mmc_bwrite(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt,
|
||||
int dev_num = block_dev->devnum;
|
||||
lbaint_t cur, blocks_todo = blkcnt;
|
||||
int err;
|
||||
uint b_max;
|
||||
|
||||
struct mmc *mmc = find_mmc_device(dev_num);
|
||||
if (!mmc)
|
||||
@@ -240,9 +252,10 @@ ulong mmc_bwrite(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt,
|
||||
if (mmc_set_blocklen(mmc, mmc->write_bl_len))
|
||||
return 0;
|
||||
|
||||
b_max = mmc_get_b_max(mmc, (void *)src, blkcnt);
|
||||
|
||||
do {
|
||||
cur = (blocks_todo > mmc->cfg->b_max) ?
|
||||
mmc->cfg->b_max : blocks_todo;
|
||||
cur = (blocks_todo > b_max) ? b_max : blocks_todo;
|
||||
if (mmc_write_blocks(mmc, start, cur, src) != cur)
|
||||
return 0;
|
||||
blocks_todo -= cur;
|
||||
|
||||
+1
-1
@@ -452,7 +452,7 @@ static int rpmb_route_frames(struct mmc *mmc, struct s_rpmb *req,
|
||||
return rpmb_route_read_req(mmc, req, req_cnt, rsp, rsp_cnt);
|
||||
|
||||
case RPMB_REQ_READ_DATA:
|
||||
if (req_cnt != 1 || !req_cnt)
|
||||
if (req_cnt != 1 || !rsp_cnt)
|
||||
return -EINVAL;
|
||||
return rpmb_route_read_req(mmc, req, req_cnt, rsp, rsp_cnt);
|
||||
|
||||
|
||||
+2
-1
@@ -733,7 +733,8 @@ static int sdhci_init(struct mmc *mmc)
|
||||
*/
|
||||
host->force_align_buffer = true;
|
||||
#else
|
||||
if (host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) {
|
||||
if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) &&
|
||||
!host->align_buffer) {
|
||||
host->align_buffer = memalign(8, 512 * 1024);
|
||||
if (!host->align_buffer) {
|
||||
log_err("Aligned buffer alloc failed\n");
|
||||
|
||||
@@ -166,6 +166,7 @@ struct rst_map_in {
|
||||
#define GEN5_SCMI_SDK_4_30 0x010c0000
|
||||
#define GEN5_SCMI_SDK_4_31 0x010d0000
|
||||
#define GEN5_SCMI_SDK_4_32 0x010e0000
|
||||
#define GEN5_SCMI_SDK_4_36 0x01100000
|
||||
|
||||
static const struct rst_map_in gen5_rst_map_dt_sdk_4_28[] = {
|
||||
{ SCP_RESET_DOMAIN_ID_UFS0, 202 },
|
||||
@@ -220,7 +221,8 @@ static int gen5_reset_of_xlate(struct reset_ctl *reset_ctl,
|
||||
map = gen5_rst_map_dt_sdk_4_28;
|
||||
map_size = ARRAY_SIZE(gen5_rst_map_dt_sdk_4_28);
|
||||
} else if (priv->basever == GEN5_SCMI_SDK_4_31 ||
|
||||
priv->basever == GEN5_SCMI_SDK_4_32) {
|
||||
priv->basever == GEN5_SCMI_SDK_4_32 ||
|
||||
priv->basever == GEN5_SCMI_SDK_4_36) {
|
||||
map = gen5_rst_map_dt_sdk_4_31;
|
||||
map_size = ARRAY_SIZE(gen5_rst_map_dt_sdk_4_31);
|
||||
} else {
|
||||
|
||||
@@ -171,6 +171,21 @@ config SPL_DM_PMIC_PCA9450
|
||||
This config enables implementation of driver-model pmic uclass features
|
||||
for PMIC PCA9450 in SPL. The driver implements read/write operations.
|
||||
|
||||
config DM_PMIC_PF9453
|
||||
bool "Enable Driver Model for PMIC PF9453"
|
||||
depends on DM_I2C
|
||||
help
|
||||
This config enables implementation of driver-model pmic uclass features
|
||||
for PMIC PF9453. The driver implements read/write operations.
|
||||
|
||||
config SPL_DM_PMIC_PF9453
|
||||
bool "Enable Driver Model for PMIC PF9453 in SPL"
|
||||
depends on SPL_DM_PMIC
|
||||
depends on SPL_DM_I2C
|
||||
help
|
||||
This config enables implementation of driver-model pmic uclass features
|
||||
for PMIC PF9453 in SPL. The driver implements read/write operations.
|
||||
|
||||
config DM_PMIC_PFUZE100
|
||||
bool "Enable Driver Model for PMIC PFUZE100"
|
||||
help
|
||||
|
||||
@@ -15,6 +15,7 @@ obj-$(CONFIG_$(PHASE_)DM_PMIC_BD71837) += bd71837.o
|
||||
obj-$(CONFIG_$(PHASE_)DM_PMIC_MP5416) += mp5416.o
|
||||
obj-$(CONFIG_$(PHASE_)DM_PMIC_PFUZE100) += pfuze100.o
|
||||
obj-$(CONFIG_$(PHASE_)DM_PMIC_PCA9450) += pca9450.o
|
||||
obj-$(CONFIG_$(PHASE_)DM_PMIC_PF9453) += pf9453.o
|
||||
obj-$(CONFIG_PMIC_S2MPS11) += s2mps11.o
|
||||
obj-$(CONFIG_DM_PMIC_SANDBOX) += sandbox.o i2c_pmic_emul.o
|
||||
obj-$(CONFIG_PMIC_AB8500) += ab8500.o
|
||||
|
||||
@@ -0,0 +1,170 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2024 NXP
|
||||
*/
|
||||
|
||||
#include <asm/global_data.h>
|
||||
#include <asm-generic/gpio.h>
|
||||
#include <fdtdec.h>
|
||||
#include <errno.h>
|
||||
#include <dm.h>
|
||||
#include <dm/device_compat.h>
|
||||
#include <i2c.h>
|
||||
#include <linux/err.h>
|
||||
#include <log.h>
|
||||
#include <power/pmic.h>
|
||||
#include <power/regulator.h>
|
||||
#include <power/pf9453.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
static const struct pmic_child_info pmic_children_info[] = {
|
||||
/* buck */
|
||||
{ .prefix = "b", .driver = PF9453_REGULATOR_DRIVER},
|
||||
{ .prefix = "B", .driver = PF9453_REGULATOR_DRIVER},
|
||||
/* ldo */
|
||||
{ .prefix = "l", .driver = PF9453_REGULATOR_DRIVER},
|
||||
{ .prefix = "L", .driver = PF9453_REGULATOR_DRIVER},
|
||||
{ },
|
||||
};
|
||||
|
||||
struct pf9453_priv {
|
||||
struct gpio_desc *sd_vsel_gpio;
|
||||
};
|
||||
|
||||
static int pf9453_reg_count(struct udevice *dev)
|
||||
{
|
||||
return PF9453_REG_NUM;
|
||||
}
|
||||
|
||||
static bool is_reg_protect(uint reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case PF9453_BUCK1OUT:
|
||||
case PF9453_BUCK2OUT:
|
||||
case PF9453_BUCK3OUT:
|
||||
case PF9453_BUCK4OUT:
|
||||
case PF9453_LDO1OUT_L:
|
||||
case PF9453_LDO1OUT_H:
|
||||
case PF9453_LDO2OUT:
|
||||
case PF9453_LDOSNVS_CFG1:
|
||||
case PF9453_BUCK2OUT_MAX_LIMIT:
|
||||
case PF9453_BUCK2OUT_MIN_LIMIT:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static int pf9453_write(struct udevice *dev, uint reg, const uint8_t *buff, int len)
|
||||
{
|
||||
bool is_pro;
|
||||
u32 val = PF9453_UNLOCK_KEY;
|
||||
|
||||
is_pro = is_reg_protect(reg);
|
||||
if (is_pro) {
|
||||
if (dm_i2c_write(dev, PF9453_REG_LOCK, (uint8_t *)&val, 1)) {
|
||||
pr_err("write error to device: %p register: %#x!\n", dev, reg);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (dm_i2c_write(dev, reg, buff, len)) {
|
||||
pr_err("write error to device: %p register: %#x!\n", dev, reg);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
val = PF9453_LOCK_KEY;
|
||||
if (dm_i2c_write(dev, PF9453_REG_LOCK, (uint8_t *)&val, 1)) {
|
||||
pr_err("write error to device: %p register: %#x!\n", dev, reg);
|
||||
return -EIO;
|
||||
}
|
||||
} else {
|
||||
if (dm_i2c_write(dev, reg, buff, len)) {
|
||||
pr_err("write error to device: %p register: %#x!\n", dev, reg);
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pf9453_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
|
||||
{
|
||||
if (dm_i2c_read(dev, reg, buff, len)) {
|
||||
pr_err("read error from device: %p register: %#x!\n", dev, reg);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pf9453_bind(struct udevice *dev)
|
||||
{
|
||||
int children;
|
||||
ofnode regulators_node;
|
||||
|
||||
regulators_node = dev_read_subnode(dev, "regulators");
|
||||
if (!ofnode_valid(regulators_node)) {
|
||||
debug("%s: %s regulators subnode not found!", __func__,
|
||||
dev->name);
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
debug("%s: '%s' - found regulators subnode\n", __func__, dev->name);
|
||||
|
||||
children = pmic_bind_children(dev, regulators_node,
|
||||
pmic_children_info);
|
||||
if (!children)
|
||||
debug("%s: %s - no child found\n", __func__, dev->name);
|
||||
|
||||
/* Always return success for this device */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pf9453_probe(struct udevice *dev)
|
||||
{
|
||||
struct pf9453_priv *priv = dev_get_priv(dev);
|
||||
unsigned int reset_ctrl;
|
||||
int ret = 0;
|
||||
|
||||
if (CONFIG_IS_ENABLED(DM_GPIO) && CONFIG_IS_ENABLED(DM_REGULATOR_PF9453)) {
|
||||
priv->sd_vsel_gpio = devm_gpiod_get_optional(dev, "sd-vsel",
|
||||
GPIOD_IS_OUT |
|
||||
GPIOD_IS_OUT_ACTIVE);
|
||||
if (IS_ERR(priv->sd_vsel_gpio)) {
|
||||
ret = PTR_ERR(priv->sd_vsel_gpio);
|
||||
dev_err(dev, "Failed to request SD_VSEL GPIO: %d\n", ret);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (ofnode_read_bool(dev_ofnode(dev), "nxp,wdog_b-warm-reset"))
|
||||
reset_ctrl = PF9453_PMIC_RESET_WDOG_B_CFG_WARM;
|
||||
else
|
||||
reset_ctrl = PF9453_PMIC_RESET_WDOG_B_CFG_COLD;
|
||||
|
||||
return pmic_clrsetbits(dev, PF9453_RESET_CTRL,
|
||||
PF9453_PMIC_RESET_WDOG_B_CFG_MASK, reset_ctrl);
|
||||
}
|
||||
|
||||
static struct dm_pmic_ops pf9453_ops = {
|
||||
.reg_count = pf9453_reg_count,
|
||||
.read = pf9453_read,
|
||||
.write = pf9453_write,
|
||||
};
|
||||
|
||||
static const struct udevice_id pf9453_ids[] = {
|
||||
{ .compatible = "nxp,pf9453", .data = NXP_CHIP_TYPE_PF9453, },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(pmic_pf9453) = {
|
||||
.name = "pf9453 pmic",
|
||||
.id = UCLASS_PMIC,
|
||||
.of_match = pf9453_ids,
|
||||
.bind = pf9453_bind,
|
||||
.probe = pf9453_probe,
|
||||
.ops = &pf9453_ops,
|
||||
.priv_auto = sizeof(struct pf9453_priv),
|
||||
};
|
||||
@@ -103,6 +103,21 @@ config SPL_DM_REGULATOR_PCA9450
|
||||
This config enables implementation of driver-model regulator uclass
|
||||
features for regulators on ROHM PCA9450 in SPL.
|
||||
|
||||
config DM_REGULATOR_PF9453
|
||||
bool "Enable Driver Model for NXP PF9453 regulators"
|
||||
depends on DM_REGULATOR && DM_PMIC_PF9453
|
||||
help
|
||||
This config enables implementation of driver-model regulator uclass
|
||||
features for regulators on NXP PF9453 PMICs. PF9453 contains 6 bucks
|
||||
and 5 LDOS. The driver implements get/set api for value and enable.
|
||||
|
||||
config SPL_DM_REGULATOR_PF9453
|
||||
bool "Enable Driver Model for NXP PF9453 regulators in SPL"
|
||||
depends on DM_REGULATOR_PF9453 && SPL
|
||||
help
|
||||
This config enables implementation of driver-model regulator uclass
|
||||
features for regulators on ROHM PF9453 in SPL.
|
||||
|
||||
config DM_REGULATOR_DA9063
|
||||
bool "Enable Driver Model for REGULATOR DA9063"
|
||||
depends on DM_REGULATOR && DM_PMIC_DA9063
|
||||
|
||||
@@ -18,6 +18,7 @@ obj-$(CONFIG_DM_REGULATOR_NPCM8XX) += npcm8xx_regulator.o
|
||||
obj-$(CONFIG_$(PHASE_)DM_REGULATOR_PFUZE100) += pfuze100.o
|
||||
obj-$(CONFIG_$(PHASE_)DM_REGULATOR_BD71837) += bd71837.o
|
||||
obj-$(CONFIG_$(PHASE_)DM_REGULATOR_PCA9450) += pca9450.o
|
||||
obj-$(CONFIG_$(PHASE_)DM_REGULATOR_PF9453) += pf9453.o
|
||||
obj-$(CONFIG_$(PHASE_)REGULATOR_PWM) += pwm_regulator.o
|
||||
obj-$(CONFIG_$(PHASE_)DM_REGULATOR_FAN53555) += fan53555.o
|
||||
obj-$(CONFIG_$(PHASE_)DM_REGULATOR_COMMON) += regulator_common.o
|
||||
|
||||
@@ -0,0 +1,256 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* NXP PF9453 regulator driver
|
||||
* Copyright 2024 NXP
|
||||
*/
|
||||
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <log.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <power/pf9453.h>
|
||||
#include <power/pmic.h>
|
||||
#include <power/regulator.h>
|
||||
|
||||
/**
|
||||
* struct pf9453_vrange - describe linear range of voltages
|
||||
*
|
||||
* @min_volt: smallest voltage in range
|
||||
* @step: how much voltage changes at each selector step
|
||||
* @min_sel: smallest selector in the range
|
||||
* @max_sel: maximum selector in the range
|
||||
*/
|
||||
struct pf9453_vrange {
|
||||
unsigned int min_volt;
|
||||
unsigned int step;
|
||||
u8 min_sel;
|
||||
u8 max_sel;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct pf9453_plat - describe regulator control registers
|
||||
*
|
||||
* @name: name of the regulator. Used for matching the dt-entry
|
||||
* @enable_reg: register address used to enable/disable regulator
|
||||
* @enablemask: register mask used to enable/disable regulator
|
||||
* @volt_reg: register address used to configure regulator voltage
|
||||
* @volt_mask: register mask used to configure regulator voltage
|
||||
* @ranges: pointer to ranges of regulator voltages and matching register
|
||||
* values
|
||||
* @numranges: number of voltage ranges pointed by ranges
|
||||
*/
|
||||
struct pf9453_plat {
|
||||
const char *name;
|
||||
u8 enable_reg;
|
||||
u8 enablemask;
|
||||
u8 volt_reg;
|
||||
u8 volt_mask;
|
||||
struct pf9453_vrange *ranges;
|
||||
unsigned int numranges;
|
||||
};
|
||||
|
||||
#define PCA_RANGE(_min, _vstep, _sel_low, _sel_hi) \
|
||||
{ \
|
||||
.min_volt = (_min), .step = (_vstep), \
|
||||
.min_sel = (_sel_low), .max_sel = (_sel_hi), \
|
||||
}
|
||||
|
||||
#define PCA_DATA(_name, enreg, enmask, vreg, vmask, _range, _numranges) \
|
||||
{ \
|
||||
.name = (_name), .enable_reg = (enreg), .enablemask = (enmask), \
|
||||
.volt_reg = (vreg), .volt_mask = (vmask), .ranges = (_range), \
|
||||
.numranges = _numranges \
|
||||
}
|
||||
|
||||
static struct pf9453_vrange pf9453_buck134_vranges[] = {
|
||||
PCA_RANGE(600000, 25000, 0, 0x7f),
|
||||
};
|
||||
|
||||
static struct pf9453_vrange pf9453_buck2_vranges[] = {
|
||||
PCA_RANGE(600000, 12500, 0, 0x7f),
|
||||
};
|
||||
|
||||
static struct pf9453_vrange pf9453_ldo1_vranges[] = {
|
||||
PCA_RANGE(800000, 25000, 0x0, 0x64),
|
||||
};
|
||||
|
||||
static struct pf9453_vrange pf9453_ldo2_vranges[] = {
|
||||
PCA_RANGE(500000, 25000, 0x0, 0x3a),
|
||||
};
|
||||
|
||||
static struct pf9453_vrange pf9453_ldosnvs_vranges[] = {
|
||||
PCA_RANGE(800000, 25000, 0x0, 0x58),
|
||||
};
|
||||
|
||||
static struct pf9453_plat pf9453_reg_data[] = {
|
||||
PCA_DATA("BUCK1", PF9453_BUCK1CTRL, PF9453_EN_MODE_MASK,
|
||||
PF9453_BUCK1OUT, PF9453_BUCK_RUN_MASK,
|
||||
pf9453_buck134_vranges, ARRAY_SIZE(pf9453_buck134_vranges)),
|
||||
PCA_DATA("BUCK2", PF9453_BUCK2CTRL, PF9453_EN_MODE_MASK,
|
||||
PF9453_BUCK2OUT, PF9453_BUCK_RUN_MASK,
|
||||
pf9453_buck2_vranges, ARRAY_SIZE(pf9453_buck2_vranges)),
|
||||
PCA_DATA("BUCK3", PF9453_BUCK3CTRL, PF9453_EN_MODE_MASK,
|
||||
PF9453_BUCK3OUT, PF9453_BUCK_RUN_MASK,
|
||||
pf9453_buck134_vranges, ARRAY_SIZE(pf9453_buck134_vranges)),
|
||||
PCA_DATA("BUCK4", PF9453_BUCK4CTRL, PF9453_EN_MODE_MASK,
|
||||
PF9453_BUCK4OUT, PF9453_BUCK_RUN_MASK,
|
||||
pf9453_buck134_vranges, ARRAY_SIZE(pf9453_buck134_vranges)),
|
||||
/* LDOs */
|
||||
PCA_DATA("LDO1", PF9453_LDO1CFG, PF9453_EN_MODE_MASK,
|
||||
PF9453_LDO1OUT_H, PF9453_LDO1_MASK,
|
||||
pf9453_ldo1_vranges, ARRAY_SIZE(pf9453_ldo1_vranges)),
|
||||
PCA_DATA("LDO2", PF9453_LDO2CFG, PF9453_EN_MODE_MASK,
|
||||
PF9453_LDO2OUT, PF9453_LDO2_MASK,
|
||||
pf9453_ldo2_vranges, ARRAY_SIZE(pf9453_ldo2_vranges)),
|
||||
PCA_DATA("LDO-SNVS", PF9453_LDOSNVS_CFG2, PF9453_EN_MODE_MASK,
|
||||
PF9453_LDOSNVS_CFG1, PF9453_LDOSNVS_MASK,
|
||||
pf9453_ldosnvs_vranges, ARRAY_SIZE(pf9453_ldosnvs_vranges)),
|
||||
};
|
||||
|
||||
static int vrange_find_value(struct pf9453_vrange *r, unsigned int sel,
|
||||
unsigned int *val)
|
||||
{
|
||||
if (!val || sel < r->min_sel || sel > r->max_sel)
|
||||
return -EINVAL;
|
||||
|
||||
*val = r->min_volt + r->step * (sel - r->min_sel);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vrange_find_selector(struct pf9453_vrange *r, int val,
|
||||
unsigned int *sel)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
int num_vals = r->max_sel - r->min_sel + 1;
|
||||
|
||||
if (val >= r->min_volt &&
|
||||
val <= r->min_volt + r->step * (num_vals - 1)) {
|
||||
if (r->step) {
|
||||
*sel = r->min_sel + ((val - r->min_volt) / r->step);
|
||||
ret = 0;
|
||||
} else {
|
||||
*sel = r->min_sel;
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pf9453_get_enable(struct udevice *dev)
|
||||
{
|
||||
struct pf9453_plat *plat = dev_get_plat(dev);
|
||||
int val;
|
||||
|
||||
val = pmic_reg_read(dev->parent, plat->enable_reg);
|
||||
if (val < 0)
|
||||
return val;
|
||||
|
||||
return (val & plat->enablemask);
|
||||
}
|
||||
|
||||
static int pf9453_set_enable(struct udevice *dev, bool enable)
|
||||
{
|
||||
int val = 0;
|
||||
struct pf9453_plat *plat = dev_get_plat(dev);
|
||||
|
||||
if (enable)
|
||||
val = plat->enablemask;
|
||||
|
||||
return pmic_clrsetbits(dev->parent, plat->enable_reg, plat->enablemask,
|
||||
val);
|
||||
}
|
||||
|
||||
static int pf9453_get_value(struct udevice *dev)
|
||||
{
|
||||
struct pf9453_plat *plat = dev_get_plat(dev);
|
||||
unsigned int reg, tmp;
|
||||
int i, ret;
|
||||
|
||||
ret = pmic_reg_read(dev->parent, plat->volt_reg);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
reg = ret;
|
||||
reg &= plat->volt_mask;
|
||||
|
||||
for (i = 0; i < plat->numranges; i++) {
|
||||
struct pf9453_vrange *r = &plat->ranges[i];
|
||||
|
||||
if (!vrange_find_value(r, reg, &tmp))
|
||||
return tmp;
|
||||
}
|
||||
|
||||
pr_err("Unknown voltage value read from pmic\n");
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int pf9453_set_value(struct udevice *dev, int uvolt)
|
||||
{
|
||||
struct pf9453_plat *plat = dev_get_plat(dev);
|
||||
unsigned int sel;
|
||||
int i, found = 0;
|
||||
|
||||
for (i = 0; i < plat->numranges; i++) {
|
||||
struct pf9453_vrange *r = &plat->ranges[i];
|
||||
|
||||
found = !vrange_find_selector(r, uvolt, &sel);
|
||||
if (found) {
|
||||
unsigned int tmp;
|
||||
|
||||
/*
|
||||
* We require exactly the requested value to be
|
||||
* supported - this can be changed later if needed
|
||||
*/
|
||||
found = !vrange_find_value(r, sel, &tmp);
|
||||
if (found && tmp == uvolt)
|
||||
break;
|
||||
found = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
return -EINVAL;
|
||||
|
||||
return pmic_clrsetbits(dev->parent, plat->volt_reg,
|
||||
plat->volt_mask, sel);
|
||||
}
|
||||
|
||||
static int pf9453_regulator_probe(struct udevice *dev)
|
||||
{
|
||||
struct pf9453_plat *plat = dev_get_plat(dev);
|
||||
int i, type;
|
||||
|
||||
type = dev_get_driver_data(dev_get_parent(dev));
|
||||
|
||||
if (type != NXP_CHIP_TYPE_PF9453) {
|
||||
debug("Unknown PMIC type\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(pf9453_reg_data); i++) {
|
||||
if (strcmp(dev->name, pf9453_reg_data[i].name))
|
||||
continue;
|
||||
*plat = pf9453_reg_data[i];
|
||||
return 0;
|
||||
}
|
||||
|
||||
pr_err("Unknown regulator '%s'\n", dev->name);
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static const struct dm_regulator_ops pf9453_regulator_ops = {
|
||||
.get_value = pf9453_get_value,
|
||||
.set_value = pf9453_set_value,
|
||||
.get_enable = pf9453_get_enable,
|
||||
.set_enable = pf9453_set_enable,
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(pf9453_regulator) = {
|
||||
.name = PF9453_REGULATOR_DRIVER,
|
||||
.id = UCLASS_REGULATOR,
|
||||
.ops = &pf9453_regulator_ops,
|
||||
.probe = pf9453_regulator_probe,
|
||||
.plat_auto = sizeof(struct pf9453_plat),
|
||||
};
|
||||
@@ -67,6 +67,7 @@ struct bd_info;
|
||||
#define MMC_CAP_NONREMOVABLE BIT(14)
|
||||
#define MMC_CAP_NEEDS_POLL BIT(15)
|
||||
#define MMC_CAP_CD_ACTIVE_HIGH BIT(16)
|
||||
#define MMC_CAP_CMD23 BIT(17)
|
||||
|
||||
#define MMC_MODE_8BIT BIT(30)
|
||||
#define MMC_MODE_4BIT BIT(29)
|
||||
@@ -141,6 +142,8 @@ static inline bool mmc_is_tuning_cmd(uint cmdidx)
|
||||
#define SD_HIGHSPEED_BUSY 0x00020000
|
||||
#define SD_HIGHSPEED_SUPPORTED 0x00020000
|
||||
|
||||
#define SD_SCR_CMD23_SUPPORT BIT(1)
|
||||
|
||||
#define UHS_SDR12_BUS_SPEED 0
|
||||
#define HIGH_SPEED_BUS_SPEED 1
|
||||
#define UHS_SDR25_BUS_SPEED 1
|
||||
|
||||
@@ -253,8 +253,6 @@
|
||||
#define MMC_CAP_DRIVER_TYPE_C (1 << 24)
|
||||
/* Host supports Driver Type D */
|
||||
#define MMC_CAP_DRIVER_TYPE_D (1 << 25)
|
||||
/* CMD23 supported. */
|
||||
#define MMC_CAP_CMD23 (1 << 30)
|
||||
/* Hardware reset */
|
||||
#define MMC_CAP_HW_RESET (1 << 31)
|
||||
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Copyright 2024 NXP
|
||||
*/
|
||||
|
||||
#ifndef PF9453_H_
|
||||
#define PF9453_H_
|
||||
|
||||
#define PF9453_REGULATOR_DRIVER "pf9453_regulator"
|
||||
|
||||
enum {
|
||||
PF9453_REG_DEV_ID = 0x00,
|
||||
PF9453_OTP_VER = 0x01,
|
||||
PF9453_INT1 = 0x02,
|
||||
PF9453_INT1_MSK = 0x03,
|
||||
PF9453_INT1_STATUS = 0x04,
|
||||
PF9453_VRFLT1_INT = 0x05,
|
||||
PF9453_VRFLT1_MASK = 0x06,
|
||||
PF9453_PWRON_STAT = 0x07,
|
||||
PF9453_RESET_CTRL = 0x08,
|
||||
PF9453_SW_RST = 0x09,
|
||||
PF9453_PWR_CTRL = 0x0a,
|
||||
PF9453_CONFIG1 = 0x0b,
|
||||
PF9453_CONFIG2 = 0x0c,
|
||||
PF9453_32K_CONFIG = 0x0d,
|
||||
PF9453_BUCK1CTRL = 0x10,
|
||||
PF9453_BUCK1OUT = 0x11,
|
||||
PF9453_BUCK2CTRL = 0x14,
|
||||
PF9453_BUCK2OUT = 0x15,
|
||||
PF9453_BUCK2OUT_STBY = 0x1D,
|
||||
PF9453_BUCK2OUT_MAX_LIMIT = 0x1F,
|
||||
PF9453_BUCK2OUT_MIN_LIMIT = 0x20,
|
||||
PF9453_BUCK3CTRL = 0x21,
|
||||
PF9453_BUCK3OUT = 0x22,
|
||||
PF9453_BUCK4CTRL = 0x2e,
|
||||
PF9453_BUCK4OUT = 0x2f,
|
||||
PF9453_LDO1OUT_L = 0x36,
|
||||
PF9453_LDO1CFG = 0x37,
|
||||
PF9453_LDO1OUT_H = 0x38,
|
||||
PF9453_LDOSNVS_CFG1 = 0x39,
|
||||
PF9453_LDOSNVS_CFG2 = 0x3a,
|
||||
PF9453_LDO2CFG = 0x3b,
|
||||
PF9453_LDO2OUT = 0x3c,
|
||||
PF9453_BUCK_POK = 0x3d,
|
||||
PF9453_LSW_CTRL1 = 0x40,
|
||||
PF9453_LSW_CTRL2 = 0x41,
|
||||
PF9453_REG_LOCK = 0x4e,
|
||||
PF9453_REG_NUM,
|
||||
};
|
||||
|
||||
int power_pf9453_init(unsigned char bus, unsigned char addr);
|
||||
|
||||
enum {
|
||||
NXP_CHIP_TYPE_PF9453 = 0,
|
||||
NXP_CHIP_TYPE_AMOUNT
|
||||
};
|
||||
|
||||
#define PF9453_UNLOCK_KEY 0x5c
|
||||
#define PF9453_LOCK_KEY 0x0
|
||||
|
||||
#define PF9453_EN_MODE_MASK 0x3
|
||||
#define PF9453_BUCK_RUN_MASK 0x7f
|
||||
#define PF9453_LDO1_MASK 0x7f
|
||||
#define PF9453_LDO2_MASK 0x3f
|
||||
#define PF9453_LDOSNVS_MASK 0x7f
|
||||
|
||||
#define PF9453_PMIC_RESET_WDOG_B_CFG_MASK 0xc0
|
||||
#define PF9453_PMIC_RESET_WDOG_B_CFG_WARM 0x40
|
||||
#define PF9453_PMIC_RESET_WDOG_B_CFG_COLD 0x80
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user