[3/6] sdhci-tegra: add support for updating pad I/O voltage via PMC

Message ID 20180327163350.15862-3-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>

This is required on Tegra210 for 1.8V support.

Signed-off-by: SwtcR <swtcr0@gmail.com>
Signed-off-by: Andre Heider <a.heider@gmail.com>
---
 drivers/mmc/host/sdhci-tegra.c | 35 ++++++++++++++++++++++++++++++++++-
 1 file changed, 34 insertions(+), 1 deletion(-)

Patch

diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c
index c545f0f34bf9..254db23eab5f 100644
--- a/drivers/mmc/host/sdhci-tegra.c
+++ b/drivers/mmc/host/sdhci-tegra.c
@@ -27,6 +27,7 @@ 
 #include <linux/mmc/mmc.h>
 #include <linux/mmc/slot-gpio.h>
 #include <linux/gpio/consumer.h>
+#include <soc/tegra/pmc.h>
 
 #include "sdhci-pltfm.h"
 
@@ -55,6 +56,7 @@ 
 #define NVQUIRK_ENABLE_SDR104		BIT(4)
 #define NVQUIRK_ENABLE_DDR50		BIT(5)
 #define NVQUIRK_HAS_PADCALIB		BIT(6)
+#define NVQUIRK_NEEDS_PAD_CONTROL	BIT(7)
 
 struct sdhci_tegra_soc_data {
 	const struct sdhci_pltfm_data *pdata;
@@ -66,6 +68,8 @@  struct sdhci_tegra {
 	struct gpio_desc *power_gpio;
 	bool ddr_signaling;
 	bool pad_calib_required;
+	bool pad_control;
+	unsigned int pad_id;
 
 	struct reset_control *rst;
 };
@@ -166,7 +170,9 @@  static void tegra_sdhci_reset(struct sdhci_host *host, u8 mask)
 	 * even if the device supports it because the IO voltage
 	 * cannot be configured.
 	 */
-	if (!IS_ERR(host->mmc->supply.vqmmc)) {
+	if (!IS_ERR(host->mmc->supply.vqmmc) &&
+	    (!(soc_data->nvquirks & NVQUIRK_NEEDS_PAD_CONTROL) ||
+	     tegra_host->pad_control)) {
 		/* Erratum: Enable SDHCI spec v3.00 support */
 		if (soc_data->nvquirks & NVQUIRK_ENABLE_SDHCI_SPEC_300)
 			misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300;
@@ -297,6 +303,24 @@  static void tegra_sdhci_voltage_switch(struct sdhci_host *host, struct mmc_ios *
 
 	if (soc_data->nvquirks & NVQUIRK_HAS_PADCALIB)
 		tegra_host->pad_calib_required = true;
+
+	if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180) {
+		if (tegra_host->pad_control) {
+			tegra_io_pad_set_voltage(tegra_host->pad_id, TEGRA_IO_PAD_1800000UV);
+		}
+	}
+}
+
+static void tegra_sdhci_pre_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);
+
+	if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
+		if (tegra_host->pad_control) {
+			tegra_io_pad_set_voltage(tegra_host->pad_id, TEGRA_IO_PAD_3300000UV);
+		}
+	}
 }
 
 static const struct sdhci_ops tegra_sdhci_ops = {
@@ -308,6 +332,7 @@  static const struct sdhci_ops tegra_sdhci_ops = {
 	.reset      = tegra_sdhci_reset,
 	.platform_execute_tuning = tegra_sdhci_execute_tuning,
 	.set_uhs_signaling = tegra_sdhci_set_uhs_signaling,
+	.pre_voltage_switch = tegra_sdhci_pre_voltage_switch,
 	.voltage_switch = tegra_sdhci_voltage_switch,
 	.get_max_clock = tegra_sdhci_get_max_clock,
 };
@@ -458,6 +483,8 @@  static int sdhci_tegra_probe(struct platform_device *pdev)
 	struct sdhci_tegra *tegra_host;
 	struct clk *clk;
 	int rc;
+	struct device_node *np = pdev->dev.of_node;
+	u32 prop;
 
 	match = of_match_device(sdhci_tegra_dt_match, &pdev->dev);
 	if (!match)
@@ -472,8 +499,14 @@  static int sdhci_tegra_probe(struct platform_device *pdev)
 	tegra_host = sdhci_pltfm_priv(pltfm_host);
 	tegra_host->ddr_signaling = false;
 	tegra_host->pad_calib_required = false;
+	tegra_host->pad_control = false;
 	tegra_host->soc_data = soc_data;
 
+	if (!of_property_read_u32(np, "nvidia,pad", &prop)) {
+		tegra_host->pad_control = true;
+		tegra_host->pad_id = prop;
+	}
+
 	rc = mmc_of_parse(host->mmc);
 	if (rc)
 		goto err_parse_dt;