summaryrefslogtreecommitdiff
path: root/drivers/mmc/host/mmci.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc/host/mmci.c')
-rw-r--r--drivers/mmc/host/mmci.c49
1 files changed, 31 insertions, 18 deletions
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index 9f92f39fec14..4ab0c622dff3 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -680,6 +680,7 @@ static bool ux500_busy_complete(struct mmci_host *host, u32 status, u32 err_msk)
writel(host->variant->busy_detect_mask, base + MMCICLEAR);
writel(readl(base + MMCIMASK0) &
~host->variant->busy_detect_mask, base + MMCIMASK0);
+ host->busy_state = MMCI_BUSY_DONE;
host->busy_status = 0;
return true;
}
@@ -697,7 +698,7 @@ static bool ux500_busy_complete(struct mmci_host *host, u32 status, u32 err_msk)
* while, to allow it to be set, but tests indicates that it
* isn't needed.
*/
- if (!host->busy_status) {
+ if (host->busy_state == MMCI_BUSY_DONE) {
status = readl(base + MMCISTATUS);
if (status & host->variant->busy_detect_flag) {
writel(readl(base + MMCIMASK0) |
@@ -705,6 +706,7 @@ static bool ux500_busy_complete(struct mmci_host *host, u32 status, u32 err_msk)
base + MMCIMASK0);
host->busy_status = status & (MCI_CMDSENT | MCI_CMDRESPEND);
+ host->busy_state = MMCI_BUSY_WAITING_FOR_START_IRQ;
return false;
}
}
@@ -720,25 +722,34 @@ static bool ux500_busy_complete(struct mmci_host *host, u32 status, u32 err_msk)
* both the start and the end interrupts needs to be cleared,
* one after the other. So, clear the busy start IRQ here.
*/
- if (host->busy_status &&
- (status & host->variant->busy_detect_flag)) {
- host->busy_status |= status & (MCI_CMDSENT | MCI_CMDRESPEND);
- writel(host->variant->busy_detect_mask, base + MMCICLEAR);
- return false;
+ if (host->busy_state == MMCI_BUSY_WAITING_FOR_START_IRQ) {
+ if (status & host->variant->busy_detect_flag) {
+ host->busy_status |= status & (MCI_CMDSENT | MCI_CMDRESPEND);
+ writel(host->variant->busy_detect_mask, base + MMCICLEAR);
+ host->busy_state = MMCI_BUSY_WAITING_FOR_END_IRQ;
+ return false;
+ } else {
+ dev_dbg(mmc_dev(host->mmc),
+ "lost busy status when waiting for busy start IRQ\n");
+ writel(host->variant->busy_detect_mask, base + MMCICLEAR);
+ writel(readl(base + MMCIMASK0) &
+ ~host->variant->busy_detect_mask, base + MMCIMASK0);
+ host->busy_state = MMCI_BUSY_DONE;
+ host->busy_status = 0;
+ return true;
+ }
}
- /*
- * If there is a command in-progress that has been successfully
- * sent and the busy bit isn't set, it means we have received
- * the busy end IRQ. Clear and mask the IRQ, then continue to
- * process the command.
- */
- if (host->busy_status) {
- writel(host->variant->busy_detect_mask, base + MMCICLEAR);
-
- writel(readl(base + MMCIMASK0) &
- ~host->variant->busy_detect_mask, base + MMCIMASK0);
- host->busy_status = 0;
+ if (host->busy_state == MMCI_BUSY_WAITING_FOR_END_IRQ) {
+ if (!(status & host->variant->busy_detect_flag)) {
+ host->busy_status |= status & (MCI_CMDSENT | MCI_CMDRESPEND);
+ host->busy_state = MMCI_BUSY_DONE;
+ return true;
+ } else {
+ dev_dbg(mmc_dev(host->mmc),
+ "busy status still asserted when handling busy end IRQ - will keep waiting\n");
+ return false;
+ }
}
return true;
@@ -1268,6 +1279,8 @@ mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c)
}
host->busy_status = 0;
+ host->busy_state = MMCI_BUSY_DONE;
+
if (host->variant->busy_timeout && cmd->flags & MMC_RSP_BUSY) {
if (!cmd->busy_timeout)
cmd->busy_timeout = 10 * MSEC_PER_SEC;