summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSahitya Tummala <stummala@codeaurora.org>2013-08-20 15:32:09 +0530
committerSubhash Jadavani <subhashj@codeaurora.org>2016-05-27 10:28:53 -0700
commitc2037aa944ca2f3decbefa620d4392652b51f286 (patch)
tree92fa1ffc37f5a64c66b106c4e42624fa5ee3f44c
parent2ba264341c60b4a5ab95ef75575a92b941cedc9d (diff)
mmc: sdhci-msm: Fix issue with 1.8v switch sequence in 3.10 kernel
The SD3.0 voltage switch sequence to 1.8v would involve stopping the SDCLK before changing the voltage level and with recent changes in 3.10 kernel, the peripheral clocks are also getting disabled instead of just stopping the clock to the card. This patch makes sure this doesn't happen by marking the flag card_clock_off in struct mmc_host before starting the voltage switch sequence and checking it in host controller driver. Change-Id: If62378ba1dd369e69524365a4421d57317c22ca2 Signed-off-by: Sahitya Tummala <stummala@codeaurora.org>
-rw-r--r--drivers/mmc/core/core.c5
-rw-r--r--drivers/mmc/host/sdhci-msm.c12
-rw-r--r--include/linux/mmc/host.h5
3 files changed, 20 insertions, 2 deletions
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 1a662cf93cb0..536cb3655d49 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -1707,6 +1707,7 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, u32 ocr)
* During a signal voltage level switch, the clock must be gated
* for 5 ms according to the SD spec
*/
+ host->card_clock_off = true;
clock = host->ios.clock;
host->ios.clock = 0;
mmc_set_ios(host);
@@ -1717,6 +1718,9 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, u32 ocr)
* sent CMD11, so a power cycle is required anyway
*/
err = -EAGAIN;
+ host->ios.clock = clock;
+ mmc_set_ios(host);
+ host->card_clock_off = false;
goto power_cycle;
}
@@ -1725,6 +1729,7 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, u32 ocr)
host->ios.clock = clock;
mmc_set_ios(host);
+ host->card_clock_off = false;
/* Wait for at least 1 ms according to spec */
mmc_delay(1);
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 7bdc85437854..3c5e546016b6 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -2347,10 +2347,18 @@ static int sdhci_msm_prepare_clocks(struct sdhci_host *host, bool enable)
mb();
} else if (!enable && atomic_read(&msm_host->clks_on)) {
- pr_debug("%s: request to disable clocks\n",
- mmc_hostname(host->mmc));
sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
mb();
+ /*
+ * During 1.8V signal switching the clock source must
+ * still be ON as it requires accessing SDHC
+ * registers (SDHCi host control2 register bit 3 must
+ * be written and polled after stopping the SDCLK).
+ */
+ if (host->mmc->card_clock_off)
+ return 0;
+ pr_debug("%s: request to disable clocks\n",
+ mmc_hostname(host->mmc));
if (!IS_ERR_OR_NULL(msm_host->sleep_clk))
clk_disable_unprepare(msm_host->sleep_clk);
if (!IS_ERR_OR_NULL(msm_host->ff_clk))
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 1939cd47b3aa..63a10df66b87 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -404,6 +404,11 @@ struct mmc_host {
} embedded_sdio_data;
#endif
+ /*
+ * Set to 1 to just stop the SDCLK to the card without
+ * actually disabling the clock from it's source.
+ */
+ bool card_clock_off;
unsigned long private[0] ____cacheline_aligned;
};