All of lore.kernel.org
 help / color / mirror / Atom feed
From: Kishon Vijay Abraham I <kishon@ti.com>
To: Ulf Hansson <ulf.hansson@linaro.org>,
	Rob Herring <robh+dt@kernel.org>,
	Tony Lindgren <tony@atomide.com>
Cc: <linux-doc@vger.kernel.org>, <linux-kernel@vger.kernel.org>,
	<linux-mmc@vger.kernel.org>, <devicetree@vger.kernel.org>,
	<linux-omap@vger.kernel.org>,
	<linux-arm-kernel@lists.infradead.org>,
	Jonathan Corbet <corbet@lwn.net>,
	Mark Rutland <mark.rutland@arm.com>,
	Russell King <linux@armlinux.org.uk>, <nsekhar@ti.com>,
	<kishon@ti.com>
Subject: [PATCH 04/41] mmc: host: omap_hsmmc: Add voltage switch support for UHS SD card
Date: Fri, 19 May 2017 13:45:04 +0530	[thread overview]
Message-ID: <20170519081541.26753-5-kishon@ti.com> (raw)
In-Reply-To: <20170519081541.26753-1-kishon@ti.com>

From: Balaji T K <balajitk@ti.com>

UHS SD card i/o data line operates at 1.8V when in UHS speed
mode.

Add support for signal voltage switch to support UHS cards.

Also, enable CIRQ before checking for CLEV/DLEV. MMC module can
sense when the clock lines and data lines are driven high by the
card, if MMC is active and CIRQ can be used to keep the MMC
module active. This is required for voltage switching to succeed
and the card to enumerate in UHS mode.

Signed-off-by: Balaji T K <balajitk@ti.com>
Signed-off-by: Sourav Poddar <sourav.poddar@ti.com>
[kishon@ti.com : cleanup the voltage switch sequence]
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
[nsekhar@ti.com: make card busy functions preempt safe]
Signed-off-by: Sekhar Nori <nsekhar@ti.com>
---
 drivers/mmc/host/omap_hsmmc.c | 165 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 165 insertions(+)

diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 893d1624a5a3..4dbf75ad2376 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -44,6 +44,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/pm_wakeirq.h>
 #include <linux/platform_data/hsmmc-omap.h>
+#include <linux/mmc/sd.h>
 
 /* OMAP HSMMC Host Controller Registers */
 #define OMAP_HSMMC_SYSSTATUS	0x0014
@@ -111,6 +112,9 @@
 /* PSTATE */
 #define DLEV_DAT(x)		(1 << (20 + (x)))
 
+/* AC12 */
+#define AC12_V1V8_SIGEN		(1 << 19)
+
 /* Interrupt masks for IE and ISE register */
 #define CC_EN			(1 << 0)
 #define TC_EN			(1 << 1)
@@ -150,6 +154,13 @@
 #define VDD_1V8			1800000		/* 180000 uV */
 #define VDD_3V0			3000000		/* 300000 uV */
 #define VDD_165_195		(ffs(MMC_VDD_165_195) - 1)
+#define VDD_30_31		(ffs(MMC_VDD_30_31) - 1)
+
+#define CON_CLKEXTFREE		(1 << 16)
+#define CON_PADEN		(1 << 15)
+#define PSTATE_CLEV		(1 << 24)
+#define PSTATE_DLEV		(0xF << 20)
+#define PSTATE_DLEV_DAT0	(0x1 << 20)
 
 /*
  * One controller can have multiple slots, like on some omap boards using
@@ -177,6 +188,7 @@ struct omap_hsmmc_host {
 	struct	mmc_host	*mmc;
 	struct	mmc_request	*mrq;
 	struct	mmc_command	*cmd;
+	u32			last_cmd;
 	struct	mmc_data	*data;
 	struct	clk		*fclk;
 	struct	clk		*dbclk;
@@ -209,6 +221,7 @@ struct omap_hsmmc_host {
 	unsigned int		flags;
 #define AUTO_CMD23		(1 << 0)        /* Auto CMD23 support */
 #define HSMMC_SDIO_IRQ_ENABLED	(1 << 1)        /* SDIO irq enabled */
+#define CLKEXTFREE_ENABLED	(1 << 2)        /* CLKEXTFREE enabled */
 	struct omap_hsmmc_next	next_data;
 	struct	omap_hsmmc_platform_data	*pdata;
 
@@ -604,6 +617,9 @@ static void omap_hsmmc_enable_irq(struct omap_hsmmc_host *host,
 	if (cmd->opcode == MMC_ERASE)
 		irq_mask &= ~DTO_EN;
 
+	if (host->flags & CLKEXTFREE_ENABLED)
+		irq_mask |= CIRQ_EN;
+
 	spin_lock_irqsave(&host->irq_lock, flags);
 	OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
 	OMAP_HSMMC_WRITE(host->base, ISE, irq_mask);
@@ -947,6 +963,7 @@ omap_hsmmc_start_command(struct omap_hsmmc_host *host, struct mmc_command *cmd,
 		cmdreg |= DMAE;
 
 	host->req_in_progress = 1;
+	host->last_cmd = cmd->opcode;
 
 	OMAP_HSMMC_WRITE(host->base, ARG, cmd->arg);
 	OMAP_HSMMC_WRITE(host->base, CMD, cmdreg);
@@ -1848,6 +1865,152 @@ static int omap_hsmmc_multi_io_quirk(struct mmc_card *card,
 	return blk_size;
 }
 
+static int omap_hsmmc_start_signal_voltage_switch(struct mmc_host *mmc,
+						  struct mmc_ios *ios)
+{
+	struct omap_hsmmc_host *host;
+	u32 val = 0;
+	int ret = 0;
+
+	host  = mmc_priv(mmc);
+
+	if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
+		val = OMAP_HSMMC_READ(host->base, CAPA);
+		if (!(val & VS30))
+			return -EOPNOTSUPP;
+
+		omap_hsmmc_conf_bus_power(host, ios->signal_voltage);
+
+		val = OMAP_HSMMC_READ(host->base, AC12);
+		val &= ~AC12_V1V8_SIGEN;
+		OMAP_HSMMC_WRITE(host->base, AC12, val);
+
+		ret = omap_hsmmc_set_power(host, 1, VDD_30_31);
+		if (ret) {
+			dev_err(mmc_dev(host->mmc), "failed to switch to 3v\n");
+			return ret;
+		}
+
+		dev_dbg(mmc_dev(host->mmc), " i/o voltage switch to 3V\n");
+	} else if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180) {
+		val = OMAP_HSMMC_READ(host->base, CAPA);
+		if (!(val & VS18))
+			return -EOPNOTSUPP;
+
+		omap_hsmmc_conf_bus_power(host, ios->signal_voltage);
+
+		val = OMAP_HSMMC_READ(host->base, AC12);
+		val |= AC12_V1V8_SIGEN;
+		OMAP_HSMMC_WRITE(host->base, AC12, val);
+
+		ret = omap_hsmmc_set_power(host, 1, VDD_165_195);
+		if (ret < 0) {
+			dev_err(mmc_dev(host->mmc), "failed to switch 1.8v\n");
+			return ret;
+		}
+	} else {
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
+static int omap_hsmmc_card_busy_low(struct omap_hsmmc_host *host)
+{
+	int i;
+	u32 val;
+
+	val = OMAP_HSMMC_READ(host->base, CON);
+	val &= ~CON_CLKEXTFREE;
+	val |= CON_PADEN;
+	OMAP_HSMMC_WRITE(host->base, CON, val);
+
+	/* By observation, card busy status reflects in 100 - 200us */
+	for (i = 0; i < 5; i++) {
+		val = OMAP_HSMMC_READ(host->base, PSTATE);
+		if (!(val & (PSTATE_CLEV | PSTATE_DLEV)))
+			return true;
+
+		usleep_range(100, 200);
+	}
+
+	dev_err(mmc_dev(host->mmc), "card busy\n");
+
+	return false;
+}
+
+static int omap_hsmmc_card_busy_high(struct omap_hsmmc_host *host)
+{
+	int i;
+	u32 val;
+	int ret = true;
+
+	val = OMAP_HSMMC_READ(host->base, CON);
+	val |= CLKEXTFREE;
+	OMAP_HSMMC_WRITE(host->base, CON, val);
+
+	host->flags |= CLKEXTFREE_ENABLED;
+	disable_irq(host->irq);
+	omap_hsmmc_enable_irq(host, NULL);
+
+	/* By observation, card busy status reflects in 100 - 200us */
+	for (i = 0; i < 5; i++) {
+		val = OMAP_HSMMC_READ(host->base, PSTATE);
+		if ((val & PSTATE_CLEV) && (val & PSTATE_DLEV)) {
+			val = OMAP_HSMMC_READ(host->base, CON);
+			val &= ~(CON_CLKEXTFREE | CON_PADEN);
+			OMAP_HSMMC_WRITE(host->base, CON, val);
+			ret = false;
+			goto disable_irq;
+		}
+
+		usleep_range(100, 200);
+	}
+
+	dev_err(mmc_dev(host->mmc), "card busy\n");
+
+disable_irq:
+	omap_hsmmc_disable_irq(host);
+	enable_irq(host->irq);
+	host->flags &= ~CLKEXTFREE_ENABLED;
+
+	return ret;
+}
+
+static int omap_hsmmc_card_busy(struct mmc_host *mmc)
+{
+	struct omap_hsmmc_host *host;
+	u32 val;
+	u32 reg;
+	int ret;
+
+	host  = mmc_priv(mmc);
+
+	if (host->last_cmd != SD_SWITCH_VOLTAGE) {
+		/*
+		 * PADEN should be set for DLEV to reflect the correct
+		 * state of data lines atleast for MMC1 on AM57x.
+		 */
+		reg = OMAP_HSMMC_READ(host->base, CON);
+		reg |= CON_PADEN;
+		OMAP_HSMMC_WRITE(host->base, CON, reg);
+		val = OMAP_HSMMC_READ(host->base, PSTATE);
+		reg &= ~CON_PADEN;
+		OMAP_HSMMC_WRITE(host->base, CON, reg);
+		if (val & PSTATE_DLEV_DAT0)
+			return false;
+		return true;
+	}
+
+	val = OMAP_HSMMC_READ(host->base, AC12);
+	if (val & AC12_V1V8_SIGEN)
+		ret = omap_hsmmc_card_busy_high(host);
+	else
+		ret = omap_hsmmc_card_busy_low(host);
+
+	return ret;
+}
+
 static struct mmc_host_ops omap_hsmmc_ops = {
 	.post_req = omap_hsmmc_post_req,
 	.pre_req = omap_hsmmc_pre_req,
@@ -1857,6 +2020,8 @@ static struct mmc_host_ops omap_hsmmc_ops = {
 	.get_ro = mmc_gpio_get_ro,
 	.init_card = omap_hsmmc_init_card,
 	.enable_sdio_irq = omap_hsmmc_enable_sdio_irq,
+	.start_signal_voltage_switch = omap_hsmmc_start_signal_voltage_switch,
+	.card_busy = omap_hsmmc_card_busy,
 };
 
 #ifdef CONFIG_DEBUG_FS
-- 
2.11.0

WARNING: multiple messages have this Message-ID (diff)
From: Kishon Vijay Abraham I <kishon@ti.com>
To: Ulf Hansson <ulf.hansson@linaro.org>,
	Rob Herring <robh+dt@kernel.org>,
	Tony Lindgren <tony@atomide.com>
Cc: linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-mmc@vger.kernel.org, devicetree@vger.kernel.org,
	linux-omap@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
	Jonathan Corbet <corbet@lwn.net>,
	Mark Rutland <mark.rutland@arm.com>,
	Russell King <linux@armlinux.org.uk>,
	nsekhar@ti.com, kishon@ti.com
Subject: [PATCH 04/41] mmc: host: omap_hsmmc: Add voltage switch support for UHS SD card
Date: Fri, 19 May 2017 13:45:04 +0530	[thread overview]
Message-ID: <20170519081541.26753-5-kishon@ti.com> (raw)
In-Reply-To: <20170519081541.26753-1-kishon@ti.com>

From: Balaji T K <balajitk@ti.com>

UHS SD card i/o data line operates at 1.8V when in UHS speed
mode.

Add support for signal voltage switch to support UHS cards.

Also, enable CIRQ before checking for CLEV/DLEV. MMC module can
sense when the clock lines and data lines are driven high by the
card, if MMC is active and CIRQ can be used to keep the MMC
module active. This is required for voltage switching to succeed
and the card to enumerate in UHS mode.

Signed-off-by: Balaji T K <balajitk@ti.com>
Signed-off-by: Sourav Poddar <sourav.poddar@ti.com>
[kishon@ti.com : cleanup the voltage switch sequence]
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
[nsekhar@ti.com: make card busy functions preempt safe]
Signed-off-by: Sekhar Nori <nsekhar@ti.com>
---
 drivers/mmc/host/omap_hsmmc.c | 165 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 165 insertions(+)

diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 893d1624a5a3..4dbf75ad2376 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -44,6 +44,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/pm_wakeirq.h>
 #include <linux/platform_data/hsmmc-omap.h>
+#include <linux/mmc/sd.h>
 
 /* OMAP HSMMC Host Controller Registers */
 #define OMAP_HSMMC_SYSSTATUS	0x0014
@@ -111,6 +112,9 @@
 /* PSTATE */
 #define DLEV_DAT(x)		(1 << (20 + (x)))
 
+/* AC12 */
+#define AC12_V1V8_SIGEN		(1 << 19)
+
 /* Interrupt masks for IE and ISE register */
 #define CC_EN			(1 << 0)
 #define TC_EN			(1 << 1)
@@ -150,6 +154,13 @@
 #define VDD_1V8			1800000		/* 180000 uV */
 #define VDD_3V0			3000000		/* 300000 uV */
 #define VDD_165_195		(ffs(MMC_VDD_165_195) - 1)
+#define VDD_30_31		(ffs(MMC_VDD_30_31) - 1)
+
+#define CON_CLKEXTFREE		(1 << 16)
+#define CON_PADEN		(1 << 15)
+#define PSTATE_CLEV		(1 << 24)
+#define PSTATE_DLEV		(0xF << 20)
+#define PSTATE_DLEV_DAT0	(0x1 << 20)
 
 /*
  * One controller can have multiple slots, like on some omap boards using
@@ -177,6 +188,7 @@ struct omap_hsmmc_host {
 	struct	mmc_host	*mmc;
 	struct	mmc_request	*mrq;
 	struct	mmc_command	*cmd;
+	u32			last_cmd;
 	struct	mmc_data	*data;
 	struct	clk		*fclk;
 	struct	clk		*dbclk;
@@ -209,6 +221,7 @@ struct omap_hsmmc_host {
 	unsigned int		flags;
 #define AUTO_CMD23		(1 << 0)        /* Auto CMD23 support */
 #define HSMMC_SDIO_IRQ_ENABLED	(1 << 1)        /* SDIO irq enabled */
+#define CLKEXTFREE_ENABLED	(1 << 2)        /* CLKEXTFREE enabled */
 	struct omap_hsmmc_next	next_data;
 	struct	omap_hsmmc_platform_data	*pdata;
 
@@ -604,6 +617,9 @@ static void omap_hsmmc_enable_irq(struct omap_hsmmc_host *host,
 	if (cmd->opcode == MMC_ERASE)
 		irq_mask &= ~DTO_EN;
 
+	if (host->flags & CLKEXTFREE_ENABLED)
+		irq_mask |= CIRQ_EN;
+
 	spin_lock_irqsave(&host->irq_lock, flags);
 	OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
 	OMAP_HSMMC_WRITE(host->base, ISE, irq_mask);
@@ -947,6 +963,7 @@ omap_hsmmc_start_command(struct omap_hsmmc_host *host, struct mmc_command *cmd,
 		cmdreg |= DMAE;
 
 	host->req_in_progress = 1;
+	host->last_cmd = cmd->opcode;
 
 	OMAP_HSMMC_WRITE(host->base, ARG, cmd->arg);
 	OMAP_HSMMC_WRITE(host->base, CMD, cmdreg);
@@ -1848,6 +1865,152 @@ static int omap_hsmmc_multi_io_quirk(struct mmc_card *card,
 	return blk_size;
 }
 
+static int omap_hsmmc_start_signal_voltage_switch(struct mmc_host *mmc,
+						  struct mmc_ios *ios)
+{
+	struct omap_hsmmc_host *host;
+	u32 val = 0;
+	int ret = 0;
+
+	host  = mmc_priv(mmc);
+
+	if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
+		val = OMAP_HSMMC_READ(host->base, CAPA);
+		if (!(val & VS30))
+			return -EOPNOTSUPP;
+
+		omap_hsmmc_conf_bus_power(host, ios->signal_voltage);
+
+		val = OMAP_HSMMC_READ(host->base, AC12);
+		val &= ~AC12_V1V8_SIGEN;
+		OMAP_HSMMC_WRITE(host->base, AC12, val);
+
+		ret = omap_hsmmc_set_power(host, 1, VDD_30_31);
+		if (ret) {
+			dev_err(mmc_dev(host->mmc), "failed to switch to 3v\n");
+			return ret;
+		}
+
+		dev_dbg(mmc_dev(host->mmc), " i/o voltage switch to 3V\n");
+	} else if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180) {
+		val = OMAP_HSMMC_READ(host->base, CAPA);
+		if (!(val & VS18))
+			return -EOPNOTSUPP;
+
+		omap_hsmmc_conf_bus_power(host, ios->signal_voltage);
+
+		val = OMAP_HSMMC_READ(host->base, AC12);
+		val |= AC12_V1V8_SIGEN;
+		OMAP_HSMMC_WRITE(host->base, AC12, val);
+
+		ret = omap_hsmmc_set_power(host, 1, VDD_165_195);
+		if (ret < 0) {
+			dev_err(mmc_dev(host->mmc), "failed to switch 1.8v\n");
+			return ret;
+		}
+	} else {
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
+static int omap_hsmmc_card_busy_low(struct omap_hsmmc_host *host)
+{
+	int i;
+	u32 val;
+
+	val = OMAP_HSMMC_READ(host->base, CON);
+	val &= ~CON_CLKEXTFREE;
+	val |= CON_PADEN;
+	OMAP_HSMMC_WRITE(host->base, CON, val);
+
+	/* By observation, card busy status reflects in 100 - 200us */
+	for (i = 0; i < 5; i++) {
+		val = OMAP_HSMMC_READ(host->base, PSTATE);
+		if (!(val & (PSTATE_CLEV | PSTATE_DLEV)))
+			return true;
+
+		usleep_range(100, 200);
+	}
+
+	dev_err(mmc_dev(host->mmc), "card busy\n");
+
+	return false;
+}
+
+static int omap_hsmmc_card_busy_high(struct omap_hsmmc_host *host)
+{
+	int i;
+	u32 val;
+	int ret = true;
+
+	val = OMAP_HSMMC_READ(host->base, CON);
+	val |= CLKEXTFREE;
+	OMAP_HSMMC_WRITE(host->base, CON, val);
+
+	host->flags |= CLKEXTFREE_ENABLED;
+	disable_irq(host->irq);
+	omap_hsmmc_enable_irq(host, NULL);
+
+	/* By observation, card busy status reflects in 100 - 200us */
+	for (i = 0; i < 5; i++) {
+		val = OMAP_HSMMC_READ(host->base, PSTATE);
+		if ((val & PSTATE_CLEV) && (val & PSTATE_DLEV)) {
+			val = OMAP_HSMMC_READ(host->base, CON);
+			val &= ~(CON_CLKEXTFREE | CON_PADEN);
+			OMAP_HSMMC_WRITE(host->base, CON, val);
+			ret = false;
+			goto disable_irq;
+		}
+
+		usleep_range(100, 200);
+	}
+
+	dev_err(mmc_dev(host->mmc), "card busy\n");
+
+disable_irq:
+	omap_hsmmc_disable_irq(host);
+	enable_irq(host->irq);
+	host->flags &= ~CLKEXTFREE_ENABLED;
+
+	return ret;
+}
+
+static int omap_hsmmc_card_busy(struct mmc_host *mmc)
+{
+	struct omap_hsmmc_host *host;
+	u32 val;
+	u32 reg;
+	int ret;
+
+	host  = mmc_priv(mmc);
+
+	if (host->last_cmd != SD_SWITCH_VOLTAGE) {
+		/*
+		 * PADEN should be set for DLEV to reflect the correct
+		 * state of data lines atleast for MMC1 on AM57x.
+		 */
+		reg = OMAP_HSMMC_READ(host->base, CON);
+		reg |= CON_PADEN;
+		OMAP_HSMMC_WRITE(host->base, CON, reg);
+		val = OMAP_HSMMC_READ(host->base, PSTATE);
+		reg &= ~CON_PADEN;
+		OMAP_HSMMC_WRITE(host->base, CON, reg);
+		if (val & PSTATE_DLEV_DAT0)
+			return false;
+		return true;
+	}
+
+	val = OMAP_HSMMC_READ(host->base, AC12);
+	if (val & AC12_V1V8_SIGEN)
+		ret = omap_hsmmc_card_busy_high(host);
+	else
+		ret = omap_hsmmc_card_busy_low(host);
+
+	return ret;
+}
+
 static struct mmc_host_ops omap_hsmmc_ops = {
 	.post_req = omap_hsmmc_post_req,
 	.pre_req = omap_hsmmc_pre_req,
@@ -1857,6 +2020,8 @@ static struct mmc_host_ops omap_hsmmc_ops = {
 	.get_ro = mmc_gpio_get_ro,
 	.init_card = omap_hsmmc_init_card,
 	.enable_sdio_irq = omap_hsmmc_enable_sdio_irq,
+	.start_signal_voltage_switch = omap_hsmmc_start_signal_voltage_switch,
+	.card_busy = omap_hsmmc_card_busy,
 };
 
 #ifdef CONFIG_DEBUG_FS
-- 
2.11.0

WARNING: multiple messages have this Message-ID (diff)
From: kishon@ti.com (Kishon Vijay Abraham I)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH 04/41] mmc: host: omap_hsmmc: Add voltage switch support for UHS SD card
Date: Fri, 19 May 2017 13:45:04 +0530	[thread overview]
Message-ID: <20170519081541.26753-5-kishon@ti.com> (raw)
In-Reply-To: <20170519081541.26753-1-kishon@ti.com>

From: Balaji T K <balajitk@ti.com>

UHS SD card i/o data line operates at 1.8V when in UHS speed
mode.

Add support for signal voltage switch to support UHS cards.

Also, enable CIRQ before checking for CLEV/DLEV. MMC module can
sense when the clock lines and data lines are driven high by the
card, if MMC is active and CIRQ can be used to keep the MMC
module active. This is required for voltage switching to succeed
and the card to enumerate in UHS mode.

Signed-off-by: Balaji T K <balajitk@ti.com>
Signed-off-by: Sourav Poddar <sourav.poddar@ti.com>
[kishon at ti.com : cleanup the voltage switch sequence]
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
[nsekhar at ti.com: make card busy functions preempt safe]
Signed-off-by: Sekhar Nori <nsekhar@ti.com>
---
 drivers/mmc/host/omap_hsmmc.c | 165 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 165 insertions(+)

diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 893d1624a5a3..4dbf75ad2376 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -44,6 +44,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/pm_wakeirq.h>
 #include <linux/platform_data/hsmmc-omap.h>
+#include <linux/mmc/sd.h>
 
 /* OMAP HSMMC Host Controller Registers */
 #define OMAP_HSMMC_SYSSTATUS	0x0014
@@ -111,6 +112,9 @@
 /* PSTATE */
 #define DLEV_DAT(x)		(1 << (20 + (x)))
 
+/* AC12 */
+#define AC12_V1V8_SIGEN		(1 << 19)
+
 /* Interrupt masks for IE and ISE register */
 #define CC_EN			(1 << 0)
 #define TC_EN			(1 << 1)
@@ -150,6 +154,13 @@
 #define VDD_1V8			1800000		/* 180000 uV */
 #define VDD_3V0			3000000		/* 300000 uV */
 #define VDD_165_195		(ffs(MMC_VDD_165_195) - 1)
+#define VDD_30_31		(ffs(MMC_VDD_30_31) - 1)
+
+#define CON_CLKEXTFREE		(1 << 16)
+#define CON_PADEN		(1 << 15)
+#define PSTATE_CLEV		(1 << 24)
+#define PSTATE_DLEV		(0xF << 20)
+#define PSTATE_DLEV_DAT0	(0x1 << 20)
 
 /*
  * One controller can have multiple slots, like on some omap boards using
@@ -177,6 +188,7 @@ struct omap_hsmmc_host {
 	struct	mmc_host	*mmc;
 	struct	mmc_request	*mrq;
 	struct	mmc_command	*cmd;
+	u32			last_cmd;
 	struct	mmc_data	*data;
 	struct	clk		*fclk;
 	struct	clk		*dbclk;
@@ -209,6 +221,7 @@ struct omap_hsmmc_host {
 	unsigned int		flags;
 #define AUTO_CMD23		(1 << 0)        /* Auto CMD23 support */
 #define HSMMC_SDIO_IRQ_ENABLED	(1 << 1)        /* SDIO irq enabled */
+#define CLKEXTFREE_ENABLED	(1 << 2)        /* CLKEXTFREE enabled */
 	struct omap_hsmmc_next	next_data;
 	struct	omap_hsmmc_platform_data	*pdata;
 
@@ -604,6 +617,9 @@ static void omap_hsmmc_enable_irq(struct omap_hsmmc_host *host,
 	if (cmd->opcode == MMC_ERASE)
 		irq_mask &= ~DTO_EN;
 
+	if (host->flags & CLKEXTFREE_ENABLED)
+		irq_mask |= CIRQ_EN;
+
 	spin_lock_irqsave(&host->irq_lock, flags);
 	OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
 	OMAP_HSMMC_WRITE(host->base, ISE, irq_mask);
@@ -947,6 +963,7 @@ omap_hsmmc_start_command(struct omap_hsmmc_host *host, struct mmc_command *cmd,
 		cmdreg |= DMAE;
 
 	host->req_in_progress = 1;
+	host->last_cmd = cmd->opcode;
 
 	OMAP_HSMMC_WRITE(host->base, ARG, cmd->arg);
 	OMAP_HSMMC_WRITE(host->base, CMD, cmdreg);
@@ -1848,6 +1865,152 @@ static int omap_hsmmc_multi_io_quirk(struct mmc_card *card,
 	return blk_size;
 }
 
+static int omap_hsmmc_start_signal_voltage_switch(struct mmc_host *mmc,
+						  struct mmc_ios *ios)
+{
+	struct omap_hsmmc_host *host;
+	u32 val = 0;
+	int ret = 0;
+
+	host  = mmc_priv(mmc);
+
+	if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
+		val = OMAP_HSMMC_READ(host->base, CAPA);
+		if (!(val & VS30))
+			return -EOPNOTSUPP;
+
+		omap_hsmmc_conf_bus_power(host, ios->signal_voltage);
+
+		val = OMAP_HSMMC_READ(host->base, AC12);
+		val &= ~AC12_V1V8_SIGEN;
+		OMAP_HSMMC_WRITE(host->base, AC12, val);
+
+		ret = omap_hsmmc_set_power(host, 1, VDD_30_31);
+		if (ret) {
+			dev_err(mmc_dev(host->mmc), "failed to switch to 3v\n");
+			return ret;
+		}
+
+		dev_dbg(mmc_dev(host->mmc), " i/o voltage switch to 3V\n");
+	} else if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180) {
+		val = OMAP_HSMMC_READ(host->base, CAPA);
+		if (!(val & VS18))
+			return -EOPNOTSUPP;
+
+		omap_hsmmc_conf_bus_power(host, ios->signal_voltage);
+
+		val = OMAP_HSMMC_READ(host->base, AC12);
+		val |= AC12_V1V8_SIGEN;
+		OMAP_HSMMC_WRITE(host->base, AC12, val);
+
+		ret = omap_hsmmc_set_power(host, 1, VDD_165_195);
+		if (ret < 0) {
+			dev_err(mmc_dev(host->mmc), "failed to switch 1.8v\n");
+			return ret;
+		}
+	} else {
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
+static int omap_hsmmc_card_busy_low(struct omap_hsmmc_host *host)
+{
+	int i;
+	u32 val;
+
+	val = OMAP_HSMMC_READ(host->base, CON);
+	val &= ~CON_CLKEXTFREE;
+	val |= CON_PADEN;
+	OMAP_HSMMC_WRITE(host->base, CON, val);
+
+	/* By observation, card busy status reflects in 100 - 200us */
+	for (i = 0; i < 5; i++) {
+		val = OMAP_HSMMC_READ(host->base, PSTATE);
+		if (!(val & (PSTATE_CLEV | PSTATE_DLEV)))
+			return true;
+
+		usleep_range(100, 200);
+	}
+
+	dev_err(mmc_dev(host->mmc), "card busy\n");
+
+	return false;
+}
+
+static int omap_hsmmc_card_busy_high(struct omap_hsmmc_host *host)
+{
+	int i;
+	u32 val;
+	int ret = true;
+
+	val = OMAP_HSMMC_READ(host->base, CON);
+	val |= CLKEXTFREE;
+	OMAP_HSMMC_WRITE(host->base, CON, val);
+
+	host->flags |= CLKEXTFREE_ENABLED;
+	disable_irq(host->irq);
+	omap_hsmmc_enable_irq(host, NULL);
+
+	/* By observation, card busy status reflects in 100 - 200us */
+	for (i = 0; i < 5; i++) {
+		val = OMAP_HSMMC_READ(host->base, PSTATE);
+		if ((val & PSTATE_CLEV) && (val & PSTATE_DLEV)) {
+			val = OMAP_HSMMC_READ(host->base, CON);
+			val &= ~(CON_CLKEXTFREE | CON_PADEN);
+			OMAP_HSMMC_WRITE(host->base, CON, val);
+			ret = false;
+			goto disable_irq;
+		}
+
+		usleep_range(100, 200);
+	}
+
+	dev_err(mmc_dev(host->mmc), "card busy\n");
+
+disable_irq:
+	omap_hsmmc_disable_irq(host);
+	enable_irq(host->irq);
+	host->flags &= ~CLKEXTFREE_ENABLED;
+
+	return ret;
+}
+
+static int omap_hsmmc_card_busy(struct mmc_host *mmc)
+{
+	struct omap_hsmmc_host *host;
+	u32 val;
+	u32 reg;
+	int ret;
+
+	host  = mmc_priv(mmc);
+
+	if (host->last_cmd != SD_SWITCH_VOLTAGE) {
+		/*
+		 * PADEN should be set for DLEV to reflect the correct
+		 * state of data lines atleast for MMC1 on AM57x.
+		 */
+		reg = OMAP_HSMMC_READ(host->base, CON);
+		reg |= CON_PADEN;
+		OMAP_HSMMC_WRITE(host->base, CON, reg);
+		val = OMAP_HSMMC_READ(host->base, PSTATE);
+		reg &= ~CON_PADEN;
+		OMAP_HSMMC_WRITE(host->base, CON, reg);
+		if (val & PSTATE_DLEV_DAT0)
+			return false;
+		return true;
+	}
+
+	val = OMAP_HSMMC_READ(host->base, AC12);
+	if (val & AC12_V1V8_SIGEN)
+		ret = omap_hsmmc_card_busy_high(host);
+	else
+		ret = omap_hsmmc_card_busy_low(host);
+
+	return ret;
+}
+
 static struct mmc_host_ops omap_hsmmc_ops = {
 	.post_req = omap_hsmmc_post_req,
 	.pre_req = omap_hsmmc_pre_req,
@@ -1857,6 +2020,8 @@ static struct mmc_host_ops omap_hsmmc_ops = {
 	.get_ro = mmc_gpio_get_ro,
 	.init_card = omap_hsmmc_init_card,
 	.enable_sdio_irq = omap_hsmmc_enable_sdio_irq,
+	.start_signal_voltage_switch = omap_hsmmc_start_signal_voltage_switch,
+	.card_busy = omap_hsmmc_card_busy,
 };
 
 #ifdef CONFIG_DEBUG_FS
-- 
2.11.0

  parent reply	other threads:[~2017-05-19  8:16 UTC|newest]

Thread overview: 137+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-05-19  8:15 [PATCH 00/41] omap_hsmmc: Add ADMA support and UHS/HS200/DDR support Kishon Vijay Abraham I
2017-05-19  8:15 ` Kishon Vijay Abraham I
2017-05-19  8:15 ` Kishon Vijay Abraham I
2017-05-19  8:15 ` [PATCH 01/41] mmc: host: omap_hsmmc: Support pbias and vmmc_aux to switch to 1.8v Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15 ` [PATCH 02/41] mmc: host: omap_hsmmc: Separate setting voltage capabilities from bus power Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15 ` [PATCH 03/41] mmc: host: omap_hsmmc: Program HCTL based on signal_voltage set by mmc core Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15 ` Kishon Vijay Abraham I [this message]
2017-05-19  8:15   ` [PATCH 04/41] mmc: host: omap_hsmmc: Add voltage switch support for UHS SD card Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15 ` [PATCH 05/41] mmc: host: omap_hsmmc: Set clk rate to the max frequency Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15 ` [PATCH 06/41] mmc: host: omap_hsmmc: Add tuning support Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15 ` [PATCH 07/41] mmc: host: omap_hsmmc: Allow io voltage switch even for fixed vdd Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15 ` [PATCH 08/41] mmc: host: omap_hsmmc: Remove incorrect voltage switch sequence Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15 ` [PATCH 09/41] mmc: host: omap_hsmmc: Add software timer when timeout greater than hardware capablility Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15 ` [PATCH 10/41] mmc: host: omap_hsmmc: Prepare *set_timing() to be used for iodelay setting Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15 ` [PATCH 11/41] mmc: host: omap_hsmmc: Add new compatible string to support dra7 Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-23 14:44   ` Rob Herring
2017-05-23 14:44     ` Rob Herring
2017-05-23 14:44     ` Rob Herring
2017-05-19  8:15 ` [PATCH 12/41] mmc: host: omap_hsmmc: Fix error path sequence Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15 ` [PATCH 13/41] mmc: host: omap_hsmmc: Add support to set IODELAY values Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-23 14:55   ` Rob Herring
2017-05-23 14:55     ` Rob Herring
2017-05-19  8:15 ` [PATCH 14/41] mmc: host: omap_hsmmc: Remove *use_dma* member Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15 ` [PATCH 15/41] mmc: host: omap_hsmmc: Enable ADMA2 Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15 ` [PATCH 16/41] mmc: omap_hsmmc: Support non-1.8V IO controllers Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15 ` [PATCH 17/41] ARM: dts: dra72-evm: Add vmmc_aux supply to mmc1 Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15 ` [PATCH 18/41] ARM: dts: dra72-evm-revc: " Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15 ` [PATCH 19/41] ARM: dts: am57xx-beagle-x15-revb1: Fix supply name used for MMC1 IO lines Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15 ` [PATCH 20/41] ARM: dts: dra7-evm: Correct the vmmc-supply for mmc2 Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15 ` [PATCH 21/41] ARM: dts: dra72-evm-common: Correct " Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15 ` [PATCH 22/41] ARM: dts: Add dra7 iodelay configuration Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15 ` [PATCH 23/41] ARM: dts: dra72x: Create a common file with MMC/SD IOdelay data Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15 ` [PATCH 24/41] ARM: dts: dra74x: " Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15 ` [PATCH 25/41] ARM: dts: dra7-evm: Add pinmux configuration for MMC Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15 ` [PATCH 26/41] ARM: dts: am57xx-beagle-x15: " Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15 ` [PATCH 27/41] ARM: dts: am57xx-idk: Move common MMC/SD properties to common file Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15 ` [PATCH 28/41] ARM: dts: am571x-idk: Add pinmux configuration for MMC Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15 ` [PATCH 29/41] ARM: dts: am572x-idk: " Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15 ` [PATCH 30/41] ARM: dts: dra72-evm: " Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15 ` [PATCH 31/41] ARM: dts: dra72-evm-revc: " Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15 ` [PATCH 32/41] ARM: dts: dra71-evm: " Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15 ` [PATCH 33/41] ARM: dts: dra7: Add "max-frequency" property to MMC dt nodes Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15 ` [PATCH 34/41] ARM: dts: dra7: Use new dra7-specific compatible string Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15 ` [PATCH 35/41] ARM: dts: dra7: Add supported MMC/SD modes in MMC dt nodes Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15 ` [PATCH 36/41] ARM: dts: am57xx-idk: Set MMC2 IO voltage to 3.3V Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15 ` [PATCH 37/41] ARM: dts: am57xx-beagle-x15-common: " Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15 ` [PATCH 38/41] ARM: OMAP2+: Add pdata-quirks for MMC/SD on DRA74x EVM Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15 ` [PATCH 39/41] ARM: omap2plus_defconfig: Enable PINCTRL_TI_IODELAY Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15 ` [PATCH 40/41] ARM: multi_v7_defconfig: " Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15 ` [PATCH 41/41] Documentation: ARM: Document new dependencies for MMC on DRA7 Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19  8:15   ` Kishon Vijay Abraham I
2017-05-19 22:13 ` [PATCH 00/41] omap_hsmmc: Add ADMA support and UHS/HS200/DDR support Tony Lindgren
2017-05-19 22:13   ` Tony Lindgren
2017-05-19 22:13   ` Tony Lindgren
2017-05-22 12:20   ` Kishon Vijay Abraham I
2017-05-22 12:20     ` Kishon Vijay Abraham I
2017-05-22 12:20     ` Kishon Vijay Abraham I

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20170519081541.26753-5-kishon@ti.com \
    --to=kishon@ti.com \
    --cc=corbet@lwn.net \
    --cc=devicetree@vger.kernel.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mmc@vger.kernel.org \
    --cc=linux-omap@vger.kernel.org \
    --cc=linux@armlinux.org.uk \
    --cc=mark.rutland@arm.com \
    --cc=nsekhar@ti.com \
    --cc=robh+dt@kernel.org \
    --cc=tony@atomide.com \
    --cc=ulf.hansson@linaro.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.