summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/mmc/host/omap_hsmmc.c83
1 files changed, 67 insertions, 16 deletions
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index e3d6a6e2a6f8..2738871e2933 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -78,6 +78,7 @@
#define MADMA_EN (1 << 0)
#define VS18 (1 << 26)
#define VS30 (1 << 25)
+#define VS33 (1 << 24)
#define VS_MASK (0x7 << 24)
#define HSS (1 << 21)
#define SDVS18 (0x5 << 9)
@@ -186,8 +187,10 @@
#define VDD_1V8 1800000 /* 180000 uV */
#define VDD_3V0 3000000 /* 300000 uV */
+#define VDD_3V3 3300000 /* 330000 uV */
#define VDD_165_195 (ffs(MMC_VDD_165_195) - 1)
#define VDD_30_31 (ffs(MMC_VDD_30_31) - 1)
+#define VDD_33_34 (ffs(MMC_VDD_33_34) - 1)
#define CON_CLKEXTFREE (1 << 16)
#define CON_PADEN (1 << 15)
@@ -257,6 +260,7 @@ struct omap_hsmmc_host {
struct clk *dbclk;
struct regulator *pbias;
bool pbias_enabled;
+ bool io_3_3v_support;
void __iomem *base;
int vqmmc_enabled;
resource_size_t mapbase;
@@ -368,7 +372,13 @@ static int omap_hsmmc_enable_supply(struct mmc_host *mmc, int iov)
host->vqmmc_enabled = 0;
}
- uvoltage = (iov == VDD_165_195) ? VDD_1V8 : VDD_3V0;
+ if (iov == VDD_165_195)
+ uvoltage = VDD_1V8;
+ else if (iov == VDD_33_34)
+ uvoltage = VDD_3V3;
+ else
+ uvoltage = VDD_3V0;
+
ret = regulator_set_voltage(mmc->supply.vqmmc, uvoltage,
uvoltage);
if (ret) {
@@ -436,7 +446,13 @@ static int omap_hsmmc_set_pbias(struct omap_hsmmc_host *host, bool power_on,
return 0;
if (power_on) {
- uvoltage = (iov <= VDD_165_195) ? VDD_1V8 : VDD_3V0;
+ if (iov <= VDD_165_195)
+ uvoltage = VDD_1V8;
+ else if (iov == VDD_33_34)
+ uvoltage = VDD_3V3;
+ else
+ uvoltage = VDD_3V0;
+
ret = regulator_set_voltage(host->pbias, uvoltage, uvoltage);
if (ret) {
dev_err(host->dev, "pbias set voltage failed\n");
@@ -862,12 +878,21 @@ static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host)
if (host->power_mode != MMC_POWER_OFF &&
(1 << ios->vdd) <= MMC_VDD_23_24)
hctl = SDVS18;
- else
+ else if (host->io_3_3v_support) {
+ hctl = SDVS33;
+ capa = VS33 | VS18;
+ } else {
hctl = SDVS30;
- capa = VS30 | VS18;
+ capa = VS30 | VS18;
+ }
} else if (host->pdata->controller_flags & OMAP_HSMMC_NO_1_8_V) {
- hctl = SDVS30;
- capa = VS30;
+ if (host->io_3_3v_support) {
+ hctl = SDVS33;
+ capa = VS33;
+ } else {
+ hctl = SDVS30;
+ capa = VS30;
+ }
} else {
hctl = SDVS18;
capa = VS18;
@@ -2150,9 +2175,15 @@ static void omap_hsmmc_set_capabilities(struct omap_hsmmc_host *host)
val = OMAP_HSMMC_READ(host->base, CAPA) & ~VS_MASK;
if (host->pdata->controller_flags & OMAP_HSMMC_SUPPORTS_DUAL_VOLT) {
- val |= (VS30 | VS18);
+ if (host->io_3_3v_support)
+ val |= (VS33 | VS18);
+ else
+ val |= (VS30 | VS18);
} else if (host->pdata->controller_flags & OMAP_HSMMC_NO_1_8_V) {
- val |= VS30;
+ if (host->io_3_3v_support)
+ val |= VS33;
+ else
+ val |= VS30;
} else {
val |= VS18;
}
@@ -2162,10 +2193,15 @@ static void omap_hsmmc_set_capabilities(struct omap_hsmmc_host *host)
static void omap_hsmmc_conf_bus_power(struct omap_hsmmc_host *host, int iov)
{
- u32 hctl, value;
+ u32 hctl = SDVS30, value;
value = OMAP_HSMMC_READ(host->base, HCTL) & ~SDVS_MASK;
- hctl = (iov == MMC_SIGNAL_VOLTAGE_180) ? SDVS18 : SDVS30;
+
+ if (iov == MMC_SIGNAL_VOLTAGE_180)
+ hctl = SDVS18;
+ else if (host->io_3_3v_support)
+ hctl = SDVS33;
+
OMAP_HSMMC_WRITE(host->base, HCTL, value | hctl);
/* Set SD bus power bit */
@@ -2188,27 +2224,35 @@ static int omap_hsmmc_start_signal_voltage_switch(struct mmc_host *mmc,
struct omap_hsmmc_host *host;
u32 val = 0;
int ret = 0;
+ u32 iov;
host = mmc_priv(mmc);
if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
val = OMAP_HSMMC_READ(host->base, CAPA);
- if (!(val & VS30))
+ if (!(val & (VS30 | VS33)))
return -EOPNOTSUPP;
+ if (val & VS33)
+ iov = VDD_33_34;
+ else
+ iov = VDD_30_31;
+
omap_hsmmc_conf_bus_power(host, ios->signal_voltage);
val = OMAP_HSMMC_READ(host->base, AC12);
val &= ~AC12_V1V8_SIGEN;
OMAP_HSMMC_WRITE(host->base, AC12, val);
- ret = omap_hsmmc_set_power(host->dev, 1, VDD_30_31);
+ ret = omap_hsmmc_set_power(host->dev, 1, iov);
if (ret) {
- dev_err(mmc_dev(host->mmc), "failed to switch to 3v\n");
+ dev_err(mmc_dev(host->mmc),
+ "failed to switch to %uV\n", iov);
return ret;
}
- dev_dbg(mmc_dev(host->mmc), " i/o voltage switch to 3V\n");
+ dev_dbg(mmc_dev(host->mmc),
+ "i/o voltage switched to %uV\n", iov);
} else if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180) {
val = OMAP_HSMMC_READ(host->base, CAPA);
if (!(val & VS18))
@@ -2895,8 +2939,6 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
mmc->pm_caps |= mmc_pdata(host)->pm_caps;
- omap_hsmmc_set_capabilities(host);
-
ret = omap_hsmmc_get_iodelay_pinctrl_state(host);
if (ret)
goto err_pinctrl;
@@ -2922,6 +2964,15 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
mmc->ocr_avail = mmc_pdata(host)->ocr_mask;
+ /* Get pbias max-voltage and update host capabilities */
+ if (host->pbias &&
+ regulator_is_supported_voltage(host->pbias, VDD_3V3, VDD_3V3)) {
+ host->io_3_3v_support = true;
+ dev_dbg(mmc_dev(host->mmc), "PBIAS supports 3.3V not 3V\n");
+ }
+
+ omap_hsmmc_set_capabilities(host);
+
omap_hsmmc_disable_irq(host);
/*