[2/6] sdhci: introduce ops->pre_voltage_switch and extend voltage_switch

Message ID 20180327163350.15862-2-a.heider@gmail.com
State New
Headers show
Series
  • [1/6] tegra: pmc: move IO pad IDs to a devicetree binding
Related show

Commit Message

Andre Heider March 27, 2018, 4:33 p.m.
From: SwtcR <swtcr0@gmail.com>

Provide a hook to be called *before* a voltage switch takes place. This
may be required, for example, to configure pins as 3.3V tolerant prior
to switching back from 1.8V to 3.3V.

This adds a 'struct mmc_ios' arg to voltage_switch to signal which
voltage we have just switched to.

Signed-off-by: SwtcR <swtcr0@gmail.com>
Signed-off-by: Andre Heider <a.heider@gmail.com>
---
 drivers/mmc/host/sdhci-tegra.c   |  2 +-
 drivers/mmc/host/sdhci.c         | 16 +++++++++++++++-
 drivers/mmc/host/sdhci.h         |  4 +++-
 drivers/mmc/host/sdhci_f_sdh30.c |  7 ++++++-
 4 files changed, 25 insertions(+), 4 deletions(-)

Patch

diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c
index b877c13184c2..c545f0f34bf9 100644
--- a/drivers/mmc/host/sdhci-tegra.c
+++ b/drivers/mmc/host/sdhci-tegra.c
@@ -289,7 +289,7 @@  static int tegra_sdhci_execute_tuning(struct sdhci_host *host, u32 opcode)
 	return mmc_send_tuning(host->mmc, opcode, NULL);
 }
 
-static void tegra_sdhci_voltage_switch(struct sdhci_host *host)
+static void tegra_sdhci_voltage_switch(struct sdhci_host *host, struct mmc_ios *ios)
 {
 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
 	struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host);
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 2020e57ffa7e..6a6ca87e9859 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1929,6 +1929,10 @@  int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
 	case MMC_SIGNAL_VOLTAGE_330:
 		if (!(host->flags & SDHCI_SIGNALING_330))
 			return -EINVAL;
+
+		if (host->ops->pre_voltage_switch)
+			host->ops->pre_voltage_switch(host, ios);
+
 		/* Set 1.8V Signal Enable in the Host Control2 register to 0 */
 		ctrl &= ~SDHCI_CTRL_VDD_180;
 		sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
@@ -1941,6 +1945,11 @@  int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
 				return -EIO;
 			}
 		}
+
+		/* Some controller need to do more when switching */
+		if (host->ops->voltage_switch)
+			host->ops->voltage_switch(host, ios);
+
 		/* Wait for 5ms */
 		usleep_range(5000, 5500);
 
@@ -1956,6 +1965,11 @@  int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
 	case MMC_SIGNAL_VOLTAGE_180:
 		if (!(host->flags & SDHCI_SIGNALING_180))
 			return -EINVAL;
+
+		/* Some controller need to do more when switching */
+		if (host->ops->pre_voltage_switch)
+			host->ops->pre_voltage_switch(host, ios);
+
 		if (!IS_ERR(mmc->supply.vqmmc)) {
 			ret = mmc_regulator_set_vqmmc(mmc, ios);
 			if (ret) {
@@ -1974,7 +1988,7 @@  int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
 
 		/* Some controller need to do more when switching */
 		if (host->ops->voltage_switch)
-			host->ops->voltage_switch(host);
+			host->ops->voltage_switch(host, ios);
 
 		/* 1.8V regulator output should be stable within 5 ms */
 		ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index c95b0a4a7594..57a0ea885d1f 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -587,7 +587,9 @@  struct sdhci_ops {
 	void	(*hw_reset)(struct sdhci_host *host);
 	void    (*adma_workaround)(struct sdhci_host *host, u32 intmask);
 	void    (*card_event)(struct sdhci_host *host);
-	void	(*voltage_switch)(struct sdhci_host *host);
+	void	(*pre_voltage_switch)(struct sdhci_host *host,
+				      struct mmc_ios *ios);
+	void	(*voltage_switch)(struct sdhci_host *host, struct mmc_ios *ios);
 };
 
 #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
diff --git a/drivers/mmc/host/sdhci_f_sdh30.c b/drivers/mmc/host/sdhci_f_sdh30.c
index 485f7591fae4..d902b1fa6b2c 100644
--- a/drivers/mmc/host/sdhci_f_sdh30.c
+++ b/drivers/mmc/host/sdhci_f_sdh30.c
@@ -53,11 +53,16 @@  struct f_sdhost_priv {
 	bool enable_cmd_dat_delay;
 };
 
-static void sdhci_f_sdh30_soft_voltage_switch(struct sdhci_host *host)
+static void sdhci_f_sdh30_soft_voltage_switch(struct sdhci_host *host,
+					      struct mmc_ios *ios)
 {
 	struct f_sdhost_priv *priv = sdhci_priv(host);
 	u32 ctrl = 0;
 
+	// FIXME: do something when switching back to 3.3V?
+	if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180)
+		return;
+
 	usleep_range(2500, 3000);
 	ctrl = sdhci_readl(host, F_SDH30_IO_CONTROL2);
 	ctrl |= F_SDH30_CRES_O_DN;