[2/2] mmc: jz4740: Add support for vqmmc power supply
Commit Message
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>
---
drivers/mmc/host/jz4740_mmc.c | 38 ++++++++++++++++++++++++++++++++++-
1 file changed, 37 insertions(+), 1 deletion(-)
Comments
On Tue, 31 Jan 2023 at 22:02, Paul Cercueil <paul@crapouillou.net> wrote:
>
> 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>
Applied for next, thanks!
Kind regards
Uffe
> ---
> drivers/mmc/host/jz4740_mmc.c | 38 ++++++++++++++++++++++++++++++++++-
> 1 file changed, 37 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c
> index eb8e9607b086..ccd2c3aed0f0 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/rwsem.h>
> #include <linux/scatterlist.h>
>
> @@ -162,6 +163,8 @@ struct jz4740_mmc_host {
> struct mmc_request *req;
> struct mmc_command *cmd;
>
> + bool vqmmc_enabled;
> +
> unsigned long waiting;
>
> uint32_t cmdat;
> @@ -943,6 +946,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);
>
> @@ -955,12 +960,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) {
> @@ -986,6 +1004,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,
> @@ -994,6 +1029,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 inline struct jz4740_mmc_host *
> --
> 2.39.1
>
@@ -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/rwsem.h>
#include <linux/scatterlist.h>
@@ -162,6 +163,8 @@ struct jz4740_mmc_host {
struct mmc_request *req;
struct mmc_command *cmd;
+ bool vqmmc_enabled;
+
unsigned long waiting;
uint32_t cmdat;
@@ -943,6 +946,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);
@@ -955,12 +960,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) {
@@ -986,6 +1004,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,
@@ -994,6 +1029,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 inline struct jz4740_mmc_host *