aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/host
diff options
context:
space:
mode:
authorDong Aisheng <b29396@freescale.com>2013-09-06 08:53:19 -0400
committerNitin Garg <nitin.garg@freescale.com>2014-04-16 09:05:36 -0400
commit093ee1a18164934cb8c0d37fbdf5e2e59df63670 (patch)
treeedbf1eb155b7f74249bcd6413f014e77dd412c21 /drivers/mmc/host
parentd513206f9d554202fa424327e4db87ac829c264d (diff)
ENGR00278646-4 sdhci: sdhci-esdhc-imx: support real clock on and off for imx6q
The signal voltage switch follow requires to shutdown and output clock in a specific sequence according to standard host controller v3.0 spec. In that timing, the card must really receive clock or not. However, for i.MX6Q, the uSDHC will not output clock even the clock is enabled until there is command or data in transfer on the bus, which will then cause singal voltage switch always to fail. For i.MX6Q, we clear ESDHC_VENDOR_SPEC_FRC_SDCLK_ON bit to let controller to gate off clock automatically and set that bit to force clock output if clock is on. This is required by SD3.0 support. Signed-off-by: Dong Aisheng <b29396@freescale.com>
Diffstat (limited to 'drivers/mmc/host')
-rw-r--r--drivers/mmc/host/sdhci-esdhc-imx.c20
1 files changed, 18 insertions, 2 deletions
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 72698a46a074..a5e5a26e6baa 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -34,6 +34,7 @@
34/* VENDOR SPEC register */ 34/* VENDOR SPEC register */
35#define ESDHC_VENDOR_SPEC 0xc0 35#define ESDHC_VENDOR_SPEC 0xc0
36#define ESDHC_VENDOR_SPEC_SDIO_QUIRK (1 << 1) 36#define ESDHC_VENDOR_SPEC_SDIO_QUIRK (1 << 1)
37#define ESDHC_VENDOR_SPEC_FRC_SDCLK_ON (1 << 8)
37#define ESDHC_WTMK_LVL 0x44 38#define ESDHC_WTMK_LVL 0x44
38#define ESDHC_MIX_CTRL 0x48 39#define ESDHC_MIX_CTRL 0x48
39#define ESDHC_MIX_CTRL_AC23EN (1 << 7) 40#define ESDHC_MIX_CTRL_AC23EN (1 << 7)
@@ -394,12 +395,20 @@ static unsigned int esdhc_pltfm_get_min_clock(struct sdhci_host *host)
394static inline void esdhc_pltfm_set_clock(struct sdhci_host *host, 395static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,
395 unsigned int clock) 396 unsigned int clock)
396{ 397{
398 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
399 struct pltfm_imx_data *imx_data = pltfm_host->priv;
397 int pre_div = 2; 400 int pre_div = 2;
398 int div = 1; 401 int div = 1;
399 u32 temp; 402 u32 temp, val;
400 403
401 if (clock == 0) 404 if (clock == 0) {
405 if (is_imx6q_usdhc(imx_data)) {
406 val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
407 writel(val & ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON,
408 host->ioaddr + ESDHC_VENDOR_SPEC);
409 }
402 goto out; 410 goto out;
411 }
403 412
404 temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL); 413 temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
405 temp &= ~(ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN 414 temp &= ~(ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN
@@ -423,6 +432,13 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,
423 | (div << ESDHC_DIVIDER_SHIFT) 432 | (div << ESDHC_DIVIDER_SHIFT)
424 | (pre_div << ESDHC_PREDIV_SHIFT)); 433 | (pre_div << ESDHC_PREDIV_SHIFT));
425 sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); 434 sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
435
436 if (is_imx6q_usdhc(imx_data)) {
437 val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
438 writel(val | ESDHC_VENDOR_SPEC_FRC_SDCLK_ON,
439 host->ioaddr + ESDHC_VENDOR_SPEC);
440 }
441
426 mdelay(1); 442 mdelay(1);
427out: 443out:
428 host->clock = clock; 444 host->clock = clock;