diff options
-rw-r--r-- | drivers/mmc/host/omap_hsmmc.c | 83 |
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); /* |