mmc: esdhc-imx: clearing SDHCI_CTRL_EXEC_TUNING should not affect other bits
authorDong Aisheng <b29396@freescale.com>
Mon, 4 Nov 2013 08:38:27 +0000 (16:38 +0800)
committerChris Ball <chris@printf.net>
Mon, 13 Jan 2014 17:48:08 +0000 (12:48 -0500)
Current code will clear all turning related bits like ESDHC_STD_TUNING_EN
and ESDHC_MIX_CTRL_FBCLK_SEL when clear SDHCI_CTRL_EXEC_TUNING.
This may cause the card which has already passed the turning to become
unwork since the turning status lost.
We observed this failure when enable runtime pm.

BTW, imx needs to enable ESDHC_MIX_CTRL_FBCLK_SEL bit for turned clock.
The FBCLK_SEL will be cleared when SDHCI_CTRL_TUNED_CLK is cleared
and SDHCI_CTRL_EXEC_TUNING is not set.
This is used in case we change to another normal card from a UHS card
in the same slot. FBCLK_SEL is not needed for normal card.

After that, SDHCI_CTRL_EXEC_TUNING will only affect ESDHC_MIX_CTRL_EXE_TUNE.
Clearing it does not affect the turned card to remain working on UHS mode.

Signed-off-by: Dong Aisheng <b29396@freescale.com>
Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
Signed-off-by: Chris Ball <cjb@laptop.org>
drivers/mmc/host/sdhci-esdhc-imx.c

index d85a6a6f9e29849e4556de99114b8a66b06524a4..b1544a786eb64a0a6d71c303a57834b14aa4394b 100644 (file)
@@ -439,24 +439,20 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
                } else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) {
                        u32 v = readl(host->ioaddr + SDHCI_ACMD12_ERR);
                        u32 m = readl(host->ioaddr + ESDHC_MIX_CTRL);
-                       new_val = readl(host->ioaddr + ESDHC_TUNING_CTRL);
+                       if (val & SDHCI_CTRL_TUNED_CLK) {
+                               v |= ESDHC_MIX_CTRL_SMPCLK_SEL;
+                       } else {
+                               v &= ~ESDHC_MIX_CTRL_SMPCLK_SEL;
+                               m &= ~ESDHC_MIX_CTRL_FBCLK_SEL;
+                       }
+
                        if (val & SDHCI_CTRL_EXEC_TUNING) {
-                               new_val |= ESDHC_STD_TUNING_EN |
-                                               ESDHC_TUNING_START_TAP;
                                v |= ESDHC_MIX_CTRL_EXE_TUNE;
                                m |= ESDHC_MIX_CTRL_FBCLK_SEL;
                        } else {
-                               new_val &= ~ESDHC_STD_TUNING_EN;
                                v &= ~ESDHC_MIX_CTRL_EXE_TUNE;
-                               m &= ~ESDHC_MIX_CTRL_FBCLK_SEL;
                        }
 
-                       if (val & SDHCI_CTRL_TUNED_CLK)
-                               v |= ESDHC_MIX_CTRL_SMPCLK_SEL;
-                       else
-                               v &= ~ESDHC_MIX_CTRL_SMPCLK_SEL;
-
-                       writel(new_val, host->ioaddr + ESDHC_TUNING_CTRL);
                        writel(v, host->ioaddr + SDHCI_ACMD12_ERR);
                        writel(m, host->ioaddr + ESDHC_MIX_CTRL);
                }
@@ -1038,6 +1034,12 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
        if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING)
                sdhci_esdhc_ops.platform_execute_tuning =
                                        esdhc_executing_tuning;
+
+       if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING)
+               writel(readl(host->ioaddr + ESDHC_TUNING_CTRL) |
+                       ESDHC_STD_TUNING_EN | ESDHC_TUNING_START_TAP,
+                       host->ioaddr + ESDHC_TUNING_CTRL);
+
        boarddata = &imx_data->boarddata;
        if (sdhci_esdhc_imx_probe_dt(pdev, boarddata) < 0) {
                if (!host->mmc->parent->platform_data) {