summaryrefslogtreecommitdiffstats
path: root/drivers/mmc/host/sdhci.c
diff options
context:
space:
mode:
authorAdrian Hunter2016-06-29 15:24:16 +0200
committerUlf Hansson2016-07-25 10:34:34 +0200
commit8cb851a4da64aa838c3cb4fa76ad130ace2b5a98 (patch)
tree3ed652f9d0267aeb7be5ec59ca979d2ae9f42778 /drivers/mmc/host/sdhci.c
parentmmc: sdhci: Split sdhci_add_host() (diff)
downloadkernel-qcow2-linux-8cb851a4da64aa838c3cb4fa76ad130ace2b5a98.tar.gz
kernel-qcow2-linux-8cb851a4da64aa838c3cb4fa76ad130ace2b5a98.tar.xz
kernel-qcow2-linux-8cb851a4da64aa838c3cb4fa76ad130ace2b5a98.zip
mmc: sdhci: Make signal voltage support explicit
Signal voltage support is not a quirk, it is a capability. According to the SDHCI specification, support for 1.8V signaling is determined by the presence of one of the capability bits SDHCI_SUPPORT_SDR50, SDHCI_SUPPORT_SDR104, or SDHCI_SUPPORT_DDR50. This is complicated by also supporting eMMC which has 1.8V modes and 1.2V modes. It would be possible to use the transfer mode to determine signal voltage support, except for eMMC DDR52 mode which uses the same capability (MMC_CAP_1_8V_DDR) for 1.8V signaling and 3V signaling. In addition, the mmc core will fail over from one signaling voltage to the next (refer mmc_power_up()) which means SDHCI really needs to validate which voltages are actually supported. Introduce SDHCI flags for signal voltage support and set them based on the supported transfer modes. In general, drivers should prefer to set the supported transfer modes correctly rather than change the signal voltage capability, except in the case where 3V DDR52 is supported but 1.8V is not. Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Diffstat (limited to 'drivers/mmc/host/sdhci.c')
-rw-r--r--drivers/mmc/host/sdhci.c17
1 files changed, 17 insertions, 0 deletions
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 22061faf7fa4..8ac5a9df2c01 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1733,6 +1733,8 @@ static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
switch (ios->signal_voltage) {
case MMC_SIGNAL_VOLTAGE_330:
+ if (!(host->flags & SDHCI_SIGNALING_330))
+ return -EINVAL;
/* Set 1.8V Signal Enable in the Host Control2 register to 0 */
ctrl &= ~SDHCI_CTRL_VDD_180;
sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
@@ -1759,6 +1761,8 @@ static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
return -EAGAIN;
case MMC_SIGNAL_VOLTAGE_180:
+ if (!(host->flags & SDHCI_SIGNALING_180))
+ return -EINVAL;
if (!IS_ERR(mmc->supply.vqmmc)) {
ret = regulator_set_voltage(mmc->supply.vqmmc,
1700000, 1950000);
@@ -1790,6 +1794,8 @@ static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
return -EAGAIN;
case MMC_SIGNAL_VOLTAGE_120:
+ if (!(host->flags & SDHCI_SIGNALING_120))
+ return -EINVAL;
if (!IS_ERR(mmc->supply.vqmmc)) {
ret = regulator_set_voltage(mmc->supply.vqmmc, 1100000,
1300000);
@@ -2798,6 +2804,8 @@ struct sdhci_host *sdhci_alloc_host(struct device *dev,
host->mmc_host_ops = sdhci_ops;
mmc->ops = &host->mmc_host_ops;
+ host->flags = SDHCI_SIGNALING_330;
+
return host;
}
@@ -3257,6 +3265,15 @@ int sdhci_setup_host(struct sdhci_host *host)
goto unreg;
}
+ if ((mmc->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
+ MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 |
+ MMC_CAP_UHS_DDR50 | MMC_CAP_1_8V_DDR)) ||
+ (mmc->caps2 & (MMC_CAP2_HS200_1_8V_SDR | MMC_CAP2_HS400_1_8V)))
+ host->flags |= SDHCI_SIGNALING_180;
+
+ if (mmc->caps2 & MMC_CAP2_HSX00_1_2V)
+ host->flags |= SDHCI_SIGNALING_120;
+
spin_lock_init(&host->lock);
/*