Merge branch 'for-upstream' of git://openrisc.net/jonas/linux
[pandora-kernel.git] / drivers / mmc / host / sdhci.c
index b9ed663..c31a334 100644 (file)
@@ -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
@@ -857,7 +861,12 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host,
                 */
                if (!host->mrq->sbc && (host->flags & SDHCI_AUTO_CMD12))
                        mode |= SDHCI_TRNS_AUTO_CMD12;
+               else if (host->mrq->sbc && (host->flags & SDHCI_AUTO_CMD23)) {
+                       mode |= SDHCI_TRNS_AUTO_CMD23;
+                       sdhci_writel(host, host->mrq->sbc->arg, SDHCI_ARGUMENT2);
+               }
        }
+
        if (data->flags & MMC_DATA_READ)
                mode |= SDHCI_TRNS_READ;
        if (host->flags & SDHCI_REQ_USE_DMA)
@@ -1252,7 +1261,7 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
                        host->mrq = mrq;
                }
 
-               if (mrq->sbc)
+               if (mrq->sbc && !(host->flags & SDHCI_AUTO_CMD23))
                        sdhci_send_command(host, mrq->sbc);
                else
                        sdhci_send_command(host, mrq->cmd);
@@ -2149,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);
@@ -2483,11 +2509,26 @@ int sdhci_add_host(struct sdhci_host *host)
        } else
                mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_200;
 
+       if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)
+               mmc->max_discard_to = (1 << 27) / (mmc->f_max / 1000);
+       else
+               mmc->max_discard_to = (1 << 27) / host->timeout_clk;
+
        mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23;
 
        if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12)
                host->flags |= SDHCI_AUTO_CMD12;
 
+       /* Auto-CMD23 stuff only works in ADMA or PIO. */
+       if ((host->version >= SDHCI_SPEC_300) &&
+           ((host->flags & SDHCI_USE_ADMA) ||
+            !(host->flags & SDHCI_USE_SDMA))) {
+               host->flags |= SDHCI_AUTO_CMD23;
+               DBG("%s: Auto-CMD23 available\n", mmc_hostname(mmc));
+       } else {
+               DBG("%s: Auto-CMD23 unavailable\n", mmc_hostname(mmc));
+       }
+
        /*
         * A controller may support 8-bit width, but the board itself
         * might not have the pins brought out.  Boards that support