|
@@ -127,11 +127,15 @@ static void sdhci_mask_irqs(struct sdhci_host *host, u32 irqs)
|
|
|
|
|
|
static void sdhci_set_card_detection(struct sdhci_host *host, bool enable)
|
|
|
{
|
|
|
- u32 irqs = SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT;
|
|
|
+ u32 present, irqs;
|
|
|
|
|
|
if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION)
|
|
|
return;
|
|
|
|
|
|
+ present = sdhci_readl(host, SDHCI_PRESENT_STATE) &
|
|
|
+ SDHCI_CARD_PRESENT;
|
|
|
+ irqs = present ? SDHCI_INT_CARD_REMOVE : SDHCI_INT_CARD_INSERT;
|
|
|
+
|
|
|
if (enable)
|
|
|
sdhci_unmask_irqs(host, irqs);
|
|
|
else
|
|
@@ -2154,13 +2158,30 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
|
|
|
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);
|
|
|
+ SDHCI_INT_CARD_REMOVE), SDHCI_INT_STATUS);
|
|
|
+ intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE);
|
|
|
tasklet_schedule(&host->card_tasklet);
|
|
|
}
|
|
|
|
|
|
- intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE);
|
|
|
-
|
|
|
if (intmask & SDHCI_INT_CMD_MASK) {
|
|
|
sdhci_writel(host, intmask & SDHCI_INT_CMD_MASK,
|
|
|
SDHCI_INT_STATUS);
|