diff options
| author | Tom Rini <[email protected]> | 2025-10-30 07:31:14 -0600 |
|---|---|---|
| committer | Tom Rini <[email protected]> | 2025-10-30 07:31:14 -0600 |
| commit | 5b14ff3a0eee77bdf942edb54594a3d3076d11a3 (patch) | |
| tree | aa7b89967fe13b377db8f1e7df90af4a59190eda | |
| parent | e34d01d23e45e007368685ffa6dfd674b6dd7b17 (diff) | |
| parent | e16018f6b22d36f9f6b9f881175547457c06dae3 (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.c | 50 | ||||
| -rw-r--r-- | drivers/mmc/exynos_dw_mmc.c | 142 | ||||
| -rw-r--r-- | drivers/mmc/mmc.c | 75 | ||||
| -rw-r--r-- | drivers/power/pmic/s2mps11.c | 37 | ||||
| -rw-r--r-- | drivers/power/regulator/fixed.c | 1 | ||||
| -rw-r--r-- | drivers/power/regulator/gpio-regulator.c | 1 | ||||
| -rw-r--r-- | drivers/power/regulator/regulator_common.c | 1 | ||||
| -rw-r--r-- | drivers/power/regulator/s2mps11_regulator.c | 590 | ||||
| -rw-r--r-- | include/dwmmc.h | 7 | ||||
| -rw-r--r-- | include/mmc.h | 3 | ||||
| -rw-r--r-- | include/power/s2mps11.h | 134 | ||||
| -rw-r--r-- | include/sdhci.h | 2 |
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) |
