diff options
author | Dong Aisheng <b29396@freescale.com> | 2013-09-13 07:11:33 -0400 |
---|---|---|
committer | Chris Ball <cjb@laptop.org> | 2013-09-26 07:57:21 -0400 |
commit | fed2f6e2d42e4bcdec5ea357e7a9db8602744753 (patch) | |
tree | 8477f64b02abcccfe5684ff26f645531bce790e8 /drivers/mmc | |
parent | d31fc00a71b4f3a52d23c5a995ccd63e50a2c877 (diff) |
mmc: sdhci-esdhc-imx: support real clock on and off for imx6q
The signal voltage switch flow 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>
Acked-by: Shawn Guo <shawn.guo@linaro.org>
Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/host/sdhci-esdhc-imx.c | 19 |
1 files changed, 17 insertions, 2 deletions
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 67eaec92e333..37fafd7df964 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) |
@@ -409,13 +410,20 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host, | |||
409 | unsigned int clock) | 410 | unsigned int clock) |
410 | { | 411 | { |
411 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); | 412 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
413 | struct pltfm_imx_data *imx_data = pltfm_host->priv; | ||
412 | unsigned int host_clock = clk_get_rate(pltfm_host->clk); | 414 | unsigned int host_clock = clk_get_rate(pltfm_host->clk); |
413 | int pre_div = 2; | 415 | int pre_div = 2; |
414 | int div = 1; | 416 | int div = 1; |
415 | u32 temp; | 417 | u32 temp, val; |
416 | 418 | ||
417 | if (clock == 0) | 419 | if (clock == 0) { |
420 | if (is_imx6q_usdhc(imx_data)) { | ||
421 | val = readl(host->ioaddr + ESDHC_VENDOR_SPEC); | ||
422 | writel(val & ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON, | ||
423 | host->ioaddr + ESDHC_VENDOR_SPEC); | ||
424 | } | ||
418 | goto out; | 425 | goto out; |
426 | } | ||
419 | 427 | ||
420 | temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL); | 428 | temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL); |
421 | temp &= ~(ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN | 429 | temp &= ~(ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN |
@@ -439,6 +447,13 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host, | |||
439 | | (div << ESDHC_DIVIDER_SHIFT) | 447 | | (div << ESDHC_DIVIDER_SHIFT) |
440 | | (pre_div << ESDHC_PREDIV_SHIFT)); | 448 | | (pre_div << ESDHC_PREDIV_SHIFT)); |
441 | sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); | 449 | sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); |
450 | |||
451 | if (is_imx6q_usdhc(imx_data)) { | ||
452 | val = readl(host->ioaddr + ESDHC_VENDOR_SPEC); | ||
453 | writel(val | ESDHC_VENDOR_SPEC_FRC_SDCLK_ON, | ||
454 | host->ioaddr + ESDHC_VENDOR_SPEC); | ||
455 | } | ||
456 | |||
442 | mdelay(1); | 457 | mdelay(1); |
443 | out: | 458 | out: |
444 | host->clock = clock; | 459 | host->clock = clock; |