Merge "mmc: msm_sdcc: fix pwrsave bit handling"
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 3986cdd..e285bfa 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -3747,6 +3747,7 @@
{
struct msmsdcc_host *host = mmc_priv(mmc);
unsigned long flags;
+ bool prev_pwrsave, curr_pwrsave;
int rc = 0;
switch (ios->signal_voltage) {
@@ -3779,7 +3780,9 @@
* low voltage is required
*/
spin_lock_irqsave(&host->lock, flags);
-
+ prev_pwrsave = !!(readl_relaxed(host->base + MMCICLOCK) &
+ MCI_CLK_PWRSAVE);
+ curr_pwrsave = prev_pwrsave;
/*
* Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
* register until they become all zeros.
@@ -3792,9 +3795,12 @@
}
/* Stop SD CLK output. */
- writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
- MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
- msmsdcc_sync_reg_wr(host);
+ if (!prev_pwrsave) {
+ writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
+ MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
+ msmsdcc_sync_reg_wr(host);
+ curr_pwrsave = true;
+ }
spin_unlock_irqrestore(&host->lock, flags);
/*
@@ -3815,6 +3821,7 @@
writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
& ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
msmsdcc_sync_reg_wr(host);
+ curr_pwrsave = false;
spin_unlock_irqrestore(&host->lock, flags);
/*
@@ -3835,10 +3842,9 @@
}
out_unlock:
- /* Enable PWRSAVE */
- writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
- MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
- msmsdcc_sync_reg_wr(host);
+ /* Restore the correct PWRSAVE state */
+ if (prev_pwrsave ^ curr_pwrsave)
+ msmsdcc_set_pwrsave(mmc, prev_pwrsave);
spin_unlock_irqrestore(&host->lock, flags);
out:
return rc;
@@ -3877,17 +3883,24 @@
int rc = 0;
unsigned long flags;
u32 wait_cnt;
+ bool prev_pwrsave, curr_pwrsave;
spin_lock_irqsave(&host->lock, flags);
+ prev_pwrsave = !!(readl_relaxed(host->base + MMCICLOCK) &
+ MCI_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->base + MMCICLOCK)
- & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
- msmsdcc_sync_reg_wr(host);
+ if (prev_pwrsave) {
+ writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
+ & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
+ msmsdcc_sync_reg_wr(host);
+ curr_pwrsave = false;
+ }
/* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
@@ -3930,10 +3943,9 @@
}
out:
- /* re-enable PWRSAVE */
- writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
- MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
- msmsdcc_sync_reg_wr(host);
+ /* Restore the correct PWRSAVE state */
+ if (prev_pwrsave ^ curr_pwrsave)
+ msmsdcc_set_pwrsave(host->mmc, prev_pwrsave);
spin_unlock_irqrestore(&host->lock, flags);
return rc;