diff mbox series

[2/2] mmc: jz4740: Add support for vqmmc power supply

Message ID 20230131210229.68129-2-paul@crapouillou.net
State New
Headers show
Series [1/2] mmc: jz4740: Work around bug on JZ4760(B) | expand

Commit Message

Paul Cercueil Jan. 31, 2023, 9:02 p.m. UTC
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

Ulf Hansson Feb. 13, 2023, 11:48 p.m. UTC | #1
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
>
diff mbox series

Patch

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 *