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
This commit is contained in:
Tom Rini
2025-10-30 07:31:14 -06:00
12 changed files with 746 additions and 309 deletions

View File

@@ -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

View File

@@ -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;
@@ -378,16 +464,30 @@ 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),
};

View File

@@ -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;
}

View File

@@ -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,
};

View File

@@ -13,7 +13,6 @@
#include <asm/gpio.h>
#include <power/pmic.h>
#include <power/regulator.h>
#include "regulator_common.h"
#include "regulator_common.h"

View File

@@ -12,7 +12,6 @@
#include <linux/printk.h>
#include <power/pmic.h>
#include <power/regulator.h>
#include "regulator_common.h"
#include "regulator_common.h"

View File

@@ -9,7 +9,6 @@
#include <asm/gpio.h>
#include <linux/delay.h>
#include <power/regulator.h>
#include "regulator_common.h"
#include "regulator_common.h"

View File

@@ -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 struct dm_regulator_mode s2mpu05_regulator_modes[] = {
MODE(OP_OFF, S2MPS11_LDO_MODE_OFF, "OFF"),
MODE(OP_ON, S2MPS11_LDO_MODE_ON, "ON"),
};
static const char s2mps11_buck_out[] = {
0xff, 0x26, 0x28, 0x2a, 0x2c, 0x2f, 0x34, 0x36, 0x38, 0x3a, 0x3c
};
static int s2mps11_buck_hex2volt(int buck, int hex)
static const ulong s2mps11_get_variant(struct udevice *dev)
{
unsigned int uV = 0;
struct udevice *parent = dev_get_parent(dev);
if (hex < 0)
goto bad;
switch (buck) {
case 7:
case 8:
case 10:
if (hex > S2MPS11_BUCK7_8_10_VOLT_MAX_HEX)
goto bad;
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;
}
static int s2mps11_buck_volt2hex(int buck, 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;
break;
case 9:
hex = (uV - S2MPS11_BUCK9_UV_MIN) / S2MPS11_BUCK9_STEP;
if (hex > S2MPS11_BUCK9_VOLT_MAX_HEX)
goto bad;
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;
return dev_get_driver_data(parent);
}
static int s2mps11_buck_val(struct udevice *dev, int op, int *uV)
{
int hex, buck, ret;
u32 mask, addr;
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 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;
}
@@ -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;
}
return 0;
}
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;
}
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;
const struct sec_regulator_desc *ldo_desc;
unsigned int addr;
unsigned char val;
int num_ldos, hex, ldo, ret;
if (hex > S2MPS11_LDO_VOLT_MAX_HEX) {
pr_err("Value: %#x is wrong for LDO%d", hex, ldo);
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;
}
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;
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;
break;
default:
hex = (uV - S2MPS11_LDO_UV_MIN) / (S2MPS11_LDO_STEP * 2);
break;
}
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;
}
return 0;
}
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;
}
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;
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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)