From cec2ab9ba3a05f03fa390c66cc77ef0e8ef36529 Mon Sep 17 00:00:00 2001 From: Subhash Jadavani Date: Tue, 28 May 2013 18:21:57 +0530 Subject: [PATCH] mmc: sdhci-msm: fix pwrsave bit handling SDCC controller provides the PWRSAVE control bit to automatically disable the clock to card when there is no activity with card. During the SDCC DLL tuning, PWRSAVE is disabled to make sure that clock is always running but once the DLL tuning is completed, currently we enable the PWRSAVE unconditionally irrespective of its previous state. This change ensures that we always check if the previous state of pwrsave before really enabling it. Change-Id: I464ab1e0db41af50550bb5a9ea9b909ee0d27dd9 Signed-off-by: Subhash Jadavani --- drivers/mmc/host/sdhci-msm.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index b76bc6b617c8..d08a2bb718d5 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -483,19 +483,25 @@ static int msm_init_cm_dll(struct sdhci_host *host) int rc = 0; unsigned long flags; u32 wait_cnt; + bool prev_pwrsave, curr_pwrsave; pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__); spin_lock_irqsave(&host->lock, flags); - + prev_pwrsave = !!(readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC) & + CORE_CLK_PWRSAVE); + curr_pwrsave = prev_pwrsave; /* * Make sure that clock is always enabled when DLL * tuning is in progress. Keeping PWRSAVE ON may * turn off the clock. So let's disable the PWRSAVE * here and re-enable it once tuning is completed. */ - writel_relaxed((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC) - & ~CORE_CLK_PWRSAVE), - host->ioaddr + CORE_VENDOR_SPEC); + if (prev_pwrsave) { + writel_relaxed((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC) + & ~CORE_CLK_PWRSAVE), + host->ioaddr + CORE_VENDOR_SPEC); + curr_pwrsave = false; + } /* Write 1 to DLL_RST bit of DLL_CONFIG register */ writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG) @@ -538,10 +544,18 @@ static int msm_init_cm_dll(struct sdhci_host *host) } out: - /* re-enable PWRSAVE */ - writel_relaxed((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC) | - CORE_CLK_PWRSAVE), - host->ioaddr + CORE_VENDOR_SPEC); + /* Restore the correct PWRSAVE state */ + if (prev_pwrsave ^ curr_pwrsave) { + u32 reg = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC); + + if (prev_pwrsave) + reg |= CORE_CLK_PWRSAVE; + else + reg &= ~CORE_CLK_PWRSAVE; + + writel_relaxed(reg, host->ioaddr + CORE_VENDOR_SPEC); + } + spin_unlock_irqrestore(&host->lock, flags); pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__); return rc;