Commit 3a48edc4 authored by Tim Kryger's avatar Tim Kryger Committed by Ulf Hansson

mmc: sdhci: Use mmc core regulator infrastucture

Switch the common SDHCI code over to use mmc_host's regulator pointers
and remove the ones in the sdhci_host structure.  Additionally, use the
common mmc_regulator_get_supply function to get the regulators and set
the ocr_avail mask.

This change sets the ocr_avail directly based upon the voltage ranges
supported which ensures ocr_avail is set correctly while allowing the
use of regulators that can't provide exactly 1.8v, 3.0v, or 3.3v.
Signed-off-by: default avatarTim Kryger <tim.kryger@gmail.com>
Signed-off-by: default avatarMarkus Mayer <markus.mayer@linaro.org>
Reviewed-by: default avatarMatt Porter <mporter@linaro.org>
Signed-off-by: default avatarUlf Hansson <ulf.hansson@linaro.org>
parent 2e42da59
...@@ -1223,6 +1223,7 @@ EXPORT_SYMBOL_GPL(sdhci_set_clock); ...@@ -1223,6 +1223,7 @@ EXPORT_SYMBOL_GPL(sdhci_set_clock);
static void sdhci_set_power(struct sdhci_host *host, unsigned char mode, static void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
unsigned short vdd) unsigned short vdd)
{ {
struct mmc_host *mmc = host->mmc;
u8 pwr = 0; u8 pwr = 0;
if (mode != MMC_POWER_OFF) { if (mode != MMC_POWER_OFF) {
...@@ -1284,9 +1285,9 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned char mode, ...@@ -1284,9 +1285,9 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
mdelay(10); mdelay(10);
} }
if (host->vmmc) { if (!IS_ERR(mmc->supply.vmmc)) {
spin_unlock_irq(&host->lock); spin_unlock_irq(&host->lock);
mmc_regulator_set_ocr(host->mmc, host->vmmc, vdd); mmc_regulator_set_ocr(host->mmc, mmc->supply.vmmc, vdd);
spin_lock_irq(&host->lock); spin_lock_irq(&host->lock);
} }
} }
...@@ -1440,13 +1441,15 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) ...@@ -1440,13 +1441,15 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
{ {
unsigned long flags; unsigned long flags;
u8 ctrl; u8 ctrl;
struct mmc_host *mmc = host->mmc;
spin_lock_irqsave(&host->lock, flags); spin_lock_irqsave(&host->lock, flags);
if (host->flags & SDHCI_DEVICE_DEAD) { if (host->flags & SDHCI_DEVICE_DEAD) {
spin_unlock_irqrestore(&host->lock, flags); spin_unlock_irqrestore(&host->lock, flags);
if (host->vmmc && ios->power_mode == MMC_POWER_OFF) if (!IS_ERR(mmc->supply.vmmc) &&
mmc_regulator_set_ocr(host->mmc, host->vmmc, 0); ios->power_mode == MMC_POWER_OFF)
mmc_regulator_set_ocr(host->mmc, mmc->supply.vmmc, 0);
return; return;
} }
...@@ -1707,6 +1710,7 @@ static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable) ...@@ -1707,6 +1710,7 @@ static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host, static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
struct mmc_ios *ios) struct mmc_ios *ios)
{ {
struct mmc_host *mmc = host->mmc;
u16 ctrl; u16 ctrl;
int ret; int ret;
...@@ -1725,8 +1729,9 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host, ...@@ -1725,8 +1729,9 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
ctrl &= ~SDHCI_CTRL_VDD_180; ctrl &= ~SDHCI_CTRL_VDD_180;
sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
if (host->vqmmc) { if (!IS_ERR(mmc->supply.vqmmc)) {
ret = regulator_set_voltage(host->vqmmc, 2700000, 3600000); ret = regulator_set_voltage(mmc->supply.vqmmc, 2700000,
3600000);
if (ret) { if (ret) {
pr_warning("%s: Switching to 3.3V signalling voltage " pr_warning("%s: Switching to 3.3V signalling voltage "
" failed\n", mmc_hostname(host->mmc)); " failed\n", mmc_hostname(host->mmc));
...@@ -1746,8 +1751,8 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host, ...@@ -1746,8 +1751,8 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
return -EAGAIN; return -EAGAIN;
case MMC_SIGNAL_VOLTAGE_180: case MMC_SIGNAL_VOLTAGE_180:
if (host->vqmmc) { if (!IS_ERR(mmc->supply.vqmmc)) {
ret = regulator_set_voltage(host->vqmmc, ret = regulator_set_voltage(mmc->supply.vqmmc,
1700000, 1950000); 1700000, 1950000);
if (ret) { if (ret) {
pr_warning("%s: Switching to 1.8V signalling voltage " pr_warning("%s: Switching to 1.8V signalling voltage "
...@@ -1776,8 +1781,9 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host, ...@@ -1776,8 +1781,9 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
return -EAGAIN; return -EAGAIN;
case MMC_SIGNAL_VOLTAGE_120: case MMC_SIGNAL_VOLTAGE_120:
if (host->vqmmc) { if (!IS_ERR(mmc->supply.vqmmc)) {
ret = regulator_set_voltage(host->vqmmc, 1100000, 1300000); ret = regulator_set_voltage(mmc->supply.vqmmc, 1100000,
1300000);
if (ret) { if (ret) {
pr_warning("%s: Switching to 1.2V signalling voltage " pr_warning("%s: Switching to 1.2V signalling voltage "
" failed\n", mmc_hostname(host->mmc)); " failed\n", mmc_hostname(host->mmc));
...@@ -2962,25 +2968,22 @@ int sdhci_add_host(struct sdhci_host *host) ...@@ -2962,25 +2968,22 @@ int sdhci_add_host(struct sdhci_host *host)
!(host->mmc->caps & MMC_CAP_NONREMOVABLE)) !(host->mmc->caps & MMC_CAP_NONREMOVABLE))
mmc->caps |= MMC_CAP_NEEDS_POLL; mmc->caps |= MMC_CAP_NEEDS_POLL;
/* If there are external regulators, get them */
if (mmc_regulator_get_supply(mmc) == -EPROBE_DEFER)
return -EPROBE_DEFER;
/* If vqmmc regulator and no 1.8V signalling, then there's no UHS */ /* If vqmmc regulator and no 1.8V signalling, then there's no UHS */
host->vqmmc = regulator_get_optional(mmc_dev(mmc), "vqmmc"); if (!IS_ERR(mmc->supply.vqmmc)) {
if (IS_ERR_OR_NULL(host->vqmmc)) { ret = regulator_enable(mmc->supply.vqmmc);
if (PTR_ERR(host->vqmmc) < 0) { if (!regulator_is_supported_voltage(mmc->supply.vqmmc, 1700000,
pr_info("%s: no vqmmc regulator found\n", 1950000))
mmc_hostname(mmc));
host->vqmmc = NULL;
}
} else {
ret = regulator_enable(host->vqmmc);
if (!regulator_is_supported_voltage(host->vqmmc, 1700000,
1950000))
caps[1] &= ~(SDHCI_SUPPORT_SDR104 | caps[1] &= ~(SDHCI_SUPPORT_SDR104 |
SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_SDR50 |
SDHCI_SUPPORT_DDR50); SDHCI_SUPPORT_DDR50);
if (ret) { if (ret) {
pr_warn("%s: Failed to enable vqmmc regulator: %d\n", pr_warn("%s: Failed to enable vqmmc regulator: %d\n",
mmc_hostname(mmc), ret); mmc_hostname(mmc), ret);
host->vqmmc = NULL; mmc->supply.vqmmc = NULL;
} }
} }
...@@ -3041,34 +3044,6 @@ int sdhci_add_host(struct sdhci_host *host) ...@@ -3041,34 +3044,6 @@ int sdhci_add_host(struct sdhci_host *host)
ocr_avail = 0; ocr_avail = 0;
host->vmmc = regulator_get_optional(mmc_dev(mmc), "vmmc");
if (IS_ERR_OR_NULL(host->vmmc)) {
if (PTR_ERR(host->vmmc) < 0) {
pr_info("%s: no vmmc regulator found\n",
mmc_hostname(mmc));
host->vmmc = NULL;
}
}
#ifdef CONFIG_REGULATOR
/*
* Voltage range check makes sense only if regulator reports
* any voltage value.
*/
if (host->vmmc && regulator_get_voltage(host->vmmc) > 0) {
ret = regulator_is_supported_voltage(host->vmmc, 2700000,
3600000);
if ((ret <= 0) || (!(caps[0] & SDHCI_CAN_VDD_330)))
caps[0] &= ~SDHCI_CAN_VDD_330;
if ((ret <= 0) || (!(caps[0] & SDHCI_CAN_VDD_300)))
caps[0] &= ~SDHCI_CAN_VDD_300;
ret = regulator_is_supported_voltage(host->vmmc, 1700000,
1950000);
if ((ret <= 0) || (!(caps[0] & SDHCI_CAN_VDD_180)))
caps[0] &= ~SDHCI_CAN_VDD_180;
}
#endif /* CONFIG_REGULATOR */
/* /*
* According to SD Host Controller spec v3.00, if the Host System * According to SD Host Controller spec v3.00, if the Host System
* can afford more than 150mA, Host Driver should set XPC to 1. Also * can afford more than 150mA, Host Driver should set XPC to 1. Also
...@@ -3077,8 +3052,8 @@ int sdhci_add_host(struct sdhci_host *host) ...@@ -3077,8 +3052,8 @@ int sdhci_add_host(struct sdhci_host *host)
* value. * value.
*/ */
max_current_caps = sdhci_readl(host, SDHCI_MAX_CURRENT); max_current_caps = sdhci_readl(host, SDHCI_MAX_CURRENT);
if (!max_current_caps && host->vmmc) { if (!max_current_caps && !IS_ERR(mmc->supply.vmmc)) {
u32 curr = regulator_get_current_limit(host->vmmc); u32 curr = regulator_get_current_limit(mmc->supply.vmmc);
if (curr > 0) { if (curr > 0) {
/* convert to SDHCI_MAX_CURRENT format */ /* convert to SDHCI_MAX_CURRENT format */
...@@ -3118,8 +3093,11 @@ int sdhci_add_host(struct sdhci_host *host) ...@@ -3118,8 +3093,11 @@ int sdhci_add_host(struct sdhci_host *host)
SDHCI_MAX_CURRENT_MULTIPLIER; SDHCI_MAX_CURRENT_MULTIPLIER;
} }
if (mmc->ocr_avail)
ocr_avail &= mmc->ocr_avail;
if (host->ocr_mask) if (host->ocr_mask)
ocr_avail = host->ocr_mask; ocr_avail &= host->ocr_mask;
mmc->ocr_avail = ocr_avail; mmc->ocr_avail = ocr_avail;
mmc->ocr_avail_sdio = ocr_avail; mmc->ocr_avail_sdio = ocr_avail;
...@@ -3273,6 +3251,7 @@ EXPORT_SYMBOL_GPL(sdhci_add_host); ...@@ -3273,6 +3251,7 @@ EXPORT_SYMBOL_GPL(sdhci_add_host);
void sdhci_remove_host(struct sdhci_host *host, int dead) void sdhci_remove_host(struct sdhci_host *host, int dead)
{ {
struct mmc_host *mmc = host->mmc;
unsigned long flags; unsigned long flags;
if (dead) { if (dead) {
...@@ -3310,15 +3289,11 @@ void sdhci_remove_host(struct sdhci_host *host, int dead) ...@@ -3310,15 +3289,11 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
tasklet_kill(&host->finish_tasklet); tasklet_kill(&host->finish_tasklet);
if (host->vmmc) { if (!IS_ERR(mmc->supply.vmmc))
regulator_disable(host->vmmc); regulator_disable(mmc->supply.vmmc);
regulator_put(host->vmmc);
}
if (host->vqmmc) { if (!IS_ERR(mmc->supply.vqmmc))
regulator_disable(host->vqmmc); regulator_disable(mmc->supply.vqmmc);
regulator_put(host->vqmmc);
}
if (host->adma_desc) if (host->adma_desc)
dma_free_coherent(mmc_dev(host->mmc), ADMA_SIZE, dma_free_coherent(mmc_dev(host->mmc), ADMA_SIZE,
......
...@@ -104,9 +104,6 @@ struct sdhci_host { ...@@ -104,9 +104,6 @@ struct sdhci_host {
const struct sdhci_ops *ops; /* Low level hw interface */ const struct sdhci_ops *ops; /* Low level hw interface */
struct regulator *vmmc; /* Power regulator (vmmc) */
struct regulator *vqmmc; /* Signaling regulator (vccq) */
/* Internal data */ /* Internal data */
struct mmc_host *mmc; /* MMC structure */ struct mmc_host *mmc; /* MMC structure */
u64 dma_mask; /* custom DMA mask */ u64 dma_mask; /* custom DMA mask */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment