summaryrefslogtreecommitdiffstats
path: root/drivers/mmc/host/sunxi-mmc.c
diff options
context:
space:
mode:
authorChen-Yu Tsai <wens@csie.org>2016-01-21 13:26:31 +0800
committerUlf Hansson <ulf.hansson@linaro.org>2016-02-29 11:02:51 +0100
commitf771f6e832ce0b5e0d8b30b33c3f1d62f92655de (patch)
treec41789128402b52ce02155905e767bb0d684eacc /drivers/mmc/host/sunxi-mmc.c
parent4159215ac9aa020c0815141f1916b33dc226fb42 (diff)
downloadlinux-stable-f771f6e832ce0b5e0d8b30b33c3f1d62f92655de.tar.gz
linux-stable-f771f6e832ce0b5e0d8b30b33c3f1d62f92655de.tar.bz2
linux-stable-f771f6e832ce0b5e0d8b30b33c3f1d62f92655de.zip
mmc: sunxi: Support vqmmc regulator
eMMC chips require 2 power supplies, vmmc for internal logic, and vqmmc for driving output buffers. vqmmc also controls signaling voltage. Most boards we've seen use the same regulator for both, nevertheless the 2 have different usages, and should be set separately. This patch adds support for vqmmc regulator supply, including voltage switching. The MMC core can use this to try different signaling voltages for eMMC. Signed-off-by: Chen-Yu Tsai <wens@csie.org> Acked-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Diffstat (limited to 'drivers/mmc/host/sunxi-mmc.c')
-rw-r--r--drivers/mmc/host/sunxi-mmc.c31
1 files changed, 31 insertions, 0 deletions
diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c
index 790f01662b4e..765dfb9f77ec 100644
--- a/drivers/mmc/host/sunxi-mmc.c
+++ b/drivers/mmc/host/sunxi-mmc.c
@@ -28,6 +28,7 @@
#include <linux/dma-mapping.h>
#include <linux/slab.h>
#include <linux/reset.h>
+#include <linux/regulator/consumer.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
@@ -256,6 +257,9 @@ struct sunxi_mmc_host {
struct mmc_request *mrq;
struct mmc_request *manual_stop_mrq;
int ferror;
+
+ /* vqmmc */
+ bool vqmmc_enabled;
};
static int sunxi_mmc_reset_host(struct sunxi_mmc_host *host)
@@ -716,6 +720,16 @@ static void sunxi_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
if (host->ferror)
return;
+ if (!IS_ERR(mmc->supply.vqmmc)) {
+ host->ferror = regulator_enable(mmc->supply.vqmmc);
+ if (host->ferror) {
+ dev_err(mmc_dev(mmc),
+ "failed to enable vqmmc\n");
+ return;
+ }
+ host->vqmmc_enabled = true;
+ }
+
host->ferror = sunxi_mmc_init_host(mmc);
if (host->ferror)
return;
@@ -727,6 +741,9 @@ static void sunxi_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
dev_dbg(mmc_dev(mmc), "power off!\n");
sunxi_mmc_reset_host(host);
mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
+ if (!IS_ERR(mmc->supply.vqmmc) && host->vqmmc_enabled)
+ regulator_disable(mmc->supply.vqmmc);
+ host->vqmmc_enabled = false;
break;
}
@@ -758,6 +775,19 @@ static void sunxi_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
}
}
+static int sunxi_mmc_volt_switch(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+ /* vqmmc regulator is available */
+ if (!IS_ERR(mmc->supply.vqmmc))
+ return mmc_regulator_set_vqmmc(mmc, ios);
+
+ /* no vqmmc regulator, assume fixed regulator at 3/3.3V */
+ if (mmc->ios.signal_voltage == MMC_SIGNAL_VOLTAGE_330)
+ return 0;
+
+ return -EINVAL;
+}
+
static void sunxi_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
{
struct sunxi_mmc_host *host = mmc_priv(mmc);
@@ -909,6 +939,7 @@ static struct mmc_host_ops sunxi_mmc_ops = {
.get_ro = mmc_gpio_get_ro,
.get_cd = mmc_gpio_get_cd,
.enable_sdio_irq = sunxi_mmc_enable_sdio_irq,
+ .start_signal_voltage_switch = sunxi_mmc_volt_switch,
.hw_reset = sunxi_mmc_hw_reset,
.card_busy = sunxi_mmc_card_busy,
};