summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Rini <[email protected]>2025-10-30 07:31:14 -0600
committerTom Rini <[email protected]>2025-10-30 07:31:14 -0600
commit5b14ff3a0eee77bdf942edb54594a3d3076d11a3 (patch)
treeaa7b89967fe13b377db8f1e7df90af4a59190eda
parente34d01d23e45e007368685ffa6dfd674b6dd7b17 (diff)
parente16018f6b22d36f9f6b9f881175547457c06dae3 (diff)
Merge tag 'mmc-power-2025-10-30' of https://source.denx.de/u-boot/custodians/u-boot-mmc
CI: https://source.denx.de/u-boot/custodians/u-boot-mmc/-/pipelines/28083 - Add support for Samsung Exynos 7870 DW-MMC device - Add support for Samsung S2MPU05 PMIC device - Add compatible string for Exynos5250 in Exynos DW-MMC driver - Add support for handling UHS-I voltage signaling without power-cycle - Minor misc cleanup
-rw-r--r--drivers/mmc/dw_mmc.c50
-rw-r--r--drivers/mmc/exynos_dw_mmc.c142
-rw-r--r--drivers/mmc/mmc.c75
-rw-r--r--drivers/power/pmic/s2mps11.c37
-rw-r--r--drivers/power/regulator/fixed.c1
-rw-r--r--drivers/power/regulator/gpio-regulator.c1
-rw-r--r--drivers/power/regulator/regulator_common.c1
-rw-r--r--drivers/power/regulator/s2mps11_regulator.c590
-rw-r--r--include/dwmmc.h7
-rw-r--r--include/mmc.h3
-rw-r--r--include/power/s2mps11.h134
-rw-r--r--include/sdhci.h2
12 files changed, 740 insertions, 303 deletions
diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c
index a51494380ce..f3c0cc5cd8e 100644
--- a/drivers/mmc/dw_mmc.c
+++ b/drivers/mmc/dw_mmc.c
@@ -419,6 +419,10 @@ static int dwmci_send_cmd_common(struct dwmci_host *host, struct mmc_cmd *cmd,
if (cmd->resp_type & MMC_RSP_CRC)
flags |= DWMCI_CMD_CHECK_CRC;
+ host->volt_switching = (cmd->cmdidx == SD_CMD_SWITCH_UHS18V);
+ if (host->volt_switching)
+ flags |= DWMCI_CMD_VOLT_SWITCH;
+
flags |= cmd->cmdidx | DWMCI_CMD_START | DWMCI_CMD_USE_HOLD_REG;
debug("Sending CMD%d\n", cmd->cmdidx);
@@ -427,6 +431,10 @@ static int dwmci_send_cmd_common(struct dwmci_host *host, struct mmc_cmd *cmd,
for (i = 0; i < retry; i++) {
mask = dwmci_readl(host, DWMCI_RINTSTS);
+ if (host->volt_switching && (mask & DWMCI_INTMSK_VOLTSW)) {
+ dwmci_writel(host, DWMCI_RINTSTS, DWMCI_INTMSK_VOLTSW);
+ break;
+ }
if (mask & DWMCI_INTMSK_CDONE) {
if (!data)
dwmci_writel(host, DWMCI_RINTSTS, mask);
@@ -482,8 +490,8 @@ static int dwmci_send_cmd_common(struct dwmci_host *host, struct mmc_cmd *cmd,
}
#ifdef CONFIG_DM_MMC
-static int dwmci_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
- struct mmc_data *data)
+int dwmci_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
+ struct mmc_data *data)
{
struct mmc *mmc = mmc_get_mmc_dev(dev);
#else
@@ -507,20 +515,24 @@ static int dwmci_control_clken(struct dwmci_host *host, bool on)
{
const u32 val = on ? DWMCI_CLKEN_ENABLE | DWMCI_CLKEN_LOW_PWR : 0;
const u32 cmd_only_clk = DWMCI_CMD_PRV_DAT_WAIT | DWMCI_CMD_UPD_CLK;
- int timeout = 10000;
- u32 status;
+ int i, timeout = 10000;
+ u32 flags, mask;
dwmci_writel(host, DWMCI_CLKENA, val);
/* Inform CIU */
- dwmci_writel(host, DWMCI_CMD, DWMCI_CMD_START | cmd_only_clk);
- do {
- status = dwmci_readl(host, DWMCI_CMD);
- if (timeout-- < 0) {
- debug("%s: Timeout!\n", __func__);
- return -ETIMEDOUT;
+ flags = DWMCI_CMD_START | cmd_only_clk;
+ if (host->volt_switching)
+ flags |= DWMCI_CMD_VOLT_SWITCH;
+ dwmci_writel(host, DWMCI_CMD, flags);
+
+ for (i = 0; i < timeout; i++) {
+ mask = dwmci_readl(host, DWMCI_RINTSTS);
+ if (mask & DWMCI_INTMSK_CDONE) {
+ dwmci_writel(host, DWMCI_RINTSTS, DWMCI_INTMSK_CDONE);
+ break;
}
- } while (status & DWMCI_CMD_START);
+ }
return 0;
}
@@ -554,7 +566,7 @@ static int dwmci_setup_bus(struct dwmci_host *host, u32 freq)
unsigned long sclk;
int ret;
- if (freq == host->clock || freq == 0)
+ if (!freq)
return 0;
/*
@@ -585,7 +597,7 @@ static int dwmci_setup_bus(struct dwmci_host *host, u32 freq)
}
#ifdef CONFIG_DM_MMC
-static int dwmci_set_ios(struct udevice *dev)
+int dwmci_set_ios(struct udevice *dev)
{
struct mmc *mmc = mmc_get_mmc_dev(dev);
#else
@@ -632,17 +644,11 @@ static int dwmci_set_ios(struct mmc *mmc)
if (mmc->vqmmc_supply) {
int ret;
- ret = regulator_set_enable_if_allowed(mmc->vqmmc_supply, false);
- if (ret)
- return ret;
-
if (mmc->signal_voltage == MMC_SIGNAL_VOLTAGE_180)
- regulator_set_value(mmc->vqmmc_supply, 1800000);
+ ret = regulator_set_value(mmc->vqmmc_supply, 1800000);
else
- regulator_set_value(mmc->vqmmc_supply, 3300000);
-
- ret = regulator_set_enable_if_allowed(mmc->vqmmc_supply, true);
- if (ret)
+ ret = regulator_set_value(mmc->vqmmc_supply, 3300000);
+ if (ret && ret != -ENOSYS)
return ret;
}
#endif
diff --git a/drivers/mmc/exynos_dw_mmc.c b/drivers/mmc/exynos_dw_mmc.c
index 12e37cb4b78..b230e9dbbf8 100644
--- a/drivers/mmc/exynos_dw_mmc.c
+++ b/drivers/mmc/exynos_dw_mmc.c
@@ -18,13 +18,18 @@
#include <linux/printk.h>
#define DWMMC_MAX_CH_NUM 4
-#define DWMMC_MAX_FREQ 52000000
+#define DWMMC_MAX_FREQ 208000000
#define DWMMC_MIN_FREQ 400000
#define DWMMC_MMC0_SDR_TIMING_VAL 0x03030001
#define DWMMC_MMC2_SDR_TIMING_VAL 0x03020001
#define EXYNOS4412_FIXED_CIU_CLK_DIV 4
+/* CLKSEL register defines */
+#define CLKSEL_CCLK_SAMPLE(x) (((x) & 7) << 0)
+#define CLKSEL_UP_SAMPLE(x, y) (((x) & ~CLKSEL_CCLK_SAMPLE(7)) |\
+ CLKSEL_CCLK_SAMPLE(y))
+
/* Quirks */
#define DWMCI_QUIRK_DISABLE_SMU BIT(0)
@@ -121,22 +126,6 @@ static int exynos_dwmmc_set_sclk(struct dwmci_host *host, unsigned long rate)
return 0;
}
-/* Configure CLKSEL register with chosen timing values */
-static int exynos_dwmci_clksel(struct dwmci_host *host)
-{
- struct dwmci_exynos_priv_data *priv = exynos_dwmmc_get_priv(host);
- u32 timing;
-
- if (host->mmc->selected_mode == MMC_DDR_52)
- timing = priv->ddr_timing;
- else
- timing = priv->sdr_timing;
-
- dwmci_writel(host, priv->chip->clksel, timing);
-
- return 0;
-}
-
/**
* exynos_dwmmc_get_ciu_div - Get internal clock divider value
* @host: MMC controller object
@@ -160,14 +149,42 @@ static u8 exynos_dwmmc_get_ciu_div(struct dwmci_host *host)
& DWMCI_DIVRATIO_MASK) + 1;
}
+/* Configure CLKSEL register with chosen timing values */
+static int exynos_dwmci_clksel(struct dwmci_host *host)
+{
+ struct dwmci_exynos_priv_data *priv = exynos_dwmmc_get_priv(host);
+ u8 clk_div = exynos_dwmmc_get_ciu_div(host) - 1;
+ u32 timing;
+
+ switch (host->mmc->selected_mode) {
+ case MMC_DDR_52:
+ timing = priv->ddr_timing;
+ break;
+ case UHS_SDR104:
+ case UHS_SDR50:
+ timing = (priv->sdr_timing & 0xfff8ffff) | (clk_div << 16);
+ break;
+ case UHS_DDR50:
+ timing = (priv->ddr_timing & 0xfff8ffff) | (clk_div << 16);
+ break;
+ default:
+ timing = priv->sdr_timing;
+ }
+
+ dwmci_writel(host, priv->chip->clksel, timing);
+
+ return 0;
+}
+
static unsigned int exynos_dwmci_get_clk(struct dwmci_host *host, uint freq)
{
unsigned long sclk;
u8 clk_div;
int err;
- /* Should be double rate for DDR mode */
- if (host->mmc->selected_mode == MMC_DDR_52 && host->mmc->bus_width == 8)
+ /* Should be double rate for DDR or HS mode */
+ if ((host->mmc->selected_mode == MMC_DDR_52 && host->mmc->bus_width == 8) ||
+ host->mmc->selected_mode == MMC_HS_400)
freq *= 2;
clk_div = exynos_dwmmc_get_ciu_div(host);
@@ -282,6 +299,74 @@ static int exynos_dwmmc_of_to_plat(struct udevice *dev)
return 0;
}
+#if CONFIG_IS_ENABLED(MMC_SUPPORTS_TUNING)
+static int exynos_dwmmc_get_best_clksmpl(u8 candidates)
+{
+ u8 i;
+
+ for (i = 0; i < 8; i++) {
+ candidates = (candidates >> 1) | (candidates << 7); /* ror */
+ if ((candidates & 0xc7) == 0xc7)
+ return i;
+ }
+
+ for (i = 0; i < 8; i++) {
+ candidates = (candidates >> 1) | (candidates << 7); /* ror */
+ if ((candidates & 0x83) == 0x83)
+ return i;
+ }
+
+ /*
+ * If no valid clock sample values are found, use the first
+ * canditate bit for clock sample value.
+ */
+ for (i = 0; i < 8; i++) {
+ candidates = (candidates >> 1) | (candidates << 7); /* ror */
+ if ((candidates & 0x1) == 0x1)
+ return i;
+ }
+
+ return -EIO;
+}
+
+static int exynos_dwmmc_execute_tuning(struct udevice *dev, u32 opcode)
+{
+ struct dwmci_exynos_priv_data *priv = dev_get_priv(dev);
+ struct dwmci_host *host = &priv->host;
+ struct mmc *mmc = mmc_get_mmc_dev(dev);
+ u8 start_smpl, smpl, candidates = 0;
+ u32 clksel;
+ int ret;
+
+ clksel = dwmci_readl(host, priv->chip->clksel);
+ start_smpl = CLKSEL_CCLK_SAMPLE(clksel);
+
+ do {
+ dwmci_writel(host, DWMCI_TMOUT, ~0);
+
+ /* move to the next clksmpl */
+ smpl = (clksel + 1) & 0x7;
+ clksel = CLKSEL_UP_SAMPLE(clksel, smpl);
+ dwmci_writel(host, priv->chip->clksel, clksel);
+
+ if (!mmc_send_tuning(mmc, opcode))
+ candidates |= (1 << smpl);
+
+ } while (start_smpl != smpl);
+
+ ret = exynos_dwmmc_get_best_clksmpl(candidates);
+ if (ret < 0) {
+ printf("DWMMC%d: No candidates for clksmpl\n", host->dev_index);
+ return ret;
+ }
+
+ dwmci_writel(host, priv->chip->clksel,
+ CLKSEL_UP_SAMPLE(clksel, ret));
+
+ return 0;
+}
+#endif
+
static int exynos_dwmmc_probe(struct udevice *dev)
{
struct exynos_mmc_plat *plat = dev_get_plat(dev);
@@ -321,7 +406,8 @@ static int exynos_dwmmc_probe(struct udevice *dev)
host->name = dev->name;
host->board_init = exynos_dwmci_board_init;
- host->caps = MMC_MODE_DDR_52MHz;
+ host->caps = MMC_MODE_DDR_52MHz | MMC_MODE_HS200 | MMC_MODE_HS400 |
+ UHS_CAPS;
host->clksel = exynos_dwmci_clksel;
host->get_mmc_clk = exynos_dwmci_get_clk;
@@ -379,15 +465,29 @@ static const struct udevice_id exynos_dwmmc_ids[] = {
.compatible = "samsung,exynos5420-dw-mshc",
.data = (ulong)&exynos5_drv_data,
}, {
+ .compatible = "samsung,exynos5250-dw-mshc",
+ .data = (ulong)&exynos5_drv_data,
+ }, {
.compatible = "samsung,exynos-dwmmc",
.data = (ulong)&exynos5_drv_data,
}, {
.compatible = "samsung,exynos7-dw-mshc-smu",
.data = (ulong)&exynos7_smu_drv_data,
+ }, {
+ .compatible = "samsung,exynos7870-dw-mshc-smu",
+ .data = (ulong)&exynos7_smu_drv_data,
},
{ }
};
+struct dm_mmc_ops exynos_dwmmc_ops = {
+ .send_cmd = dwmci_send_cmd,
+ .set_ios = dwmci_set_ios,
+#if CONFIG_IS_ENABLED(MMC_SUPPORTS_TUNING)
+ .execute_tuning = exynos_dwmmc_execute_tuning,
+#endif
+};
+
U_BOOT_DRIVER(exynos_dwmmc_drv) = {
.name = "exynos_dwmmc",
.id = UCLASS_MMC,
@@ -395,7 +495,7 @@ U_BOOT_DRIVER(exynos_dwmmc_drv) = {
.of_to_plat = exynos_dwmmc_of_to_plat,
.bind = exynos_dwmmc_bind,
.probe = exynos_dwmmc_probe,
- .ops = &dm_dwmci_ops,
+ .ops = &exynos_dwmmc_ops,
.priv_auto = sizeof(struct dwmci_exynos_priv_data),
.plat_auto = sizeof(struct exynos_mmc_plat),
};
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index ec61ed92e86..bf82c515600 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -643,6 +643,19 @@ static int mmc_switch_voltage(struct mmc *mmc, int signal_voltage)
return 0;
}
+
+static bool mmc_sd_card_using_v18(struct mmc *mmc)
+{
+ /*
+ * According to the SD spec., the Bus Speed Mode (function group 1) bits
+ * 2 to 4 are zero if the card is initialized at 3.3V signal level. Thus
+ * they can be used to determine if the card has already switched to
+ * 1.8V signaling.
+ */
+ bool volt = mmc->sd3_bus_mode &
+ (SD_MODE_UHS_SDR50 | SD_MODE_UHS_SDR104 | SD_MODE_UHS_DDR50);
+ return volt;
+}
#endif
static int sd_send_op_cond(struct mmc *mmc, bool uhs_en)
@@ -1369,9 +1382,6 @@ static int sd_get_capabilities(struct mmc *mmc)
ALLOC_CACHE_ALIGN_BUFFER(__be32, switch_status, 16);
struct mmc_data data;
int timeout;
-#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
- u32 sd3_bus_mode;
-#endif
mmc->card_caps = MMC_MODE_1BIT | MMC_CAP(MMC_LEGACY);
@@ -1451,16 +1461,16 @@ static int sd_get_capabilities(struct mmc *mmc)
if (mmc->version < SD_VERSION_3)
return 0;
- sd3_bus_mode = __be32_to_cpu(switch_status[3]) >> 16 & 0x1f;
- if (sd3_bus_mode & SD_MODE_UHS_SDR104)
+ mmc->sd3_bus_mode = __be32_to_cpu(switch_status[3]) >> 16 & 0x1f;
+ if (mmc->sd3_bus_mode & SD_MODE_UHS_SDR104)
mmc->card_caps |= MMC_CAP(UHS_SDR104);
- if (sd3_bus_mode & SD_MODE_UHS_SDR50)
+ if (mmc->sd3_bus_mode & SD_MODE_UHS_SDR50)
mmc->card_caps |= MMC_CAP(UHS_SDR50);
- if (sd3_bus_mode & SD_MODE_UHS_SDR25)
+ if (mmc->sd3_bus_mode & SD_MODE_UHS_SDR25)
mmc->card_caps |= MMC_CAP(UHS_SDR25);
- if (sd3_bus_mode & SD_MODE_UHS_SDR12)
+ if (mmc->sd3_bus_mode & SD_MODE_UHS_SDR12)
mmc->card_caps |= MMC_CAP(UHS_SDR12);
- if (sd3_bus_mode & SD_MODE_UHS_DDR50)
+ if (mmc->sd3_bus_mode & SD_MODE_UHS_DDR50)
mmc->card_caps |= MMC_CAP(UHS_DDR50);
#endif
@@ -1830,7 +1840,11 @@ static int sd_select_mode_and_width(struct mmc *mmc, uint card_caps)
uint widths[] = {MMC_MODE_4BIT, MMC_MODE_1BIT};
const struct mode_width_tuning *mwt;
#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
- bool uhs_en = (mmc->ocr & OCR_S18R) ? true : false;
+ /*
+ * Enable UHS mode if the card advertises 1.8V support (S18R in OCR)
+ * or is already operating at 1.8V signaling.
+ */
+ bool uhs_en = (mmc->ocr & OCR_S18R) || mmc_sd_card_using_v18(mmc);
#else
bool uhs_en = false;
#endif
@@ -2701,6 +2715,27 @@ static int mmc_startup(struct mmc *mmc)
err = sd_get_capabilities(mmc);
if (err)
return err;
+
+#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
+ /*
+ * If the card has already switched to 1.8V signaling, then
+ * set the signal voltage to 1.8V.
+ */
+ if (mmc_sd_card_using_v18(mmc)) {
+ /*
+ * During a signal voltage level switch, the clock must be gated
+ * for 5 ms according to the SD spec.
+ */
+ mmc_set_clock(mmc, mmc->clock, MMC_CLK_DISABLE);
+ err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_180);
+ if (err)
+ return err;
+ /* Keep clock gated for at least 10 ms, though spec only says 5 ms */
+ mdelay(10);
+ mmc_set_clock(mmc, mmc->clock, MMC_CLK_ENABLE);
+ }
+#endif
+
err = sd_select_mode_and_width(mmc, mmc->card_caps);
} else {
err = mmc_get_capabilities(mmc);
@@ -2844,6 +2879,16 @@ static int mmc_power_on(struct mmc *mmc)
return ret;
}
}
+
+ if (mmc->vqmmc_supply) {
+ int ret = regulator_set_enable_if_allowed(mmc->vqmmc_supply,
+ true);
+
+ if (ret && ret != -ENOSYS) {
+ printf("Error enabling VQMMC supply : %d\n", ret);
+ return ret;
+ }
+ }
#endif
return 0;
}
@@ -2861,6 +2906,16 @@ static int mmc_power_off(struct mmc *mmc)
return ret;
}
}
+
+ if (mmc->vqmmc_supply) {
+ int ret = regulator_set_enable_if_allowed(mmc->vqmmc_supply,
+ false);
+
+ if (ret && ret != -ENOSYS) {
+ pr_debug("Error disabling VQMMC supply : %d\n", ret);
+ return ret;
+ }
+ }
#endif
return 0;
}
diff --git a/drivers/power/pmic/s2mps11.c b/drivers/power/pmic/s2mps11.c
index 6e819579030..5cf9d34ffaf 100644
--- a/drivers/power/pmic/s2mps11.c
+++ b/drivers/power/pmic/s2mps11.c
@@ -13,15 +13,28 @@
#include <power/pmic.h>
#include <power/s2mps11.h>
-static const struct pmic_child_info pmic_children_info[] = {
+static const struct pmic_child_info s2mps11_pmic_children_info[] = {
{ .prefix = S2MPS11_OF_LDO_PREFIX, .driver = S2MPS11_LDO_DRIVER },
{ .prefix = S2MPS11_OF_BUCK_PREFIX, .driver = S2MPS11_BUCK_DRIVER },
{ },
};
+static const struct pmic_child_info s2mpu05_pmic_children_info[] = {
+ { .prefix = S2MPU05_OF_LDO_PREFIX, .driver = S2MPS11_LDO_DRIVER },
+ { .prefix = S2MPU05_OF_BUCK_PREFIX, .driver = S2MPS11_BUCK_DRIVER },
+ { },
+};
+
static int s2mps11_reg_count(struct udevice *dev)
{
- return S2MPS11_REG_COUNT;
+ switch (dev_get_driver_data(dev)) {
+ case VARIANT_S2MPS11:
+ return S2MPS11_REG_COUNT;
+ case VARIANT_S2MPU05:
+ return S2MPU05_REG_COUNT;
+ default:
+ return -EINVAL;
+ }
}
static int s2mps11_write(struct udevice *dev, uint reg, const uint8_t *buff,
@@ -47,10 +60,11 @@ static int s2mps11_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
return ret;
}
-static int s2mps11_probe(struct udevice *dev)
+static int s2mps11_bind(struct udevice *dev)
{
ofnode regulators_node;
int children;
+ const struct pmic_child_info *pmic_children_info;
regulators_node = dev_read_subnode(dev, "regulators");
if (!ofnode_valid(regulators_node)) {
@@ -61,6 +75,18 @@ static int s2mps11_probe(struct udevice *dev)
debug("%s: '%s' - found regulators subnode\n", __func__, dev->name);
+ switch (dev_get_driver_data(dev)) {
+ case VARIANT_S2MPS11:
+ pmic_children_info = s2mps11_pmic_children_info;
+ break;
+ case VARIANT_S2MPU05:
+ pmic_children_info = s2mpu05_pmic_children_info;
+ break;
+ default:
+ debug("%s: unknown device type\n", __func__);
+ return -EINVAL;
+ }
+
children = pmic_bind_children(dev, regulators_node, pmic_children_info);
if (!children)
debug("%s: %s - no child found\n", __func__, dev->name);
@@ -75,7 +101,8 @@ static struct dm_pmic_ops s2mps11_ops = {
};
static const struct udevice_id s2mps11_ids[] = {
- { .compatible = "samsung,s2mps11-pmic" },
+ { .compatible = "samsung,s2mps11-pmic", .data = VARIANT_S2MPS11 },
+ { .compatible = "samsung,s2mpu05-pmic", .data = VARIANT_S2MPU05 },
{ }
};
@@ -84,5 +111,5 @@ U_BOOT_DRIVER(pmic_s2mps11) = {
.id = UCLASS_PMIC,
.of_match = s2mps11_ids,
.ops = &s2mps11_ops,
- .probe = s2mps11_probe,
+ .bind = s2mps11_bind,
};
diff --git a/drivers/power/regulator/fixed.c b/drivers/power/regulator/fixed.c
index 996da41546a..1dd137f493e 100644
--- a/drivers/power/regulator/fixed.c
+++ b/drivers/power/regulator/fixed.c
@@ -13,7 +13,6 @@
#include <asm/gpio.h>
#include <power/pmic.h>
#include <power/regulator.h>
-#include "regulator_common.h"
#include "regulator_common.h"
diff --git a/drivers/power/regulator/gpio-regulator.c b/drivers/power/regulator/gpio-regulator.c
index 38b22535c3d..787f8170234 100644
--- a/drivers/power/regulator/gpio-regulator.c
+++ b/drivers/power/regulator/gpio-regulator.c
@@ -12,7 +12,6 @@
#include <linux/printk.h>
#include <power/pmic.h>
#include <power/regulator.h>
-#include "regulator_common.h"
#include "regulator_common.h"
diff --git a/drivers/power/regulator/regulator_common.c b/drivers/power/regulator/regulator_common.c
index c80f10c3aa3..3ed713ce501 100644
--- a/drivers/power/regulator/regulator_common.c
+++ b/drivers/power/regulator/regulator_common.c
@@ -9,7 +9,6 @@
#include <asm/gpio.h>
#include <linux/delay.h>
#include <power/regulator.h>
-#include "regulator_common.h"
#include "regulator_common.h"
diff --git a/drivers/power/regulator/s2mps11_regulator.c b/drivers/power/regulator/s2mps11_regulator.c
index 96de55065fe..4b4353af639 100644
--- a/drivers/power/regulator/s2mps11_regulator.c
+++ b/drivers/power/regulator/s2mps11_regulator.c
@@ -13,6 +13,193 @@
#include <power/regulator.h>
#include <power/s2mps11.h>
+#define regulator_desc_s2mps11_buck(num, mask, min, step, max_hex) \
+ [num] = { \
+ .mode_reg = S2MPS11_REG_B##num##CTRL1, \
+ .mode_mask = S2MPS11_BUCK_MODE_MASK << S2MPS11_BUCK_MODE_SHIFT, \
+ .volt_reg = S2MPS11_REG_B##num##CTRL2, \
+ .volt_mask = mask, \
+ .volt_min = min, \
+ .volt_step = step, \
+ .volt_max_hex = max_hex, \
+ }
+
+#define regulator_desc_s2mps11_buck1_2_3_4_6(num) \
+ regulator_desc_s2mps11_buck(num, S2MPS11_BUCK_VOLT_MASK, \
+ S2MPS11_BUCK_UV_MIN, \
+ S2MPS11_BUCK_LSTEP, \
+ S2MPS11_BUCK_VOLT_MAX_HEX)
+
+#define regulator_desc_s2mps11_buck5 \
+ regulator_desc_s2mps11_buck(5, S2MPS11_BUCK_VOLT_MASK, \
+ S2MPS11_BUCK_UV_MIN, \
+ S2MPS11_BUCK_LSTEP, \
+ S2MPS11_BUCK5_VOLT_MAX_HEX)
+
+#define regulator_desc_s2mps11_buck7_8_10(num) \
+ regulator_desc_s2mps11_buck(num, S2MPS11_BUCK_VOLT_MASK, \
+ S2MPS11_BUCK_UV_HMIN, \
+ S2MPS11_BUCK_HSTEP, \
+ S2MPS11_BUCK7_8_10_VOLT_MAX_HEX)
+
+#define regulator_desc_s2mps11_buck9 \
+ regulator_desc_s2mps11_buck(9, S2MPS11_BUCK9_VOLT_MASK, \
+ S2MPS11_BUCK_UV_MIN, \
+ S2MPS11_BUCK9_STEP, \
+ S2MPS11_BUCK9_VOLT_MAX_HEX)
+
+static const struct sec_regulator_desc s2mps11_buck_desc[] = {
+ regulator_desc_s2mps11_buck1_2_3_4_6(1),
+ regulator_desc_s2mps11_buck1_2_3_4_6(2),
+ regulator_desc_s2mps11_buck1_2_3_4_6(3),
+ regulator_desc_s2mps11_buck1_2_3_4_6(4),
+ regulator_desc_s2mps11_buck5,
+ regulator_desc_s2mps11_buck1_2_3_4_6(6),
+ regulator_desc_s2mps11_buck7_8_10(7),
+ regulator_desc_s2mps11_buck7_8_10(8),
+ regulator_desc_s2mps11_buck9,
+ regulator_desc_s2mps11_buck7_8_10(10),
+};
+
+#define regulator_desc_s2mps11_ldo(num, step) \
+ [num] = { \
+ .mode_reg = S2MPS11_REG_L##num##CTRL, \
+ .mode_mask = S2MPS11_LDO_MODE_MASK << S2MPS11_LDO_MODE_SHIFT, \
+ .volt_reg = S2MPS11_REG_L##num##CTRL, \
+ .volt_mask = S2MPS11_LDO_VOLT_MASK, \
+ .volt_min = S2MPS11_LDO_UV_MIN, \
+ .volt_step = step, \
+ .volt_max_hex = S2MPS11_LDO_VOLT_MAX_HEX \
+ }
+
+#define regulator_desc_s2mps11_ldo_type1(num) \
+ regulator_desc_s2mps11_ldo(num, S2MPS11_LDO_STEP)
+
+#define regulator_desc_s2mps11_ldo_type2(num) \
+ regulator_desc_s2mps11_ldo(num, S2MPS11_LDO_STEP * 2)
+
+static const struct sec_regulator_desc s2mps11_ldo_desc[] = {
+ regulator_desc_s2mps11_ldo_type1(1),
+ regulator_desc_s2mps11_ldo_type2(2),
+ regulator_desc_s2mps11_ldo_type2(3),
+ regulator_desc_s2mps11_ldo_type2(4),
+ regulator_desc_s2mps11_ldo_type2(5),
+ regulator_desc_s2mps11_ldo_type1(6),
+ regulator_desc_s2mps11_ldo_type2(7),
+ regulator_desc_s2mps11_ldo_type2(8),
+ regulator_desc_s2mps11_ldo_type2(9),
+ regulator_desc_s2mps11_ldo_type2(10),
+ regulator_desc_s2mps11_ldo_type1(11),
+ regulator_desc_s2mps11_ldo_type2(12),
+ regulator_desc_s2mps11_ldo_type2(13),
+ regulator_desc_s2mps11_ldo_type2(14),
+ regulator_desc_s2mps11_ldo_type2(15),
+ regulator_desc_s2mps11_ldo_type2(16),
+ regulator_desc_s2mps11_ldo_type2(17),
+ regulator_desc_s2mps11_ldo_type2(18),
+ regulator_desc_s2mps11_ldo_type2(19),
+ regulator_desc_s2mps11_ldo_type2(20),
+ regulator_desc_s2mps11_ldo_type2(21),
+ regulator_desc_s2mps11_ldo_type1(22),
+ regulator_desc_s2mps11_ldo_type1(23),
+ regulator_desc_s2mps11_ldo_type2(24),
+ regulator_desc_s2mps11_ldo_type2(25),
+ regulator_desc_s2mps11_ldo_type2(26),
+ regulator_desc_s2mps11_ldo_type1(27),
+ regulator_desc_s2mps11_ldo_type2(28),
+ regulator_desc_s2mps11_ldo_type2(29),
+ regulator_desc_s2mps11_ldo_type2(30),
+ regulator_desc_s2mps11_ldo_type2(31),
+ regulator_desc_s2mps11_ldo_type2(32),
+ regulator_desc_s2mps11_ldo_type2(33),
+ regulator_desc_s2mps11_ldo_type2(34),
+ regulator_desc_s2mps11_ldo_type1(35),
+ regulator_desc_s2mps11_ldo_type2(36),
+ regulator_desc_s2mps11_ldo_type2(37),
+ regulator_desc_s2mps11_ldo_type2(38),
+};
+
+#define regulator_desc_s2mpu05_buck(num, which) \
+ [num] = { \
+ .mode_reg = S2MPU05_REG_B##num##CTRL1, \
+ .mode_mask = S2MPS11_BUCK_MODE_MASK << S2MPS11_BUCK_MODE_SHIFT, \
+ .volt_reg = S2MPU05_REG_B##num##CTRL2, \
+ .volt_mask = S2MPS11_BUCK_VOLT_MASK, \
+ .volt_min = S2MPU05_BUCK_MIN##which, \
+ .volt_step = S2MPU05_BUCK_STEP##which, \
+ .volt_max_hex = S2MPS11_BUCK_VOLT_MASK, \
+ }
+
+#define regulator_desc_s2mpu05_buck1_2_3(num) \
+ regulator_desc_s2mpu05_buck(num, 1)
+
+#define regulator_desc_s2mpu05_buck4_5(num) \
+ regulator_desc_s2mpu05_buck(num, 2)
+
+static const struct sec_regulator_desc s2mpu05_buck_desc[] = {
+ regulator_desc_s2mpu05_buck1_2_3(1),
+ regulator_desc_s2mpu05_buck1_2_3(2),
+ regulator_desc_s2mpu05_buck1_2_3(3),
+ regulator_desc_s2mpu05_buck4_5(4),
+ regulator_desc_s2mpu05_buck4_5(5),
+};
+
+#define regulator_desc_s2mpu05_ldo(num, reg, min, step) \
+ [num] = { \
+ .mode_reg = S2MPU05_REG_L##num##reg, \
+ .mode_mask = S2MPS11_LDO_MODE_MASK << S2MPS11_LDO_MODE_SHIFT, \
+ .volt_reg = S2MPU05_REG_L##num##reg, \
+ .volt_mask = S2MPS11_LDO_VOLT_MASK, \
+ .volt_min = min, \
+ .volt_step = step, \
+ .volt_max_hex = S2MPS11_LDO_VOLT_MAX_HEX, \
+ }
+
+#define regulator_desc_s2mpu05_ldo_type1(num) \
+ regulator_desc_s2mpu05_ldo(num, CTRL, S2MPU05_LDO_MIN1, \
+ S2MPU05_LDO_STEP1)
+
+#define regulator_desc_s2mpu05_ldo_type2(num) \
+ regulator_desc_s2mpu05_ldo(num, CTRL, S2MPU05_LDO_MIN1, \
+ S2MPU05_LDO_STEP2)
+
+#define regulator_desc_s2mpu05_ldo_type3(num) \
+ regulator_desc_s2mpu05_ldo(num, CTRL, S2MPU05_LDO_MIN2, \
+ S2MPU05_LDO_STEP2)
+
+#define regulator_desc_s2mpu05_ldo_type4(num) \
+ regulator_desc_s2mpu05_ldo(num, CTRL, S2MPU05_LDO_MIN3, \
+ S2MPU05_LDO_STEP2)
+
+#define regulator_desc_s2mpu05_ldo_type5(num) \
+ regulator_desc_s2mpu05_ldo(num, CTRL1, S2MPU05_LDO_MIN3, \
+ S2MPU05_LDO_STEP2)
+
+static const struct sec_regulator_desc s2mpu05_ldo_desc[] = {
+ regulator_desc_s2mpu05_ldo_type4(1),
+ regulator_desc_s2mpu05_ldo_type3(2),
+ regulator_desc_s2mpu05_ldo_type2(3),
+ regulator_desc_s2mpu05_ldo_type1(4),
+ regulator_desc_s2mpu05_ldo_type1(5),
+ regulator_desc_s2mpu05_ldo_type1(6),
+ regulator_desc_s2mpu05_ldo_type2(7),
+ regulator_desc_s2mpu05_ldo_type3(8),
+ regulator_desc_s2mpu05_ldo_type5(9),
+ regulator_desc_s2mpu05_ldo_type4(10),
+ /* LDOs 11-24 are used for CP. They aren't documented. */
+ regulator_desc_s2mpu05_ldo_type2(25),
+ regulator_desc_s2mpu05_ldo_type3(26),
+ regulator_desc_s2mpu05_ldo_type2(27),
+ regulator_desc_s2mpu05_ldo_type3(28),
+ regulator_desc_s2mpu05_ldo_type3(29),
+ regulator_desc_s2mpu05_ldo_type2(30),
+ regulator_desc_s2mpu05_ldo_type3(31),
+ regulator_desc_s2mpu05_ldo_type3(32),
+ regulator_desc_s2mpu05_ldo_type3(33),
+ regulator_desc_s2mpu05_ldo_type3(34),
+ regulator_desc_s2mpu05_ldo_type3(35),
+};
+
#define MODE(_id, _val, _name) { \
.id = _id, \
.register_value = _val, \
@@ -33,94 +220,46 @@ static struct dm_regulator_mode s2mps11_ldo_modes[] = {
MODE(OP_ON, S2MPS11_LDO_MODE_ON, "ON"),
};
-static const char s2mps11_buck_ctrl[] = {
- 0xff, 0x25, 0x27, 0x29, 0x2b, 0x2d, 0x33, 0x35, 0x37, 0x39, 0x3b
-};
-
-static const char s2mps11_buck_out[] = {
- 0xff, 0x26, 0x28, 0x2a, 0x2c, 0x2f, 0x34, 0x36, 0x38, 0x3a, 0x3c
+static struct dm_regulator_mode s2mpu05_regulator_modes[] = {
+ MODE(OP_OFF, S2MPS11_LDO_MODE_OFF, "OFF"),
+ MODE(OP_ON, S2MPS11_LDO_MODE_ON, "ON"),
};
-static int s2mps11_buck_hex2volt(int buck, int hex)
+static const ulong s2mps11_get_variant(struct udevice *dev)
{
- unsigned int uV = 0;
-
- if (hex < 0)
- goto bad;
-
- switch (buck) {
- case 7:
- case 8:
- case 10:
- if (hex > S2MPS11_BUCK7_8_10_VOLT_MAX_HEX)
- goto bad;
+ struct udevice *parent = dev_get_parent(dev);
- uV = hex * S2MPS11_BUCK_HSTEP + S2MPS11_BUCK_UV_HMIN;
- break;
- case 9:
- if (hex > S2MPS11_BUCK9_VOLT_MAX_HEX)
- goto bad;
- uV = hex * S2MPS11_BUCK9_STEP * 2 + S2MPS11_BUCK9_UV_MIN;
- break;
- default:
- if (buck == 5 && hex > S2MPS11_BUCK5_VOLT_MAX_HEX)
- goto bad;
- else if (buck != 5 && hex > S2MPS11_BUCK_VOLT_MAX_HEX)
- goto bad;
-
- uV = hex * S2MPS11_BUCK_LSTEP + S2MPS11_BUCK_UV_MIN;
- break;
+ if (!parent) {
+ pr_err("Parent is non-existent, this shouldn't happen!\n");
+ return VARIANT_NONE;
}
- return uV;
-bad:
- pr_err("Value: %#x is wrong for BUCK%d", hex, buck);
- return -EINVAL;
+ return dev_get_driver_data(parent);
}
-static int s2mps11_buck_volt2hex(int buck, int uV)
+static int s2mps11_buck_val(struct udevice *dev, int op, int *uV)
{
- int hex;
-
- switch (buck) {
- case 7:
- case 8:
- case 10:
- hex = (uV - S2MPS11_BUCK_UV_HMIN) / S2MPS11_BUCK_HSTEP;
- if (hex > S2MPS11_BUCK7_8_10_VOLT_MAX_HEX)
- goto bad;
+ const struct sec_regulator_desc *buck_desc;
+ int num_bucks, hex, buck, ret;
+ u32 addr;
+ u8 val;
+ switch (s2mps11_get_variant(dev)) {
+ case VARIANT_S2MPS11:
+ buck_desc = s2mps11_buck_desc;
+ num_bucks = ARRAY_SIZE(s2mps11_buck_desc);
break;
- case 9:
- hex = (uV - S2MPS11_BUCK9_UV_MIN) / S2MPS11_BUCK9_STEP;
- if (hex > S2MPS11_BUCK9_VOLT_MAX_HEX)
- goto bad;
+ case VARIANT_S2MPU05:
+ buck_desc = s2mpu05_buck_desc;
+ num_bucks = ARRAY_SIZE(s2mpu05_buck_desc);
break;
default:
- hex = (uV - S2MPS11_BUCK_UV_MIN) / S2MPS11_BUCK_LSTEP;
- if (buck == 5 && hex > S2MPS11_BUCK5_VOLT_MAX_HEX)
- goto bad;
- else if (buck != 5 && hex > S2MPS11_BUCK_VOLT_MAX_HEX)
- goto bad;
- break;
- };
-
- if (hex >= 0)
- return hex;
-
-bad:
- pr_err("Value: %d uV is wrong for BUCK%d", uV, buck);
- return -EINVAL;
-}
-
-static int s2mps11_buck_val(struct udevice *dev, int op, int *uV)
-{
- int hex, buck, ret;
- u32 mask, addr;
- u8 val;
+ pr_err("Unknown device type\n");
+ return -EINVAL;
+ }
buck = dev->driver_data;
- if (buck < 1 || buck > S2MPS11_BUCK_NUM) {
+ if (buck < 1 || buck > num_bucks) {
pr_err("Wrong buck number: %d\n", buck);
return -EINVAL;
}
@@ -128,35 +267,25 @@ static int s2mps11_buck_val(struct udevice *dev, int op, int *uV)
if (op == PMIC_OP_GET)
*uV = 0;
- addr = s2mps11_buck_out[buck];
-
- switch (buck) {
- case 9:
- mask = S2MPS11_BUCK9_VOLT_MASK;
- break;
- default:
- mask = S2MPS11_BUCK_VOLT_MASK;
- break;
- }
+ addr = buck_desc[buck].volt_reg;
ret = pmic_read(dev->parent, addr, &val, 1);
if (ret)
return ret;
if (op == PMIC_OP_GET) {
- val &= mask;
- ret = s2mps11_buck_hex2volt(buck, val);
- if (ret < 0)
- return ret;
- *uV = ret;
+ val &= buck_desc[buck].volt_mask;
+ *uV = val * buck_desc[buck].volt_step + buck_desc[buck].volt_min;
return 0;
}
- hex = s2mps11_buck_volt2hex(buck, *uV);
- if (hex < 0)
- return hex;
+ hex = (*uV - buck_desc[buck].volt_min) / buck_desc[buck].volt_step;
+ if (hex > buck_desc[buck].volt_max_hex) {
+ pr_err("Value: %d uV is wrong for LDO%d\n", *uV, buck);
+ return -EINVAL;
+ }
- val &= ~mask;
+ val &= ~buck_desc[buck].volt_mask;
val |= hex;
ret = pmic_write(dev->parent, addr, &val, 1);
@@ -165,60 +294,63 @@ static int s2mps11_buck_val(struct udevice *dev, int op, int *uV)
static int s2mps11_buck_mode(struct udevice *dev, int op, int *opmode)
{
+ struct dm_regulator_uclass_plat *uc_pdata = dev_get_uclass_plat(dev);
+ const struct sec_regulator_desc *buck_desc;
unsigned int addr, mode;
unsigned char val;
- int buck, ret;
+ int num_bucks, buck, ret, i;
+
+ switch (s2mps11_get_variant(dev)) {
+ case VARIANT_S2MPS11:
+ buck_desc = s2mps11_buck_desc;
+ num_bucks = ARRAY_SIZE(s2mps11_buck_desc);
+ break;
+ case VARIANT_S2MPU05:
+ buck_desc = s2mpu05_buck_desc;
+ num_bucks = ARRAY_SIZE(s2mpu05_buck_desc);
+ break;
+ default:
+ pr_err("Unknown device type\n");
+ return -EINVAL;
+ }
buck = dev->driver_data;
- if (buck < 1 || buck > S2MPS11_BUCK_NUM) {
+ if (buck < 1 || buck > num_bucks) {
pr_err("Wrong buck number: %d\n", buck);
return -EINVAL;
}
- addr = s2mps11_buck_ctrl[buck];
+ addr = buck_desc[buck].mode_reg;
ret = pmic_read(dev->parent, addr, &val, 1);
if (ret)
return ret;
if (op == PMIC_OP_GET) {
- val &= (S2MPS11_BUCK_MODE_MASK << S2MPS11_BUCK_MODE_SHIFT);
- switch (val) {
- case S2MPS11_BUCK_MODE_OFF:
- *opmode = OP_OFF;
- break;
- case S2MPS11_BUCK_MODE_STANDBY:
- *opmode = OP_STANDBY;
- break;
- case S2MPS11_BUCK_MODE_ON:
- *opmode = OP_ON;
- break;
- default:
- return -EINVAL;
+ val &= buck_desc[buck].mode_mask;
+ for (i = 0; i < uc_pdata->mode_count; i++) {
+ if (uc_pdata->mode[i].register_value != val)
+ continue;
+
+ *opmode = uc_pdata->mode[i].id;
+ return 0;
}
- return 0;
- }
- switch (*opmode) {
- case OP_OFF:
- mode = S2MPS11_BUCK_MODE_OFF;
- break;
- case OP_STANDBY:
- mode = S2MPS11_BUCK_MODE_STANDBY;
- break;
- case OP_ON:
- mode = S2MPS11_BUCK_MODE_ON;
- break;
- default:
- pr_err("Wrong mode: %d for buck: %d\n", *opmode, buck);
return -EINVAL;
}
- val &= ~(S2MPS11_BUCK_MODE_MASK << S2MPS11_BUCK_MODE_SHIFT);
- val |= mode;
- ret = pmic_write(dev->parent, addr, &val, 1);
+ for (i = 0; i < uc_pdata->mode_count; i++) {
+ if (uc_pdata->mode[i].id != *opmode)
+ continue;
- return ret;
+ mode = uc_pdata->mode[i].register_value;
+ val &= ~buck_desc[buck].mode_mask;
+ val |= mode;
+ return pmic_write(dev->parent, addr, &val, 1);
+ }
+
+ pr_err("Wrong mode: %d for buck: %d\n", *opmode, buck);
+ return -EINVAL;
}
static int s2mps11_buck_enable(struct udevice *dev, int op, bool *enable)
@@ -307,10 +439,21 @@ static int s2mps11_buck_probe(struct udevice *dev)
struct dm_regulator_uclass_plat *uc_pdata;
uc_pdata = dev_get_uclass_plat(dev);
-
uc_pdata->type = REGULATOR_TYPE_BUCK;
- uc_pdata->mode = s2mps11_buck_modes;
- uc_pdata->mode_count = ARRAY_SIZE(s2mps11_buck_modes);
+
+ switch (s2mps11_get_variant(dev)) {
+ case VARIANT_S2MPS11:
+ uc_pdata->mode = s2mps11_buck_modes;
+ uc_pdata->mode_count = ARRAY_SIZE(s2mps11_buck_modes);
+ break;
+ case VARIANT_S2MPU05:
+ uc_pdata->mode = s2mpu05_regulator_modes;
+ uc_pdata->mode_count = ARRAY_SIZE(s2mpu05_regulator_modes);
+ break;
+ default:
+ pr_err("Unknown device type\n");
+ return -EINVAL;
+ }
return 0;
}
@@ -331,95 +474,55 @@ U_BOOT_DRIVER(s2mps11_buck) = {
.probe = s2mps11_buck_probe,
};
-static int s2mps11_ldo_hex2volt(int ldo, int hex)
+static int s2mps11_ldo_val(struct udevice *dev, int op, int *uV)
{
- unsigned int uV = 0;
-
- if (hex > S2MPS11_LDO_VOLT_MAX_HEX) {
- pr_err("Value: %#x is wrong for LDO%d", hex, ldo);
- return -EINVAL;
- }
+ const struct sec_regulator_desc *ldo_desc;
+ unsigned int addr;
+ unsigned char val;
+ int num_ldos, hex, ldo, ret;
- switch (ldo) {
- case 1:
- case 6:
- case 11:
- case 22:
- case 23:
- case 27:
- case 35:
- uV = hex * S2MPS11_LDO_STEP + S2MPS11_LDO_UV_MIN;
- break;
- default:
- uV = hex * S2MPS11_LDO_STEP * 2 + S2MPS11_LDO_UV_MIN;
+ switch (s2mps11_get_variant(dev)) {
+ case VARIANT_S2MPS11:
+ ldo_desc = s2mps11_ldo_desc;
+ num_ldos = ARRAY_SIZE(s2mps11_ldo_desc);
break;
- }
-
- return uV;
-}
-
-static int s2mps11_ldo_volt2hex(int ldo, int uV)
-{
- int hex = 0;
-
- switch (ldo) {
- case 1:
- case 6:
- case 11:
- case 22:
- case 23:
- case 27:
- case 35:
- hex = (uV - S2MPS11_LDO_UV_MIN) / S2MPS11_LDO_STEP;
+ case VARIANT_S2MPU05:
+ ldo_desc = s2mpu05_ldo_desc;
+ num_ldos = ARRAY_SIZE(s2mpu05_ldo_desc);
break;
default:
- hex = (uV - S2MPS11_LDO_UV_MIN) / (S2MPS11_LDO_STEP * 2);
- break;
+ pr_err("Unknown device type\n");
+ return -EINVAL;
}
- if (hex >= 0 && hex <= S2MPS11_LDO_VOLT_MAX_HEX)
- return hex;
-
- pr_err("Value: %d uV is wrong for LDO%d", uV, ldo);
- return -EINVAL;
-
- return 0;
-}
-
-static int s2mps11_ldo_val(struct udevice *dev, int op, int *uV)
-{
- unsigned int addr;
- unsigned char val;
- int hex, ldo, ret;
-
ldo = dev->driver_data;
- if (ldo < 1 || ldo > S2MPS11_LDO_NUM) {
+ if (ldo < 1 || ldo > num_ldos) {
pr_err("Wrong ldo number: %d\n", ldo);
return -EINVAL;
}
- addr = S2MPS11_REG_L1CTRL + ldo - 1;
+ addr = ldo_desc[ldo].volt_reg;
+
+ if (op == PMIC_OP_GET)
+ *uV = 0;
ret = pmic_read(dev->parent, addr, &val, 1);
if (ret)
return ret;
if (op == PMIC_OP_GET) {
- *uV = 0;
- val &= S2MPS11_LDO_VOLT_MASK;
- ret = s2mps11_ldo_hex2volt(ldo, val);
- if (ret < 0)
- return ret;
-
- *uV = ret;
+ val &= ldo_desc[ldo].volt_mask;
+ *uV = val * ldo_desc[ldo].volt_step + ldo_desc[ldo].volt_min;
return 0;
}
- hex = s2mps11_ldo_volt2hex(ldo, *uV);
- if (hex < 0)
- return hex;
+ hex = (*uV - ldo_desc[ldo].volt_min) / ldo_desc[ldo].volt_step;
+ if (hex > ldo_desc[ldo].volt_max_hex) {
+ pr_err("Value: %d uV is wrong for LDO%d\n", *uV, ldo);
+ return -EINVAL;
+ }
- val &= ~S2MPS11_LDO_VOLT_MASK;
+ val &= ~ldo_desc[ldo].volt_mask;
val |= hex;
ret = pmic_write(dev->parent, addr, &val, 1);
@@ -428,65 +531,64 @@ static int s2mps11_ldo_val(struct udevice *dev, int op, int *uV)
static int s2mps11_ldo_mode(struct udevice *dev, int op, int *opmode)
{
+ struct dm_regulator_uclass_plat *uc_pdata = dev_get_uclass_plat(dev);
+ const struct sec_regulator_desc *ldo_desc;
unsigned int addr, mode;
unsigned char val;
- int ldo, ret;
+ int num_ldos, ldo, ret, i;
+
+ switch (s2mps11_get_variant(dev)) {
+ case VARIANT_S2MPS11:
+ ldo_desc = s2mps11_ldo_desc;
+ num_ldos = ARRAY_SIZE(s2mps11_ldo_desc);
+ break;
+ case VARIANT_S2MPU05:
+ ldo_desc = s2mpu05_ldo_desc;
+ num_ldos = ARRAY_SIZE(s2mpu05_ldo_desc);
+ break;
+ default:
+ pr_err("Unknown device type\n");
+ return -EINVAL;
+ }
ldo = dev->driver_data;
- if (ldo < 1 || ldo > S2MPS11_LDO_NUM) {
+ if (ldo < 1 || ldo > num_ldos) {
pr_err("Wrong ldo number: %d\n", ldo);
return -EINVAL;
}
- addr = S2MPS11_REG_L1CTRL + ldo - 1;
+
+ addr = ldo_desc[ldo].mode_reg;
ret = pmic_read(dev->parent, addr, &val, 1);
if (ret)
return ret;
if (op == PMIC_OP_GET) {
- val &= (S2MPS11_LDO_MODE_MASK << S2MPS11_LDO_MODE_SHIFT);
- switch (val) {
- case S2MPS11_LDO_MODE_OFF:
- *opmode = OP_OFF;
- break;
- case S2MPS11_LDO_MODE_STANDBY:
- *opmode = OP_STANDBY;
- break;
- case S2MPS11_LDO_MODE_STANDBY_LPM:
- *opmode = OP_STANDBY_LPM;
- break;
- case S2MPS11_LDO_MODE_ON:
- *opmode = OP_ON;
- break;
- default:
- return -EINVAL;
+ val &= ldo_desc[ldo].mode_mask;
+
+ for (i = 0; i < uc_pdata->mode_count; i++) {
+ if (uc_pdata->mode[i].register_value != val)
+ continue;
+
+ *opmode = uc_pdata->mode[i].id;
+ return 0;
}
- return 0;
- }
- switch (*opmode) {
- case OP_OFF:
- mode = S2MPS11_LDO_MODE_OFF;
- break;
- case OP_STANDBY:
- mode = S2MPS11_LDO_MODE_STANDBY;
- break;
- case OP_STANDBY_LPM:
- mode = S2MPS11_LDO_MODE_STANDBY_LPM;
- break;
- case OP_ON:
- mode = S2MPS11_LDO_MODE_ON;
- break;
- default:
- pr_err("Wrong mode: %d for ldo: %d\n", *opmode, ldo);
return -EINVAL;
}
- val &= ~(S2MPS11_LDO_MODE_MASK << S2MPS11_LDO_MODE_SHIFT);
- val |= mode;
- ret = pmic_write(dev->parent, addr, &val, 1);
+ for (i = 0; i < uc_pdata->mode_count; i++) {
+ if (uc_pdata->mode[i].id != *opmode)
+ continue;
- return ret;
+ mode = uc_pdata->mode[i].register_value;
+ val &= ~ldo_desc[ldo].mode_mask;
+ val |= mode;
+ return pmic_write(dev->parent, addr, &val, 1);
+ }
+
+ pr_err("Wrong mode: %d for ldo: %d\n", *opmode, ldo);
+ return -EINVAL;
}
static int s2mps11_ldo_enable(struct udevice *dev, int op, bool *enable)
@@ -584,8 +686,20 @@ static int s2mps11_ldo_probe(struct udevice *dev)
uc_pdata = dev_get_uclass_plat(dev);
uc_pdata->type = REGULATOR_TYPE_LDO;
- uc_pdata->mode = s2mps11_ldo_modes;
- uc_pdata->mode_count = ARRAY_SIZE(s2mps11_ldo_modes);
+
+ switch (s2mps11_get_variant(dev)) {
+ case VARIANT_S2MPS11:
+ uc_pdata->mode = s2mps11_ldo_modes;
+ uc_pdata->mode_count = ARRAY_SIZE(s2mps11_ldo_modes);
+ break;
+ case VARIANT_S2MPU05:
+ uc_pdata->mode = s2mpu05_regulator_modes;
+ uc_pdata->mode_count = ARRAY_SIZE(s2mpu05_regulator_modes);
+ break;
+ default:
+ pr_err("Unknown device type\n");
+ return -EINVAL;
+ }
return 0;
}
diff --git a/include/dwmmc.h b/include/dwmmc.h
index 87ca127cd6c..47e3220985e 100644
--- a/include/dwmmc.h
+++ b/include/dwmmc.h
@@ -72,6 +72,7 @@
#define DWMCI_INTMSK_RTO BIT(8)
#define DWMCI_INTMSK_DRTO BIT(9)
#define DWMCI_INTMSK_HTO BIT(10)
+#define DWMCI_INTMSK_VOLTSW BIT(10) /* overlap! */
#define DWMCI_INTMSK_FRUN BIT(11)
#define DWMCI_INTMSK_HLE BIT(12)
#define DWMCI_INTMSK_SBE BIT(13)
@@ -104,6 +105,7 @@
#define DWMCI_CMD_ABORT_STOP BIT(14)
#define DWMCI_CMD_PRV_DAT_WAIT BIT(13)
#define DWMCI_CMD_UPD_CLK BIT(21)
+#define DWMCI_CMD_VOLT_SWITCH BIT(28)
#define DWMCI_CMD_USE_HOLD_REG BIT(29)
#define DWMCI_CMD_START BIT(31)
@@ -190,6 +192,7 @@ struct dwmci_idmac_regs {
* @cfg: Internal MMC configuration, for !CONFIG_BLK cases
* @fifo_mode: Use FIFO mode (not DMA) to read and write data
* @dma_64bit_address: Whether DMA supports 64-bit address mode or not
+ * @volt_switching: Whether SD voltage switching is in process or not
* @regs: Registers that can vary for different DW MMC block versions
*/
struct dwmci_host {
@@ -229,6 +232,7 @@ struct dwmci_host {
bool fifo_mode;
bool dma_64bit_address;
+ bool volt_switching;
const struct dwmci_idmac_regs *regs;
};
@@ -334,6 +338,9 @@ int add_dwmci(struct dwmci_host *host, u32 max_clk, u32 min_clk);
#ifdef CONFIG_DM_MMC
/* Export the operations to drivers */
int dwmci_probe(struct udevice *dev);
+int dwmci_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
+ struct mmc_data *data);
+int dwmci_set_ios(struct udevice *dev);
extern const struct dm_mmc_ops dm_dwmci_ops;
#endif
diff --git a/include/mmc.h b/include/mmc.h
index c6b2ab4a29f..51d3f2f8dd5 100644
--- a/include/mmc.h
+++ b/include/mmc.h
@@ -759,6 +759,9 @@ struct mmc {
#endif
u8 *ext_csd;
u32 cardtype; /* cardtype read from the MMC */
+#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
+ u32 sd3_bus_mode; /* Supported UHS-I bus speed modes */
+#endif
enum mmc_voltage current_voltage;
enum bus_mode selected_mode; /* mode currently used */
enum bus_mode best_mode; /* best mode is the supported mode with the
diff --git a/include/power/s2mps11.h b/include/power/s2mps11.h
index 22b38fff703..51eb79bdde1 100644
--- a/include/power/s2mps11.h
+++ b/include/power/s2mps11.h
@@ -106,9 +106,6 @@ enum s2mps11_reg {
#define S2MPS11_LDO26_ENABLE 0xec
-#define S2MPS11_LDO_NUM 26
-#define S2MPS11_BUCK_NUM 10
-
/* Driver name */
#define S2MPS11_BUCK_DRIVER "s2mps11_buck"
#define S2MPS11_OF_BUCK_PREFIX "BUCK"
@@ -153,6 +150,131 @@ enum s2mps11_reg {
#define S2MPS11_LDO_MODE_STANDBY_LPM (0x2 << 6)
#define S2MPS11_LDO_MODE_ON (0x3 << 6)
+enum s2mpu05_reg {
+ S2MPU05_REG_ID,
+ S2MPU05_REG_INT1,
+ S2MPU05_REG_INT2,
+ S2MPU05_REG_INT3,
+ S2MPU05_REG_INT1M,
+ S2MPU05_REG_INT2M,
+ S2MPU05_REG_INT3M,
+ S2MPU05_REG_ST1,
+ S2MPU05_REG_ST2,
+ S2MPU05_REG_PWRONSRC,
+ S2MPU05_REG_OFFSRC,
+ S2MPU05_REG_BU_CHG,
+ S2MPU05_REG_RTC_BUF,
+ S2MPU05_REG_CTRL1,
+ S2MPU05_REG_CTRL2,
+ S2MPU05_REG_ETC_TEST,
+ S2MPU05_REG_OTP_ADRL,
+ S2MPU05_REG_OTP_ADRH,
+ S2MPU05_REG_OTP_DATA,
+ S2MPU05_REG_MON1SEL,
+ S2MPU05_REG_MON2SEL,
+ S2MPU05_REG_CTRL3,
+ S2MPU05_REG_ETC_OTP,
+ S2MPU05_REG_UVLO,
+ S2MPU05_REG_TIME_CTRL1,
+ S2MPU05_REG_TIME_CTRL2,
+ S2MPU05_REG_B1CTRL1,
+ S2MPU05_REG_B1CTRL2,
+ S2MPU05_REG_B2CTRL1,
+ S2MPU05_REG_B2CTRL2,
+ S2MPU05_REG_B2CTRL3,
+ S2MPU05_REG_B2CTRL4,
+ S2MPU05_REG_B3CTRL1,
+ S2MPU05_REG_B3CTRL2,
+ S2MPU05_REG_B3CTRL3,
+ S2MPU05_REG_B4CTRL1,
+ S2MPU05_REG_B4CTRL2,
+ S2MPU05_REG_B5CTRL1,
+ S2MPU05_REG_B5CTRL2,
+ S2MPU05_REG_BUCK_RAMP,
+ S2MPU05_REG_LDO_DVS1,
+ S2MPU05_REG_LDO_DVS9,
+ S2MPU05_REG_LDO_DVS10,
+ S2MPU05_REG_L1CTRL,
+ S2MPU05_REG_L2CTRL,
+ S2MPU05_REG_L3CTRL,
+ S2MPU05_REG_L4CTRL,
+ S2MPU05_REG_L5CTRL,
+ S2MPU05_REG_L6CTRL,
+ S2MPU05_REG_L7CTRL,
+ S2MPU05_REG_L8CTRL,
+ S2MPU05_REG_L9CTRL1,
+ S2MPU05_REG_L9CTRL2,
+ S2MPU05_REG_L10CTRL,
+ S2MPU05_REG_L11CTRL1,
+ S2MPU05_REG_L11CTRL2,
+ S2MPU05_REG_L12CTRL,
+ S2MPU05_REG_L13CTRL,
+ S2MPU05_REG_L14CTRL,
+ S2MPU05_REG_L15CTRL,
+ S2MPU05_REG_L16CTRL,
+ S2MPU05_REG_L17CTRL1,
+ S2MPU05_REG_L17CTRL2,
+ S2MPU05_REG_L18CTRL1,
+ S2MPU05_REG_L18CTRL2,
+ S2MPU05_REG_L19CTRL,
+ S2MPU05_REG_L20CTRL,
+ S2MPU05_REG_L21CTRL,
+ S2MPU05_REG_L22CTRL,
+ S2MPU05_REG_L23CTRL,
+ S2MPU05_REG_L24CTRL,
+ S2MPU05_REG_L25CTRL,
+ S2MPU05_REG_L26CTRL,
+ S2MPU05_REG_L27CTRL,
+ S2MPU05_REG_L28CTRL,
+ S2MPU05_REG_L29CTRL,
+ S2MPU05_REG_L30CTRL,
+ S2MPU05_REG_L31CTRL,
+ S2MPU05_REG_L32CTRL,
+ S2MPU05_REG_L33CTRL,
+ S2MPU05_REG_L34CTRL,
+ S2MPU05_REG_L35CTRL,
+ S2MPU05_REG_LDO_DSCH1,
+ S2MPU05_REG_LDO_DSCH2,
+ S2MPU05_REG_LDO_DSCH3,
+ S2MPU05_REG_LDO_DSCH4,
+ S2MPU05_REG_LDO_DSCH5,
+ S2MPU05_REG_LDO_CTRL1,
+ S2MPU05_REG_LDO_CTRL2,
+ S2MPU05_REG_TCXO_CTRL,
+ S2MPU05_REG_SELMIF,
+ S2MPU05_REG_COUNT,
+};
+
+#define S2MPU05_OF_BUCK_PREFIX "buck"
+#define S2MPU05_OF_LDO_PREFIX "ldo"
+
+/* BUCK */
+#define S2MPU05_BUCK_MIN1 400000
+#define S2MPU05_BUCK_MIN2 600000
+#define S2MPU05_BUCK_STEP1 6250
+#define S2MPU05_BUCK_STEP2 12500
+
+/* LDO */
+#define S2MPU05_LDO_MIN1 800000
+#define S2MPU05_LDO_MIN2 1800000
+#define S2MPU05_LDO_MIN3 400000
+#define S2MPU05_LDO_STEP1 12500
+#define S2MPU05_LDO_STEP2 25000
+
+struct sec_regulator_desc {
+ /* regulator mode control */
+ unsigned int mode_reg;
+ unsigned int mode_mask;
+
+ /* regulator voltage control */
+ unsigned int volt_reg;
+ unsigned int volt_mask;
+
+ unsigned int volt_min;
+ unsigned int volt_step;
+ unsigned int volt_max_hex;
+};
+
enum {
OP_OFF = 0,
OP_LPM,
@@ -161,4 +283,10 @@ enum {
OP_ON,
};
+enum {
+ VARIANT_NONE,
+ VARIANT_S2MPS11,
+ VARIANT_S2MPU05,
+};
+
#endif
diff --git a/include/sdhci.h b/include/sdhci.h
index 2372697b743..d9c0597a0c1 100644
--- a/include/sdhci.h
+++ b/include/sdhci.h
@@ -143,7 +143,7 @@
#define SDHCI_INT_CMD_MASK (SDHCI_INT_RESPONSE | SDHCI_INT_TIMEOUT | \
SDHCI_INT_CRC | SDHCI_INT_END_BIT | SDHCI_INT_INDEX)
#define SDHCI_INT_DATA_MASK (SDHCI_INT_DATA_END | SDHCI_INT_DMA_END | \
- SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | \
+ SDHCI_INT_SPACE_AVAIL | SDHCI_INT_DATA_AVAIL | \
SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_DATA_CRC | \
SDHCI_INT_DATA_END_BIT | SDHCI_INT_ADMA_ERROR)
#define SDHCI_INT_ALL_MASK ((unsigned int)-1)