[PATCH 04/16] mmc: host: omap_hsmmc: Add voltage switch support for UHS SD card

2017-06-16 Thread Kishon Vijay Abraham I
UHS SD card IO data line operates at 1.8V when in UHS speed
mode.

Add voltage switch support in order to enumerate 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 
Signed-off-by: Sourav Poddar 
[kis...@ti.com : cleanup the voltage switch sequence]
Signed-off-by: Kishon Vijay Abraham I 
[nsek...@ti.com: make card busy functions preempt safe]
Signed-off-by: Sekhar Nori 
---
 drivers/mmc/host/omap_hsmmc.c | 179 +++---
 1 file changed, 170 insertions(+), 9 deletions(-)

diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 65330d2263ad..680934d50919 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -44,6 +44,7 @@
 #include 
 #include 
 #include 
+#include 
 
 /* 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_1V8180 /* 18 uV */
 #define VDD_3V0300 /* 30 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 intflags;
 #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;
 
@@ -593,6 +606,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(>irq_lock, flags);
OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
OMAP_HSMMC_WRITE(host->base, ISE, irq_mask);
@@ -936,6 +952,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);
@@ -1735,17 +1752,12 @@ static void omap_hsmmc_set_capabilities(struct 
omap_hsmmc_host *host)
OMAP_HSMMC_WRITE(host->base, CAPA, val);
 }
 
-static void omap_hsmmc_conf_bus_power(struct omap_hsmmc_host *host)
+static void omap_hsmmc_conf_bus_power(struct omap_hsmmc_host *host, int iov)
 {
u32 hctl, value;
 
-   /* Only MMC1 supports 3.0V */
-   if (host->pdata->controller_flags & OMAP_HSMMC_SUPPORTS_DUAL_VOLT)
-   hctl = SDVS30;
-   else
-   hctl = SDVS18;
-
value = OMAP_HSMMC_READ(host->base, HCTL) & ~SDVS_MASK;
+   hctl = (iov == MMC_SIGNAL_VOLTAGE_180) ? SDVS18 : SDVS30;
OMAP_HSMMC_WRITE(host->base, HCTL, value | hctl);
 
/* Set SD bus power bit */
@@ -1762,6 +1774,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;
+   

[PATCH 04/16] mmc: host: omap_hsmmc: Add voltage switch support for UHS SD card

2017-06-16 Thread Kishon Vijay Abraham I
UHS SD card IO data line operates at 1.8V when in UHS speed
mode.

Add voltage switch support in order to enumerate 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 
Signed-off-by: Sourav Poddar 
[kis...@ti.com : cleanup the voltage switch sequence]
Signed-off-by: Kishon Vijay Abraham I 
[nsek...@ti.com: make card busy functions preempt safe]
Signed-off-by: Sekhar Nori 
---
 drivers/mmc/host/omap_hsmmc.c | 179 +++---
 1 file changed, 170 insertions(+), 9 deletions(-)

diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 65330d2263ad..680934d50919 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -44,6 +44,7 @@
 #include 
 #include 
 #include 
+#include 
 
 /* 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_1V8180 /* 18 uV */
 #define VDD_3V0300 /* 30 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 intflags;
 #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;
 
@@ -593,6 +606,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(>irq_lock, flags);
OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
OMAP_HSMMC_WRITE(host->base, ISE, irq_mask);
@@ -936,6 +952,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);
@@ -1735,17 +1752,12 @@ static void omap_hsmmc_set_capabilities(struct 
omap_hsmmc_host *host)
OMAP_HSMMC_WRITE(host->base, CAPA, val);
 }
 
-static void omap_hsmmc_conf_bus_power(struct omap_hsmmc_host *host)
+static void omap_hsmmc_conf_bus_power(struct omap_hsmmc_host *host, int iov)
 {
u32 hctl, value;
 
-   /* Only MMC1 supports 3.0V */
-   if (host->pdata->controller_flags & OMAP_HSMMC_SUPPORTS_DUAL_VOLT)
-   hctl = SDVS30;
-   else
-   hctl = SDVS18;
-
value = OMAP_HSMMC_READ(host->base, HCTL) & ~SDVS_MASK;
+   hctl = (iov == MMC_SIGNAL_VOLTAGE_180) ? SDVS18 : SDVS30;
OMAP_HSMMC_WRITE(host->base, HCTL, value | hctl);
 
/* Set SD bus power bit */
@@ -1762,6 +1774,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 =