mmc: msm_sdcc: Add delay after writing to MCI_CLEAR register
After writing to MCI_CLEAR register there is a synchronization
delay (3MCLK+2HCLK) for the write to take effect in MCI_STATUS
register. If we write to the same register without this delay
then these two writes can possibly negate each other and the
old status value is reflected in the STATUS register. This can
lead ISR handler to loop forever in do-while.
Now, since msmsdcc_delay is called in ISR handler it is better
to cache the values from delay computation when clk_rate
gets updated and use it afterwards.
CRs-Fixed: 309435
Signed-off-by: Sujith Reddy Thumma <sthumma@codeaurora.org>
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 78b3338..d2d8485 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -337,9 +337,7 @@
ktime_t start, diff;
mb();
- udelay(1 + ((3 * USEC_PER_SEC) /
- (host->clk_rate ? host->clk_rate :
- msmsdcc_get_min_sup_clk_rate(host))));
+ udelay(host->reg_write_delay);
if (host->plat->sdcc_v4_sup &&
(readl_relaxed(host->base + MCI_STATUS2) &
@@ -1390,6 +1388,7 @@
wake_lock(&host->sdio_wlock);
/* only ansyc interrupt can come when clocks are off */
writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
+ msmsdcc_delay(host);
}
status = readl_relaxed(host->base + MMCISTATUS);
@@ -1403,7 +1402,8 @@
#endif
status &= readl_relaxed(host->base + MMCIMASK0);
writel_relaxed(status, host->base + MMCICLEAR);
- mb();
+ /* Allow clear to take effect*/
+ msmsdcc_delay(host);
#if IRQ_DEBUG
msmsdcc_print_status(host, "irq0-p", status);
#endif
@@ -2148,6 +2148,10 @@
pr_debug("%s: failed to set clk rate %u\n",
mmc_hostname(mmc), clock);
host->clk_rate = clock;
+ host->reg_write_delay =
+ (1 + ((3 * USEC_PER_SEC) /
+ (host->clk_rate ? host->clk_rate :
+ msmsdcc_get_min_sup_clk_rate(host))));
}
/*
* give atleast 2 MCLK cycles delay for clocks
@@ -3653,6 +3657,15 @@
goto clk_put;
host->clk_rate = clk_get_rate(host->clk);
+ if (!host->clk_rate)
+ dev_err(&pdev->dev, "Failed to read MCLK\n");
+ /*
+ * Set the register write delay according to min. clock frequency
+ * supported and update later when the host->clk_rate changes.
+ */
+ host->reg_write_delay =
+ (1 + ((3 * USEC_PER_SEC) /
+ msmsdcc_get_min_sup_clk_rate(host)));
host->clks_on = 1;
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h
index d539ffe..31ece6e 100644
--- a/drivers/mmc/host/msm_sdcc.h
+++ b/drivers/mmc/host/msm_sdcc.h
@@ -353,6 +353,7 @@
unsigned int sdcc_irq_disabled;
struct timer_list req_tout_timer;
+ unsigned long reg_write_delay;
bool io_pad_pwr_switch;
bool cmd19_tuning_in_progress;
bool tuning_needed;