{
irqreturn_t result;
struct sdhci_host *host = dev_id;
- u32 intmask, unexpected = 0;
+ u32 intmask, mask, unexpected = 0;
int cardint = 0, max_loops = 16;
spin_lock(&host->lock);
}
intmask = sdhci_readl(host, SDHCI_INT_STATUS);
-
if (!intmask || intmask == 0xffffffff) {
result = IRQ_NONE;
goto out;
}
-again:
- DBG("*** %s got interrupt: 0x%08x\n",
- mmc_hostname(host->mmc), intmask);
-
- if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) {
- u32 present = sdhci_readl(host, SDHCI_PRESENT_STATE) &
- SDHCI_CARD_PRESENT;
-
- /*
- * There is a observation on i.mx esdhc. INSERT bit will be
- * immediately set again when it gets cleared, if a card is
- * inserted. We have to mask the irq to prevent interrupt
- * storm which will freeze the system. And the REMOVE gets
- * the same situation.
- *
- * More testing are needed here to ensure it works for other
- * platforms though.
- */
- sdhci_mask_irqs(host, present ? SDHCI_INT_CARD_INSERT :
- SDHCI_INT_CARD_REMOVE);
- sdhci_unmask_irqs(host, present ? SDHCI_INT_CARD_REMOVE :
- SDHCI_INT_CARD_INSERT);
-
- sdhci_writel(host, intmask & (SDHCI_INT_CARD_INSERT |
- SDHCI_INT_CARD_REMOVE), SDHCI_INT_STATUS);
- intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE);
- tasklet_schedule(&host->card_tasklet);
- }
+ do {
+ /* Clear selected interrupts. */
+ mask = intmask & (SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK |
+ SDHCI_INT_BUS_POWER);
+ sdhci_writel(host, mask, SDHCI_INT_STATUS);
- if (intmask & SDHCI_INT_CMD_MASK) {
- sdhci_writel(host, intmask & SDHCI_INT_CMD_MASK,
- SDHCI_INT_STATUS);
- sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK);
- }
+ DBG("*** %s got interrupt: 0x%08x\n",
+ mmc_hostname(host->mmc), intmask);
- if (intmask & SDHCI_INT_DATA_MASK) {
- sdhci_writel(host, intmask & SDHCI_INT_DATA_MASK,
- SDHCI_INT_STATUS);
- sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK);
- }
+ if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) {
+ u32 present = sdhci_readl(host, SDHCI_PRESENT_STATE) &
+ SDHCI_CARD_PRESENT;
- intmask &= ~(SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK);
+ /*
+ * There is a observation on i.mx esdhc. INSERT
+ * bit will be immediately set again when it gets
+ * cleared, if a card is inserted. We have to mask
+ * the irq to prevent interrupt storm which will
+ * freeze the system. And the REMOVE gets the
+ * same situation.
+ *
+ * More testing are needed here to ensure it works
+ * for other platforms though.
+ */
+ sdhci_mask_irqs(host, present ? SDHCI_INT_CARD_INSERT :
+ SDHCI_INT_CARD_REMOVE);
+ sdhci_unmask_irqs(host, present ? SDHCI_INT_CARD_REMOVE :
+ SDHCI_INT_CARD_INSERT);
+
+ sdhci_writel(host, intmask & (SDHCI_INT_CARD_INSERT |
+ SDHCI_INT_CARD_REMOVE), SDHCI_INT_STATUS);
+ tasklet_schedule(&host->card_tasklet);
+ }
- intmask &= ~SDHCI_INT_ERROR;
+ if (intmask & SDHCI_INT_CMD_MASK)
+ sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK);
- if (intmask & SDHCI_INT_BUS_POWER) {
- pr_err("%s: Card is consuming too much power!\n",
- mmc_hostname(host->mmc));
- sdhci_writel(host, SDHCI_INT_BUS_POWER, SDHCI_INT_STATUS);
- }
+ if (intmask & SDHCI_INT_DATA_MASK)
+ sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK);
- intmask &= ~SDHCI_INT_BUS_POWER;
+ if (intmask & SDHCI_INT_BUS_POWER)
+ pr_err("%s: Card is consuming too much power!\n",
+ mmc_hostname(host->mmc));
- if (intmask & SDHCI_INT_CARD_INT)
- cardint = 1;
+ if (intmask & SDHCI_INT_CARD_INT)
+ cardint = 1;
- intmask &= ~SDHCI_INT_CARD_INT;
+ intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE |
+ SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK |
+ SDHCI_INT_ERROR | SDHCI_INT_BUS_POWER |
+ SDHCI_INT_CARD_INT);
- if (intmask) {
- unexpected |= intmask;
- sdhci_writel(host, intmask, SDHCI_INT_STATUS);
- }
+ if (intmask) {
+ unexpected |= intmask;
+ sdhci_writel(host, intmask, SDHCI_INT_STATUS);
+ }
- result = IRQ_HANDLED;
+ result = IRQ_HANDLED;
- intmask = sdhci_readl(host, SDHCI_INT_STATUS);
+ intmask = sdhci_readl(host, SDHCI_INT_STATUS);
- /*
- * If we know we'll call the driver to signal SDIO IRQ, disregard
- * further indications of Card Interrupt in the status to avoid a
- * needless loop.
- */
- if (cardint)
- intmask &= ~SDHCI_INT_CARD_INT;
- if (intmask && --max_loops)
- goto again;
+ /*
+ * If we know we'll call the driver to signal SDIO IRQ,
+ * disregard further indications of Card Interrupt in
+ * the status to avoid a needless loop.
+ */
+ if (cardint)
+ intmask &= ~SDHCI_INT_CARD_INT;
+ } while (intmask && --max_loops);
out:
spin_unlock(&host->lock);