[v5,2/5] mmc: sdhci-of-esdhc: add support for signal voltage switch
diff mbox

Message ID 1492676084-28218-3-git-send-email-yangbo.lu@nxp.com
State Accepted, archived
Headers show

Commit Message

Yangbo Lu April 20, 2017, 8:14 a.m. UTC
eSDHC supports signal voltage switch from 3.3v to 1.8v by
eSDHC_PROCTL[VOLT_SEL] bit. This bit changes the value of output
signal SDHC_VS, and there must be a control circuit out of eSDHC
to change the signal voltage according to SDHC_VS output signal.

Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
Acked-by: Adrian Hunter <adrian.hunter@intel.com>
---
Changes for v2:
	- Used Adrain's method to support voltage switching:
          host->mmc_host_ops.start_signal_voltage_switch =
                     esdhc_signal_voltage_switch;
Changes for v3:
	- Put .start_signal_voltage_switch assigning after IS_ERR(host) check.
Changes for v4:
	- None
Changes for v5:
	- Added Adrian's ACK
---
 drivers/mmc/host/sdhci-esdhc.h    |  1 +
 drivers/mmc/host/sdhci-of-esdhc.c | 74 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 75 insertions(+)

Comments

Ulf Hansson April 20, 2017, 2:06 p.m. UTC | #1
[...]

> +       switch (ios->signal_voltage) {
> +       case MMC_SIGNAL_VOLTAGE_330:
> +               val &= ~ESDHC_VOLT_SEL;
> +               sdhci_writel(host, val, ESDHC_PROCTL);
> +               return 0;
> +       case MMC_SIGNAL_VOLTAGE_180:
> +               scfg_node = of_find_matching_node(NULL, scfg_device_ids);
> +               if (scfg_node)
> +                       scfg_base = of_iomap(scfg_node, 0);

Why don't you do this at probe time instead of every time you do the
voltage switch?

Never mind at this point, I have queued this up for 4.12, however feel
free to send a new patch on top.

> +               if (scfg_base) {
> +                       sdhciovselcr = SDHCIOVSELCR_TGLEN |
> +                                      SDHCIOVSELCR_VSELVAL;
> +                       iowrite32be(sdhciovselcr,
> +                               scfg_base + SCFG_SDHCIOVSELCR);
> +
> +                       val |= ESDHC_VOLT_SEL;
> +                       sdhci_writel(host, val, ESDHC_PROCTL);
> +                       mdelay(5);
> +
> +                       sdhciovselcr = SDHCIOVSELCR_TGLEN |
> +                                      SDHCIOVSELCR_SDHC_VS;
> +                       iowrite32be(sdhciovselcr,
> +                               scfg_base + SCFG_SDHCIOVSELCR);
> +                       iounmap(scfg_base);
> +               } else {
> +                       val |= ESDHC_VOLT_SEL;
> +                       sdhci_writel(host, val, ESDHC_PROCTL);
> +               }
> +               return 0;
> +       default:
> +               return 0;
> +       }
> +}

[...]

Kind regards
Uffe
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Yangbo Lu April 26, 2017, 3:04 a.m. UTC | #2
SGkgVWZmZSwNCg0KDQo+IC0tLS0tT3JpZ2luYWwgTWVzc2FnZS0tLS0tDQo+IEZyb206IFVsZiBI
YW5zc29uIFttYWlsdG86dWxmLmhhbnNzb25AbGluYXJvLm9yZ10NCj4gU2VudDogVGh1cnNkYXks
IEFwcmlsIDIwLCAyMDE3IDEwOjA2IFBNDQo+IFRvOiBZLkIuIEx1DQo+IENjOiBsaW51eC1tbWNA
dmdlci5rZXJuZWwub3JnOyBBZHJpYW4gSHVudGVyOyBYaWFvYm8gWGllDQo+IFN1YmplY3Q6IFJl
OiBbdjUsIDIvNV0gbW1jOiBzZGhjaS1vZi1lc2RoYzogYWRkIHN1cHBvcnQgZm9yIHNpZ25hbA0K
PiB2b2x0YWdlIHN3aXRjaA0KPiANCj4gWy4uLl0NCj4gDQo+ID4gKyAgICAgICBzd2l0Y2ggKGlv
cy0+c2lnbmFsX3ZvbHRhZ2UpIHsNCj4gPiArICAgICAgIGNhc2UgTU1DX1NJR05BTF9WT0xUQUdF
XzMzMDoNCj4gPiArICAgICAgICAgICAgICAgdmFsICY9IH5FU0RIQ19WT0xUX1NFTDsNCj4gPiAr
ICAgICAgICAgICAgICAgc2RoY2lfd3JpdGVsKGhvc3QsIHZhbCwgRVNESENfUFJPQ1RMKTsNCj4g
PiArICAgICAgICAgICAgICAgcmV0dXJuIDA7DQo+ID4gKyAgICAgICBjYXNlIE1NQ19TSUdOQUxf
Vk9MVEFHRV8xODA6DQo+ID4gKyAgICAgICAgICAgICAgIHNjZmdfbm9kZSA9IG9mX2ZpbmRfbWF0
Y2hpbmdfbm9kZShOVUxMLA0KPiBzY2ZnX2RldmljZV9pZHMpOw0KPiA+ICsgICAgICAgICAgICAg
ICBpZiAoc2NmZ19ub2RlKQ0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHNjZmdfYmFzZSA9
IG9mX2lvbWFwKHNjZmdfbm9kZSwgMCk7DQo+IA0KPiBXaHkgZG9uJ3QgeW91IGRvIHRoaXMgYXQg
cHJvYmUgdGltZSBpbnN0ZWFkIG9mIGV2ZXJ5IHRpbWUgeW91IGRvIHRoZQ0KPiB2b2x0YWdlIHN3
aXRjaD8NCj4gDQo+IE5ldmVyIG1pbmQgYXQgdGhpcyBwb2ludCwgSSBoYXZlIHF1ZXVlZCB0aGlz
IHVwIGZvciA0LjEyLCBob3dldmVyIGZlZWwNCj4gZnJlZSB0byBzZW5kIGEgbmV3IHBhdGNoIG9u
IHRvcC4NCg0KW0x1IFlhbmdiby1CNDcwOTNdIFRoYW5rIHlvdSB2ZXJ5IG11Y2ggZm9yIHBvaW50
IG91dCB0aGlzLg0KSSB3aWxsIHdvcmsgb24gYW5vdGhlciBwYXRjaCB0byBmaXggdGhpcyA6KQ0K
DQotIFlhbmdibyBMdQ0KDQo+IA0KPiA+ICsgICAgICAgICAgICAgICBpZiAoc2NmZ19iYXNlKSB7
DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgc2RoY2lvdnNlbGNyID0gU0RIQ0lPVlNFTENS
X1RHTEVOIHwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBTREhD
SU9WU0VMQ1JfVlNFTFZBTDsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBpb3dyaXRlMzJi
ZShzZGhjaW92c2VsY3IsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzY2Zn
X2Jhc2UgKyBTQ0ZHX1NESENJT1ZTRUxDUik7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICAg
ICAgICAgIHZhbCB8PSBFU0RIQ19WT0xUX1NFTDsNCj4gPiArICAgICAgICAgICAgICAgICAgICAg
ICBzZGhjaV93cml0ZWwoaG9zdCwgdmFsLCBFU0RIQ19QUk9DVEwpOw0KPiA+ICsgICAgICAgICAg
ICAgICAgICAgICAgIG1kZWxheSg1KTsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgICAgICAg
ICAgc2RoY2lvdnNlbGNyID0gU0RIQ0lPVlNFTENSX1RHTEVOIHwNCj4gPiArICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICBTREhDSU9WU0VMQ1JfU0RIQ19WUzsNCj4gPiArICAg
ICAgICAgICAgICAgICAgICAgICBpb3dyaXRlMzJiZShzZGhjaW92c2VsY3IsDQo+ID4gKyAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICBzY2ZnX2Jhc2UgKyBTQ0ZHX1NESENJT1ZTRUxDUik7
DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgaW91bm1hcChzY2ZnX2Jhc2UpOw0KPiA+ICsg
ICAgICAgICAgICAgICB9IGVsc2Ugew0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHZhbCB8
PSBFU0RIQ19WT0xUX1NFTDsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBzZGhjaV93cml0
ZWwoaG9zdCwgdmFsLCBFU0RIQ19QUk9DVEwpOw0KPiA+ICsgICAgICAgICAgICAgICB9DQo+ID4g
KyAgICAgICAgICAgICAgIHJldHVybiAwOw0KPiA+ICsgICAgICAgZGVmYXVsdDoNCj4gPiArICAg
ICAgICAgICAgICAgcmV0dXJuIDA7DQo+ID4gKyAgICAgICB9DQo+ID4gK30NCj4gDQo+IFsuLi5d
DQo+IA0KPiBLaW5kIHJlZ2FyZHMNCj4gVWZmZQ0K
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Patch
diff mbox

diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h
index 5343fc0..6869567 100644
--- a/drivers/mmc/host/sdhci-esdhc.h
+++ b/drivers/mmc/host/sdhci-esdhc.h
@@ -37,6 +37,7 @@ 
 
 /* Protocol Control Register */
 #define ESDHC_PROCTL			0x28
+#define ESDHC_VOLT_SEL			0x00000400
 #define ESDHC_CTRL_4BITBUS		(0x1 << 1)
 #define ESDHC_CTRL_8BITBUS		(0x2 << 1)
 #define ESDHC_CTRL_BUSWIDTH_MASK	(0x3 << 1)
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index 0b3f05a..f2d7002 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -16,6 +16,7 @@ 
 #include <linux/err.h>
 #include <linux/io.h>
 #include <linux/of.h>
+#include <linux/of_address.h>
 #include <linux/delay.h>
 #include <linux/module.h>
 #include <linux/sys_soc.h>
@@ -560,6 +561,76 @@  static void esdhc_reset(struct sdhci_host *host, u8 mask)
 	sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
 }
 
+/* The SCFG, Supplemental Configuration Unit, provides SoC specific
+ * configuration and status registers for the device. There is a
+ * SDHC IO VSEL control register on SCFG for some platforms. It's
+ * used to support SDHC IO voltage switching.
+ */
+static const struct of_device_id scfg_device_ids[] = {
+	{ .compatible = "fsl,t1040-scfg", },
+	{ .compatible = "fsl,ls1012a-scfg", },
+	{ .compatible = "fsl,ls1046a-scfg", },
+	{}
+};
+
+/* SDHC IO VSEL control register definition */
+#define SCFG_SDHCIOVSELCR	0x408
+#define SDHCIOVSELCR_TGLEN	0x80000000
+#define SDHCIOVSELCR_VSELVAL	0x60000000
+#define SDHCIOVSELCR_SDHC_VS	0x00000001
+
+static int esdhc_signal_voltage_switch(struct mmc_host *mmc,
+				       struct mmc_ios *ios)
+{
+	struct sdhci_host *host = mmc_priv(mmc);
+	struct device_node *scfg_node;
+	void __iomem *scfg_base = NULL;
+	u32 sdhciovselcr;
+	u32 val;
+
+	/*
+	 * Signal Voltage Switching is only applicable for Host Controllers
+	 * v3.00 and above.
+	 */
+	if (host->version < SDHCI_SPEC_300)
+		return 0;
+
+	val = sdhci_readl(host, ESDHC_PROCTL);
+
+	switch (ios->signal_voltage) {
+	case MMC_SIGNAL_VOLTAGE_330:
+		val &= ~ESDHC_VOLT_SEL;
+		sdhci_writel(host, val, ESDHC_PROCTL);
+		return 0;
+	case MMC_SIGNAL_VOLTAGE_180:
+		scfg_node = of_find_matching_node(NULL, scfg_device_ids);
+		if (scfg_node)
+			scfg_base = of_iomap(scfg_node, 0);
+		if (scfg_base) {
+			sdhciovselcr = SDHCIOVSELCR_TGLEN |
+				       SDHCIOVSELCR_VSELVAL;
+			iowrite32be(sdhciovselcr,
+				scfg_base + SCFG_SDHCIOVSELCR);
+
+			val |= ESDHC_VOLT_SEL;
+			sdhci_writel(host, val, ESDHC_PROCTL);
+			mdelay(5);
+
+			sdhciovselcr = SDHCIOVSELCR_TGLEN |
+				       SDHCIOVSELCR_SDHC_VS;
+			iowrite32be(sdhciovselcr,
+				scfg_base + SCFG_SDHCIOVSELCR);
+			iounmap(scfg_base);
+		} else {
+			val |= ESDHC_VOLT_SEL;
+			sdhci_writel(host, val, ESDHC_PROCTL);
+		}
+		return 0;
+	default:
+		return 0;
+	}
+}
+
 #ifdef CONFIG_PM_SLEEP
 static u32 esdhc_proctl;
 static int esdhc_of_suspend(struct device *dev)
@@ -717,6 +788,9 @@  static int sdhci_esdhc_probe(struct platform_device *pdev)
 	if (IS_ERR(host))
 		return PTR_ERR(host);
 
+	host->mmc_host_ops.start_signal_voltage_switch =
+		esdhc_signal_voltage_switch;
+
 	esdhc_init(pdev, host);
 
 	sdhci_get_of_property(pdev);