diff options
author | Paul Cercueil <paul@crapouillou.net> | 2023-01-31 22:02:29 +0100 |
---|---|---|
committer | Ulf Hansson <ulf.hansson@linaro.org> | 2023-02-14 00:27:13 +0100 |
commit | 152b5245e361f9493d930a1aaa51c932e3dff660 (patch) | |
tree | c172f39629f4eb6133420196dd8bac3f17f0e81b /drivers/mmc | |
parent | mmc: Merge branch fixes into next (diff) | |
download | linux-152b5245e361f9493d930a1aaa51c932e3dff660.tar.xz linux-152b5245e361f9493d930a1aaa51c932e3dff660.zip |
mmc: jz4740: Add support for vqmmc power supply
Support enabling / disabling the vqmmc power supply if it was provided
by the firmware.
Provide the .start_signal_voltage_switch callback to change the voltage
of the external vqmmc power supply.
Signed-off-by: Paul Cercueil <paul@crapouillou.net>
Link: https://lore.kernel.org/r/20230131210229.68129-2-paul@crapouillou.net
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/host/jz4740_mmc.c | 38 |
1 files changed, 37 insertions, 1 deletions
diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c index eda1e2ddcaca..698450afa7bb 100644 --- a/drivers/mmc/host/jz4740_mmc.c +++ b/drivers/mmc/host/jz4740_mmc.c @@ -21,6 +21,7 @@ #include <linux/of_device.h> #include <linux/pinctrl/consumer.h> #include <linux/platform_device.h> +#include <linux/regulator/consumer.h> #include <linux/scatterlist.h> #include <asm/cacheflush.h> @@ -158,6 +159,8 @@ struct jz4740_mmc_host { struct mmc_request *req; struct mmc_command *cmd; + bool vqmmc_enabled; + unsigned long waiting; uint32_t cmdat; @@ -935,6 +938,8 @@ static void jz4740_mmc_request(struct mmc_host *mmc, struct mmc_request *req) static void jz4740_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { struct jz4740_mmc_host *host = mmc_priv(mmc); + int ret; + if (ios->clock) jz4740_mmc_set_clock_rate(host, ios->clock); @@ -947,12 +952,25 @@ static void jz4740_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) clk_prepare_enable(host->clk); break; case MMC_POWER_ON: + if (!IS_ERR(mmc->supply.vqmmc) && !host->vqmmc_enabled) { + ret = regulator_enable(mmc->supply.vqmmc); + if (ret) + dev_err(&host->pdev->dev, "Failed to set vqmmc power!\n"); + else + host->vqmmc_enabled = true; + } break; - default: + case MMC_POWER_OFF: if (!IS_ERR(mmc->supply.vmmc)) 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; + } clk_disable_unprepare(host->clk); break; + default: + break; } switch (ios->bus_width) { @@ -978,6 +996,23 @@ static void jz4740_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable) jz4740_mmc_set_irq_enabled(host, JZ_MMC_IRQ_SDIO, enable); } +static int jz4740_voltage_switch(struct mmc_host *mmc, struct mmc_ios *ios) +{ + int ret; + + /* vqmmc regulator is available */ + if (!IS_ERR(mmc->supply.vqmmc)) { + ret = mmc_regulator_set_vqmmc(mmc, ios); + return ret < 0 ? ret : 0; + } + + /* no vqmmc regulator, assume fixed regulator at 3/3.3V */ + if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) + return 0; + + return -EINVAL; +} + static const struct mmc_host_ops jz4740_mmc_ops = { .request = jz4740_mmc_request, .pre_req = jz4740_mmc_pre_request, @@ -986,6 +1021,7 @@ static const struct mmc_host_ops jz4740_mmc_ops = { .get_ro = mmc_gpio_get_ro, .get_cd = mmc_gpio_get_cd, .enable_sdio_irq = jz4740_mmc_enable_sdio_irq, + .start_signal_voltage_switch = jz4740_voltage_switch, }; static const struct of_device_id jz4740_mmc_of_match[] = { |