mmc: sdhci: convert reset into a library function
[deliverable/linux.git] / drivers / mmc / host / sdhci.c
index 9ddef47635418d4d18019a8a1433e67ca536628c..5e25147e92f77629c3a072efd5d3fd16da3aca66 100644 (file)
@@ -131,43 +131,26 @@ static void sdhci_dumpregs(struct sdhci_host *host)
  *                                                                           *
 \*****************************************************************************/
 
-static void sdhci_clear_set_irqs(struct sdhci_host *host, u32 clear, u32 set)
-{
-       u32 ier;
-
-       ier = sdhci_readl(host, SDHCI_INT_ENABLE);
-       ier &= ~clear;
-       ier |= set;
-       sdhci_writel(host, ier, SDHCI_INT_ENABLE);
-       sdhci_writel(host, ier, SDHCI_SIGNAL_ENABLE);
-}
-
-static void sdhci_unmask_irqs(struct sdhci_host *host, u32 irqs)
-{
-       sdhci_clear_set_irqs(host, 0, irqs);
-}
-
-static void sdhci_mask_irqs(struct sdhci_host *host, u32 irqs)
-{
-       sdhci_clear_set_irqs(host, irqs, 0);
-}
-
 static void sdhci_set_card_detection(struct sdhci_host *host, bool enable)
 {
-       u32 present, irqs;
+       u32 present;
 
        if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) ||
            (host->mmc->caps & MMC_CAP_NONREMOVABLE))
                return;
 
-       present = sdhci_readl(host, SDHCI_PRESENT_STATE) &
-                             SDHCI_CARD_PRESENT;
-       irqs = present ? SDHCI_INT_CARD_REMOVE : SDHCI_INT_CARD_INSERT;
+       if (enable) {
+               present = sdhci_readl(host, SDHCI_PRESENT_STATE) &
+                                     SDHCI_CARD_PRESENT;
 
-       if (enable)
-               sdhci_unmask_irqs(host, irqs);
-       else
-               sdhci_mask_irqs(host, irqs);
+               host->ier |= present ? SDHCI_INT_CARD_REMOVE :
+                                      SDHCI_INT_CARD_INSERT;
+       } else {
+               host->ier &= ~(SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT);
+       }
+
+       sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+       sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
 }
 
 static void sdhci_enable_card_detection(struct sdhci_host *host)
@@ -180,22 +163,9 @@ static void sdhci_disable_card_detection(struct sdhci_host *host)
        sdhci_set_card_detection(host, false);
 }
 
-static void sdhci_reset(struct sdhci_host *host, u8 mask)
+void sdhci_reset(struct sdhci_host *host, u8 mask)
 {
        unsigned long timeout;
-       u32 uninitialized_var(ier);
-
-       if (host->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) {
-               if (!(sdhci_readl(host, SDHCI_PRESENT_STATE) &
-                       SDHCI_CARD_PRESENT))
-                       return;
-       }
-
-       if (host->quirks & SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET)
-               ier = sdhci_readl(host, SDHCI_INT_ENABLE);
-
-       if (host->ops->platform_reset_enter)
-               host->ops->platform_reset_enter(host, mask);
 
        sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET);
 
@@ -220,12 +190,23 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask)
                timeout--;
                mdelay(1);
        }
+}
+EXPORT_SYMBOL_GPL(sdhci_reset);
 
-       if (host->ops->platform_reset_exit)
-               host->ops->platform_reset_exit(host, mask);
+static void sdhci_do_reset(struct sdhci_host *host, u8 mask)
+{
+       if (host->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) {
+               if (!(sdhci_readl(host, SDHCI_PRESENT_STATE) &
+                       SDHCI_CARD_PRESENT))
+                       return;
+       }
 
-       if (host->quirks & SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET)
-               sdhci_clear_set_irqs(host, SDHCI_INT_ALL_MASK, ier);
+       host->ops->reset(host, mask);
+
+       if (host->quirks & SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET) {
+               sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+               sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
+       }
 
        if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
                if ((host->ops->enable_dma) && (mask & SDHCI_RESET_ALL))
@@ -238,15 +219,18 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios);
 static void sdhci_init(struct sdhci_host *host, int soft)
 {
        if (soft)
-               sdhci_reset(host, SDHCI_RESET_CMD|SDHCI_RESET_DATA);
+               sdhci_do_reset(host, SDHCI_RESET_CMD|SDHCI_RESET_DATA);
        else
-               sdhci_reset(host, SDHCI_RESET_ALL);
+               sdhci_do_reset(host, SDHCI_RESET_ALL);
 
-       sdhci_clear_set_irqs(host, SDHCI_INT_ALL_MASK,
-               SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT |
-               SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_INDEX |
-               SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT |
-               SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE);
+       host->ier = SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT |
+                   SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT |
+                   SDHCI_INT_INDEX | SDHCI_INT_END_BIT | SDHCI_INT_CRC |
+                   SDHCI_INT_TIMEOUT | SDHCI_INT_DATA_END |
+                   SDHCI_INT_RESPONSE;
+
+       sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+       sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
 
        if (soft) {
                /* force clock reconfiguration */
@@ -675,12 +659,12 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
                return 0xE;
 
        /* Unspecified timeout, assume max */
-       if (!data && !cmd->cmd_timeout_ms)
+       if (!data && !cmd->busy_timeout)
                return 0xE;
 
        /* timeout in us */
        if (!data)
-               target_timeout = cmd->cmd_timeout_ms * 1000;
+               target_timeout = cmd->busy_timeout * 1000;
        else {
                target_timeout = data->timeout_ns / 1000;
                if (host->clock)
@@ -721,9 +705,12 @@ static void sdhci_set_transfer_irqs(struct sdhci_host *host)
        u32 dma_irqs = SDHCI_INT_DMA_END | SDHCI_INT_ADMA_ERROR;
 
        if (host->flags & SDHCI_REQ_USE_DMA)
-               sdhci_clear_set_irqs(host, pio_irqs, dma_irqs);
+               host->ier = (host->ier & ~pio_irqs) | dma_irqs;
        else
-               sdhci_clear_set_irqs(host, dma_irqs, pio_irqs);
+               host->ier = (host->ier & ~dma_irqs) | pio_irqs;
+
+       sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+       sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
 }
 
 static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
@@ -976,8 +963,8 @@ static void sdhci_finish_data(struct sdhci_host *host)
                 * upon error conditions.
                 */
                if (data->error) {
-                       sdhci_reset(host, SDHCI_RESET_CMD);
-                       sdhci_reset(host, SDHCI_RESET_DATA);
+                       sdhci_do_reset(host, SDHCI_RESET_CMD);
+                       sdhci_do_reset(host, SDHCI_RESET_DATA);
                }
 
                sdhci_send_command(host, data->stop);
@@ -1019,8 +1006,8 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
        }
 
        timeout = jiffies;
-       if (!cmd->data && cmd->cmd_timeout_ms > 9000)
-               timeout += DIV_ROUND_UP(cmd->cmd_timeout_ms, 1000) * HZ + HZ;
+       if (!cmd->data && cmd->busy_timeout > 9000)
+               timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ;
        else
                timeout += 10 * HZ;
        mod_timer(&host->timer, timeout);
@@ -1427,6 +1414,27 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
        spin_unlock_irqrestore(&host->lock, flags);
 }
 
+void sdhci_set_bus_width(struct sdhci_host *host, int width)
+{
+       u8 ctrl;
+
+       ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
+       if (width == MMC_BUS_WIDTH_8) {
+               ctrl &= ~SDHCI_CTRL_4BITBUS;
+               if (host->version >= SDHCI_SPEC_300)
+                       ctrl |= SDHCI_CTRL_8BITBUS;
+       } else {
+               if (host->version >= SDHCI_SPEC_300)
+                       ctrl &= ~SDHCI_CTRL_8BITBUS;
+               if (width == MMC_BUS_WIDTH_4)
+                       ctrl |= SDHCI_CTRL_4BITBUS;
+               else
+                       ctrl &= ~SDHCI_CTRL_4BITBUS;
+       }
+       sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
+}
+EXPORT_SYMBOL_GPL(sdhci_set_bus_width);
+
 static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
 {
        unsigned long flags;
@@ -1472,29 +1480,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
        if (host->ops->platform_send_init_74_clocks)
                host->ops->platform_send_init_74_clocks(host, ios->power_mode);
 
-       /*
-        * If your platform has 8-bit width support but is not a v3 controller,
-        * or if it requires special setup code, you should implement that in
-        * platform_bus_width().
-        */
-       if (host->ops->platform_bus_width) {
-               host->ops->platform_bus_width(host, ios->bus_width);
-       } else {
-               ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
-               if (ios->bus_width == MMC_BUS_WIDTH_8) {
-                       ctrl &= ~SDHCI_CTRL_4BITBUS;
-                       if (host->version >= SDHCI_SPEC_300)
-                               ctrl |= SDHCI_CTRL_8BITBUS;
-               } else {
-                       if (host->version >= SDHCI_SPEC_300)
-                               ctrl &= ~SDHCI_CTRL_8BITBUS;
-                       if (ios->bus_width == MMC_BUS_WIDTH_4)
-                               ctrl |= SDHCI_CTRL_4BITBUS;
-                       else
-                               ctrl &= ~SDHCI_CTRL_4BITBUS;
-               }
-               sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
-       }
+       host->ops->set_bus_width(host, ios->bus_width);
 
        ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
 
@@ -1510,6 +1496,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
 
                /* In case of UHS-I modes, set High Speed Enable */
                if ((ios->timing == MMC_TIMING_MMC_HS200) ||
+                   (ios->timing == MMC_TIMING_MMC_DDR52) ||
                    (ios->timing == MMC_TIMING_UHS_SDR50) ||
                    (ios->timing == MMC_TIMING_UHS_SDR104) ||
                    (ios->timing == MMC_TIMING_UHS_DDR50) ||
@@ -1570,7 +1557,8 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
                                ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
                        else if (ios->timing == MMC_TIMING_UHS_SDR50)
                                ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
-                       else if (ios->timing == MMC_TIMING_UHS_DDR50)
+                       else if ((ios->timing == MMC_TIMING_UHS_DDR50) ||
+                                (ios->timing == MMC_TIMING_MMC_DDR52))
                                ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
                        sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
                }
@@ -1600,7 +1588,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
         * it on each ios seems to solve the problem.
         */
        if(host->quirks & SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS)
-               sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
+               sdhci_do_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
 
        mmiowb();
        spin_unlock_irqrestore(&host->lock, flags);
@@ -1709,24 +1697,16 @@ static int sdhci_get_ro(struct mmc_host *mmc)
 
 static void sdhci_enable_sdio_irq_nolock(struct sdhci_host *host, int enable)
 {
-       if (host->flags & SDHCI_DEVICE_DEAD)
-               goto out;
-
-       if (enable)
-               host->flags |= SDHCI_SDIO_IRQ_ENABLED;
-       else
-               host->flags &= ~SDHCI_SDIO_IRQ_ENABLED;
-
-       /* SDIO IRQ will be enabled as appropriate in runtime resume */
-       if (host->runtime_suspended)
-               goto out;
+       if (!(host->flags & SDHCI_DEVICE_DEAD)) {
+               if (enable)
+                       host->ier |= SDHCI_INT_CARD_INT;
+               else
+                       host->ier &= ~SDHCI_INT_CARD_INT;
 
-       if (enable)
-               sdhci_unmask_irqs(host, SDHCI_INT_CARD_INT);
-       else
-               sdhci_mask_irqs(host, SDHCI_INT_CARD_INT);
-out:
-       mmiowb();
+               sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+               sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
+               mmiowb();
+       }
 }
 
 static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
@@ -1734,9 +1714,18 @@ static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
        struct sdhci_host *host = mmc_priv(mmc);
        unsigned long flags;
 
+       sdhci_runtime_pm_get(host);
+
        spin_lock_irqsave(&host->lock, flags);
+       if (enable)
+               host->flags |= SDHCI_SDIO_IRQ_ENABLED;
+       else
+               host->flags &= ~SDHCI_SDIO_IRQ_ENABLED;
+
        sdhci_enable_sdio_irq_nolock(host, enable);
        spin_unlock_irqrestore(&host->lock, flags);
+
+       sdhci_runtime_pm_put(host);
 }
 
 static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
@@ -1857,7 +1846,6 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
 {
        struct sdhci_host *host;
        u16 ctrl;
-       u32 ier;
        int tuning_loop_counter = MAX_TUNING_LOOP;
        unsigned long timeout;
        int err = 0;
@@ -1911,8 +1899,8 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
         * to make sure we don't hit a controller bug, we _only_
         * enable Buffer Read Ready interrupt here.
         */
-       ier = sdhci_readl(host, SDHCI_INT_ENABLE);
-       sdhci_clear_set_irqs(host, ier, SDHCI_INT_DATA_AVAIL);
+       sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_INT_ENABLE);
+       sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_SIGNAL_ENABLE);
 
        /*
         * Issue CMD19 repeatedly till Execute Tuning is set to 0 or the number
@@ -1992,7 +1980,10 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
                ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
                tuning_loop_counter--;
                timeout--;
-               mdelay(1);
+
+               /* eMMC spec does not require a delay between tuning cycles */
+               if (opcode == MMC_SEND_TUNING_BLOCK)
+                       mdelay(1);
        } while (ctrl & SDHCI_CTRL_EXEC_TUNING);
 
        /*
@@ -2026,12 +2017,11 @@ out:
                        host->tuning_count * HZ);
                /* Tuning mode 1 limits the maximum data length to 4MB */
                mmc->max_blk_count = (4 * 1024 * 1024) / mmc->max_blk_size;
-       } else {
+       } else if (host->flags & SDHCI_USING_RETUNING_TIMER) {
                host->flags &= ~SDHCI_NEEDS_RETUNING;
                /* Reload the new initial value for timer */
-               if (host->tuning_mode == SDHCI_TUNING_MODE_1)
-                       mod_timer(&host->tuning_timer, jiffies +
-                               host->tuning_count * HZ);
+               mod_timer(&host->tuning_timer, jiffies +
+                         host->tuning_count * HZ);
        }
 
        /*
@@ -2045,7 +2035,8 @@ out:
        if (err && (host->flags & SDHCI_USING_RETUNING_TIMER))
                err = 0;
 
-       sdhci_clear_set_irqs(host, SDHCI_INT_DATA_AVAIL, ier);
+       sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+       sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
        spin_unlock_irqrestore(&host->lock, flags);
        sdhci_runtime_pm_put(host);
 
@@ -2096,8 +2087,8 @@ static void sdhci_card_event(struct mmc_host *mmc)
                pr_err("%s: Resetting controller.\n",
                        mmc_hostname(host->mmc));
 
-               sdhci_reset(host, SDHCI_RESET_CMD);
-               sdhci_reset(host, SDHCI_RESET_DATA);
+               sdhci_do_reset(host, SDHCI_RESET_CMD);
+               sdhci_do_reset(host, SDHCI_RESET_DATA);
 
                host->mrq->cmd->error = -ENOMEDIUM;
                tasklet_schedule(&host->finish_tasklet);
@@ -2125,15 +2116,6 @@ static const struct mmc_host_ops sdhci_ops = {
  *                                                                           *
 \*****************************************************************************/
 
-static void sdhci_tasklet_card(unsigned long param)
-{
-       struct sdhci_host *host = (struct sdhci_host*)param;
-
-       sdhci_card_event(host->mmc);
-
-       mmc_detect_change(host->mmc, msecs_to_jiffies(200));
-}
-
 static void sdhci_tasklet_finish(unsigned long param)
 {
        struct sdhci_host *host;
@@ -2174,8 +2156,8 @@ static void sdhci_tasklet_finish(unsigned long param)
 
                /* Spec says we should do both at the same time, but Ricoh
                   controllers do not like that. */
-               sdhci_reset(host, SDHCI_RESET_CMD);
-               sdhci_reset(host, SDHCI_RESET_DATA);
+               sdhci_do_reset(host, SDHCI_RESET_CMD);
+               sdhci_do_reset(host, SDHCI_RESET_DATA);
        }
 
        host->mrq = NULL;
@@ -2425,103 +2407,94 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
 
 static irqreturn_t sdhci_irq(int irq, void *dev_id)
 {
-       irqreturn_t result;
+       irqreturn_t result = IRQ_NONE;
        struct sdhci_host *host = dev_id;
-       u32 intmask, unexpected = 0;
-       int cardint = 0, max_loops = 16;
+       u32 intmask, mask, unexpected = 0;
+       int max_loops = 16;
 
        spin_lock(&host->lock);
 
-       if (host->runtime_suspended) {
+       if (host->runtime_suspended && !sdhci_sdio_irq_enabled(host)) {
                spin_unlock(&host->lock);
-               pr_warning("%s: got irq while runtime suspended\n",
-                      mmc_hostname(host->mmc));
-               return IRQ_HANDLED;
+               return IRQ_NONE;
        }
 
        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);
-       }
-
-       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);
-       }
+       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_DATA_MASK) {
-               sdhci_writel(host, intmask & SDHCI_INT_DATA_MASK,
-                       SDHCI_INT_STATUS);
-               sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK);
-       }
+               DBG("*** %s got interrupt: 0x%08x\n",
+                       mmc_hostname(host->mmc), intmask);
 
-       intmask &= ~(SDHCI_INT_CMD_MASK | 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_ERROR;
+                       /*
+                        * 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.
+                        */
+                       host->ier &= ~(SDHCI_INT_CARD_INSERT |
+                                      SDHCI_INT_CARD_REMOVE);
+                       host->ier |= present ? SDHCI_INT_CARD_REMOVE :
+                                              SDHCI_INT_CARD_INSERT;
+                       sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+                       sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
+
+                       sdhci_writel(host, intmask & (SDHCI_INT_CARD_INSERT |
+                                    SDHCI_INT_CARD_REMOVE), SDHCI_INT_STATUS);
+
+                       host->thread_isr |= intmask & (SDHCI_INT_CARD_INSERT |
+                                                      SDHCI_INT_CARD_REMOVE);
+                       result = IRQ_WAKE_THREAD;
+               }
 
-       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_CMD_MASK)
+                       sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK);
 
-       intmask &= ~SDHCI_INT_BUS_POWER;
+               if (intmask & SDHCI_INT_DATA_MASK)
+                       sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK);
 
-       if (intmask & SDHCI_INT_CARD_INT)
-               cardint = 1;
+               if (intmask & SDHCI_INT_BUS_POWER)
+                       pr_err("%s: Card is consuming too much power!\n",
+                               mmc_hostname(host->mmc));
 
-       intmask &= ~SDHCI_INT_CARD_INT;
+               if (intmask & SDHCI_INT_CARD_INT) {
+                       sdhci_enable_sdio_irq_nolock(host, false);
+                       host->thread_isr |= SDHCI_INT_CARD_INT;
+                       result = IRQ_WAKE_THREAD;
+               }
 
-       if (intmask) {
-               unexpected |= intmask;
-               sdhci_writel(host, intmask, SDHCI_INT_STATUS);
-       }
+               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);
 
-       result = IRQ_HANDLED;
+               if (intmask) {
+                       unexpected |= intmask;
+                       sdhci_writel(host, intmask, SDHCI_INT_STATUS);
+               }
 
-       intmask = sdhci_readl(host, SDHCI_INT_STATUS);
+               if (result == IRQ_NONE)
+                       result = IRQ_HANDLED;
 
-       /*
-        * 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;
+               intmask = sdhci_readl(host, SDHCI_INT_STATUS);
+       } while (intmask && --max_loops);
 out:
        spin_unlock(&host->lock);
 
@@ -2530,15 +2503,38 @@ out:
                           mmc_hostname(host->mmc), unexpected);
                sdhci_dumpregs(host);
        }
-       /*
-        * We have to delay this as it calls back into the driver.
-        */
-       if (cardint)
-               mmc_signal_sdio_irq(host->mmc);
 
        return result;
 }
 
+static irqreturn_t sdhci_thread_irq(int irq, void *dev_id)
+{
+       struct sdhci_host *host = dev_id;
+       unsigned long flags;
+       u32 isr;
+
+       spin_lock_irqsave(&host->lock, flags);
+       isr = host->thread_isr;
+       host->thread_isr = 0;
+       spin_unlock_irqrestore(&host->lock, flags);
+
+       if (isr & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) {
+               sdhci_card_event(host->mmc);
+               mmc_detect_change(host->mmc, msecs_to_jiffies(200));
+       }
+
+       if (isr & SDHCI_INT_CARD_INT) {
+               sdio_run_irqs(host->mmc);
+
+               spin_lock_irqsave(&host->lock, flags);
+               if (host->flags & SDHCI_SDIO_IRQ_ENABLED)
+                       sdhci_enable_sdio_irq_nolock(host, true);
+               spin_unlock_irqrestore(&host->lock, flags);
+       }
+
+       return isr ? IRQ_HANDLED : IRQ_NONE;
+}
+
 /*****************************************************************************\
  *                                                                           *
  * Suspend/resume                                                            *
@@ -2587,7 +2583,9 @@ int sdhci_suspend_host(struct sdhci_host *host)
        }
 
        if (!device_may_wakeup(mmc_dev(host->mmc))) {
-               sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK);
+               host->ier = 0;
+               sdhci_writel(host, 0, SDHCI_INT_ENABLE);
+               sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE);
                free_irq(host->irq, host);
        } else {
                sdhci_enable_irq_wakeups(host);
@@ -2608,8 +2606,9 @@ int sdhci_resume_host(struct sdhci_host *host)
        }
 
        if (!device_may_wakeup(mmc_dev(host->mmc))) {
-               ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED,
-                                 mmc_hostname(host->mmc), host);
+               ret = request_threaded_irq(host->irq, sdhci_irq,
+                                          sdhci_thread_irq, IRQF_SHARED,
+                                          mmc_hostname(host->mmc), host);
                if (ret)
                        return ret;
        } else {
@@ -2685,10 +2684,12 @@ int sdhci_runtime_suspend_host(struct sdhci_host *host)
        }
 
        spin_lock_irqsave(&host->lock, flags);
-       sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK);
+       host->ier &= SDHCI_INT_CARD_INT;
+       sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+       sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
        spin_unlock_irqrestore(&host->lock, flags);
 
-       synchronize_irq(host->irq);
+       synchronize_hardirq(host->irq);
 
        spin_lock_irqsave(&host->lock, flags);
        host->runtime_suspended = true;
@@ -2732,7 +2733,7 @@ int sdhci_runtime_resume_host(struct sdhci_host *host)
        host->runtime_suspended = false;
 
        /* Enable SDIO IRQ */
-       if ((host->flags & SDHCI_SDIO_IRQ_ENABLED))
+       if (host->flags & SDHCI_SDIO_IRQ_ENABLED)
                sdhci_enable_sdio_irq_nolock(host, true);
 
        /* Enable Card Detection */
@@ -2791,7 +2792,7 @@ int sdhci_add_host(struct sdhci_host *host)
        if (debug_quirks2)
                host->quirks2 = debug_quirks2;
 
-       sdhci_reset(host, SDHCI_RESET_ALL);
+       sdhci_do_reset(host, SDHCI_RESET_ALL);
 
        host->version = sdhci_readw(host, SDHCI_HOST_VERSION);
        host->version = (host->version & SDHCI_SPEC_VER_MASK)
@@ -2941,9 +2942,10 @@ int sdhci_add_host(struct sdhci_host *host)
        if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)
                host->timeout_clk = mmc->f_max / 1000;
 
-       mmc->max_discard_to = (1 << 27) / host->timeout_clk;
+       mmc->max_busy_timeout = (1 << 27) / host->timeout_clk;
 
        mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23;
+       mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD;
 
        if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12)
                host->flags |= SDHCI_AUTO_CMD12;
@@ -3020,7 +3022,8 @@ int sdhci_add_host(struct sdhci_host *host)
        } else if (caps[1] & SDHCI_SUPPORT_SDR50)
                mmc->caps |= MMC_CAP_UHS_SDR50;
 
-       if (caps[1] & SDHCI_SUPPORT_DDR50)
+       if ((caps[1] & SDHCI_SUPPORT_DDR50) &&
+               !(host->quirks2 & SDHCI_QUIRK2_BROKEN_DDR50))
                mmc->caps |= MMC_CAP_UHS_DDR50;
 
        /* Does the host need tuning for SDR50? */
@@ -3214,8 +3217,6 @@ int sdhci_add_host(struct sdhci_host *host)
        /*
         * Init tasklets.
         */
-       tasklet_init(&host->card_tasklet,
-               sdhci_tasklet_card, (unsigned long)host);
        tasklet_init(&host->finish_tasklet,
                sdhci_tasklet_finish, (unsigned long)host);
 
@@ -3232,8 +3233,8 @@ int sdhci_add_host(struct sdhci_host *host)
 
        sdhci_init(host, 0);
 
-       ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED,
-               mmc_hostname(mmc), host);
+       ret = request_threaded_irq(host->irq, sdhci_irq, sdhci_thread_irq,
+                                  IRQF_SHARED, mmc_hostname(mmc), host);
        if (ret) {
                pr_err("%s: Failed to request IRQ %d: %d\n",
                       mmc_hostname(mmc), host->irq, ret);
@@ -3275,12 +3276,12 @@ int sdhci_add_host(struct sdhci_host *host)
 
 #ifdef SDHCI_USE_LEDS_CLASS
 reset:
-       sdhci_reset(host, SDHCI_RESET_ALL);
-       sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK);
+       sdhci_do_reset(host, SDHCI_RESET_ALL);
+       sdhci_writel(host, 0, SDHCI_INT_ENABLE);
+       sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE);
        free_irq(host->irq, host);
 #endif
 untasklet:
-       tasklet_kill(&host->card_tasklet);
        tasklet_kill(&host->finish_tasklet);
 
        return ret;
@@ -3317,14 +3318,14 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
 #endif
 
        if (!dead)
-               sdhci_reset(host, SDHCI_RESET_ALL);
+               sdhci_do_reset(host, SDHCI_RESET_ALL);
 
-       sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK);
+       sdhci_writel(host, 0, SDHCI_INT_ENABLE);
+       sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE);
        free_irq(host->irq, host);
 
        del_timer_sync(&host->timer);
 
-       tasklet_kill(&host->card_tasklet);
        tasklet_kill(&host->finish_tasklet);
 
        if (host->vmmc) {
This page took 0.036247 seconds and 5 git commands to generate.