]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/mmc/host/sdhci.c
mmc: sdhci: Export sdhci_enable_sdio_irq() from sdhci.c
[karo-tx-linux.git] / drivers / mmc / host / sdhci.c
index 63bc33a54d0dd8e63b50197611be31aae6f288fc..4bdad8959ec26a15ff4663e57b446c0f6487b066 100644 (file)
@@ -14,6 +14,7 @@
  */
 
 #include <linux/delay.h>
+#include <linux/ktime.h>
 #include <linux/highmem.h>
 #include <linux/io.h>
 #include <linux/module.h>
 #define DRIVER_NAME "sdhci"
 
 #define DBG(f, x...) \
-       pr_debug(DRIVER_NAME " [%s()]: " f, __func__,## x)
+       pr_debug("%s: " DRIVER_NAME ": " f, mmc_hostname(host->mmc), ## x)
+
+#define SDHCI_DUMP(f, x...) \
+       pr_err("%s: " DRIVER_NAME ": " f, mmc_hostname(host->mmc), ## x)
 
 #define MAX_TUNING_LOOP 40
 
@@ -48,61 +52,68 @@ static void sdhci_finish_data(struct sdhci_host *);
 
 static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable);
 
-static void sdhci_dumpregs(struct sdhci_host *host)
-{
-       pr_err(DRIVER_NAME ": =========== REGISTER DUMP (%s)===========\n",
-              mmc_hostname(host->mmc));
-
-       pr_err(DRIVER_NAME ": Sys addr: 0x%08x | Version:  0x%08x\n",
-              sdhci_readl(host, SDHCI_DMA_ADDRESS),
-              sdhci_readw(host, SDHCI_HOST_VERSION));
-       pr_err(DRIVER_NAME ": Blk size: 0x%08x | Blk cnt:  0x%08x\n",
-              sdhci_readw(host, SDHCI_BLOCK_SIZE),
-              sdhci_readw(host, SDHCI_BLOCK_COUNT));
-       pr_err(DRIVER_NAME ": Argument: 0x%08x | Trn mode: 0x%08x\n",
-              sdhci_readl(host, SDHCI_ARGUMENT),
-              sdhci_readw(host, SDHCI_TRANSFER_MODE));
-       pr_err(DRIVER_NAME ": Present:  0x%08x | Host ctl: 0x%08x\n",
-              sdhci_readl(host, SDHCI_PRESENT_STATE),
-              sdhci_readb(host, SDHCI_HOST_CONTROL));
-       pr_err(DRIVER_NAME ": Power:    0x%08x | Blk gap:  0x%08x\n",
-              sdhci_readb(host, SDHCI_POWER_CONTROL),
-              sdhci_readb(host, SDHCI_BLOCK_GAP_CONTROL));
-       pr_err(DRIVER_NAME ": Wake-up:  0x%08x | Clock:    0x%08x\n",
-              sdhci_readb(host, SDHCI_WAKE_UP_CONTROL),
-              sdhci_readw(host, SDHCI_CLOCK_CONTROL));
-       pr_err(DRIVER_NAME ": Timeout:  0x%08x | Int stat: 0x%08x\n",
-              sdhci_readb(host, SDHCI_TIMEOUT_CONTROL),
-              sdhci_readl(host, SDHCI_INT_STATUS));
-       pr_err(DRIVER_NAME ": Int enab: 0x%08x | Sig enab: 0x%08x\n",
-              sdhci_readl(host, SDHCI_INT_ENABLE),
-              sdhci_readl(host, SDHCI_SIGNAL_ENABLE));
-       pr_err(DRIVER_NAME ": AC12 err: 0x%08x | Slot int: 0x%08x\n",
-              sdhci_readw(host, SDHCI_ACMD12_ERR),
-              sdhci_readw(host, SDHCI_SLOT_INT_STATUS));
-       pr_err(DRIVER_NAME ": Caps:     0x%08x | Caps_1:   0x%08x\n",
-              sdhci_readl(host, SDHCI_CAPABILITIES),
-              sdhci_readl(host, SDHCI_CAPABILITIES_1));
-       pr_err(DRIVER_NAME ": Cmd:      0x%08x | Max curr: 0x%08x\n",
-              sdhci_readw(host, SDHCI_COMMAND),
-              sdhci_readl(host, SDHCI_MAX_CURRENT));
-       pr_err(DRIVER_NAME ": Host ctl2: 0x%08x\n",
-              sdhci_readw(host, SDHCI_HOST_CONTROL2));
+void sdhci_dumpregs(struct sdhci_host *host)
+{
+       SDHCI_DUMP("============ SDHCI REGISTER DUMP ===========\n");
+
+       SDHCI_DUMP("Sys addr:  0x%08x | Version:  0x%08x\n",
+                  sdhci_readl(host, SDHCI_DMA_ADDRESS),
+                  sdhci_readw(host, SDHCI_HOST_VERSION));
+       SDHCI_DUMP("Blk size:  0x%08x | Blk cnt:  0x%08x\n",
+                  sdhci_readw(host, SDHCI_BLOCK_SIZE),
+                  sdhci_readw(host, SDHCI_BLOCK_COUNT));
+       SDHCI_DUMP("Argument:  0x%08x | Trn mode: 0x%08x\n",
+                  sdhci_readl(host, SDHCI_ARGUMENT),
+                  sdhci_readw(host, SDHCI_TRANSFER_MODE));
+       SDHCI_DUMP("Present:   0x%08x | Host ctl: 0x%08x\n",
+                  sdhci_readl(host, SDHCI_PRESENT_STATE),
+                  sdhci_readb(host, SDHCI_HOST_CONTROL));
+       SDHCI_DUMP("Power:     0x%08x | Blk gap:  0x%08x\n",
+                  sdhci_readb(host, SDHCI_POWER_CONTROL),
+                  sdhci_readb(host, SDHCI_BLOCK_GAP_CONTROL));
+       SDHCI_DUMP("Wake-up:   0x%08x | Clock:    0x%08x\n",
+                  sdhci_readb(host, SDHCI_WAKE_UP_CONTROL),
+                  sdhci_readw(host, SDHCI_CLOCK_CONTROL));
+       SDHCI_DUMP("Timeout:   0x%08x | Int stat: 0x%08x\n",
+                  sdhci_readb(host, SDHCI_TIMEOUT_CONTROL),
+                  sdhci_readl(host, SDHCI_INT_STATUS));
+       SDHCI_DUMP("Int enab:  0x%08x | Sig enab: 0x%08x\n",
+                  sdhci_readl(host, SDHCI_INT_ENABLE),
+                  sdhci_readl(host, SDHCI_SIGNAL_ENABLE));
+       SDHCI_DUMP("AC12 err:  0x%08x | Slot int: 0x%08x\n",
+                  sdhci_readw(host, SDHCI_ACMD12_ERR),
+                  sdhci_readw(host, SDHCI_SLOT_INT_STATUS));
+       SDHCI_DUMP("Caps:      0x%08x | Caps_1:   0x%08x\n",
+                  sdhci_readl(host, SDHCI_CAPABILITIES),
+                  sdhci_readl(host, SDHCI_CAPABILITIES_1));
+       SDHCI_DUMP("Cmd:       0x%08x | Max curr: 0x%08x\n",
+                  sdhci_readw(host, SDHCI_COMMAND),
+                  sdhci_readl(host, SDHCI_MAX_CURRENT));
+       SDHCI_DUMP("Resp[0]:   0x%08x | Resp[1]:  0x%08x\n",
+                  sdhci_readl(host, SDHCI_RESPONSE),
+                  sdhci_readl(host, SDHCI_RESPONSE + 4));
+       SDHCI_DUMP("Resp[2]:   0x%08x | Resp[3]:  0x%08x\n",
+                  sdhci_readl(host, SDHCI_RESPONSE + 8),
+                  sdhci_readl(host, SDHCI_RESPONSE + 12));
+       SDHCI_DUMP("Host ctl2: 0x%08x\n",
+                  sdhci_readw(host, SDHCI_HOST_CONTROL2));
 
        if (host->flags & SDHCI_USE_ADMA) {
-               if (host->flags & SDHCI_USE_64_BIT_DMA)
-                       pr_err(DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x%08x\n",
-                              readl(host->ioaddr + SDHCI_ADMA_ERROR),
-                              readl(host->ioaddr + SDHCI_ADMA_ADDRESS_HI),
-                              readl(host->ioaddr + SDHCI_ADMA_ADDRESS));
-               else
-                       pr_err(DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x\n",
-                              readl(host->ioaddr + SDHCI_ADMA_ERROR),
-                              readl(host->ioaddr + SDHCI_ADMA_ADDRESS));
+               if (host->flags & SDHCI_USE_64_BIT_DMA) {
+                       SDHCI_DUMP("ADMA Err:  0x%08x | ADMA Ptr: 0x%08x%08x\n",
+                                  sdhci_readl(host, SDHCI_ADMA_ERROR),
+                                  sdhci_readl(host, SDHCI_ADMA_ADDRESS_HI),
+                                  sdhci_readl(host, SDHCI_ADMA_ADDRESS));
+               } else {
+                       SDHCI_DUMP("ADMA Err:  0x%08x | ADMA Ptr: 0x%08x\n",
+                                  sdhci_readl(host, SDHCI_ADMA_ERROR),
+                                  sdhci_readl(host, SDHCI_ADMA_ADDRESS));
+               }
        }
 
-       pr_err(DRIVER_NAME ": ===========================================\n");
+       SDHCI_DUMP("============================================\n");
 }
+EXPORT_SYMBOL_GPL(sdhci_dumpregs);
 
 /*****************************************************************************\
  *                                                                           *
@@ -165,7 +176,7 @@ static void sdhci_runtime_pm_bus_off(struct sdhci_host *host)
 
 void sdhci_reset(struct sdhci_host *host, u8 mask)
 {
-       unsigned long timeout;
+       ktime_t timeout;
 
        sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET);
 
@@ -177,18 +188,17 @@ void sdhci_reset(struct sdhci_host *host, u8 mask)
        }
 
        /* Wait max 100 ms */
-       timeout = 100;
+       timeout = ktime_add_ms(ktime_get(), 100);
 
        /* hw clears the bit when it's done */
        while (sdhci_readb(host, SDHCI_SOFTWARE_RESET) & mask) {
-               if (timeout == 0) {
+               if (ktime_after(ktime_get(), timeout)) {
                        pr_err("%s: Reset 0x%x never completed.\n",
                                mmc_hostname(host->mmc), (int)mask);
                        sdhci_dumpregs(host);
                        return;
                }
-               timeout--;
-               mdelay(1);
+               udelay(10);
        }
 }
 EXPORT_SYMBOL_GPL(sdhci_reset);
@@ -215,15 +225,8 @@ static void sdhci_do_reset(struct sdhci_host *host, u8 mask)
        }
 }
 
-static void sdhci_init(struct sdhci_host *host, int soft)
+static void sdhci_set_default_irqs(struct sdhci_host *host)
 {
-       struct mmc_host *mmc = host->mmc;
-
-       if (soft)
-               sdhci_do_reset(host, SDHCI_RESET_CMD|SDHCI_RESET_DATA);
-       else
-               sdhci_do_reset(host, SDHCI_RESET_ALL);
-
        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 |
@@ -236,6 +239,20 @@ static void sdhci_init(struct sdhci_host *host, int soft)
 
        sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
        sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
+}
+
+static void sdhci_init(struct sdhci_host *host, int soft)
+{
+       struct mmc_host *mmc = host->mmc;
+
+       if (soft)
+               sdhci_do_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
+       else
+               sdhci_do_reset(host, SDHCI_RESET_ALL);
+
+       sdhci_set_default_irqs(host);
+
+       host->cqe_on = false;
 
        if (soft) {
                /* force clock reconfiguration */
@@ -485,8 +502,7 @@ static int sdhci_pre_dma_transfer(struct sdhci_host *host,
                return data->sg_count;
 
        sg_count = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
-                               data->flags & MMC_DATA_WRITE ?
-                               DMA_TO_DEVICE : DMA_FROM_DEVICE);
+                             mmc_get_dma_dir(data));
 
        if (sg_count == 0)
                return -ENOSPC;
@@ -715,8 +731,8 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
        }
 
        if (count >= 0xF) {
-               DBG("%s: Too large timeout 0x%x requested for CMD%d!\n",
-                   mmc_hostname(host->mmc), count, cmd->opcode);
+               DBG("Too large timeout 0x%x requested for CMD%d!\n",
+                   count, cmd->opcode);
                count = 0xE;
        }
 
@@ -1346,25 +1362,22 @@ EXPORT_SYMBOL_GPL(sdhci_calc_clk);
 
 void sdhci_enable_clk(struct sdhci_host *host, u16 clk)
 {
-       unsigned long timeout;
+       ktime_t timeout;
 
        clk |= SDHCI_CLOCK_INT_EN;
        sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
 
        /* Wait max 20 ms */
-       timeout = 20;
+       timeout = ktime_add_ms(ktime_get(), 20);
        while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL))
                & SDHCI_CLOCK_INT_STABLE)) {
-               if (timeout == 0) {
+               if (ktime_after(ktime_get(), timeout)) {
                        pr_err("%s: Internal clock never stabilised.\n",
                               mmc_hostname(host->mmc));
                        sdhci_dumpregs(host);
                        return;
                }
-               timeout--;
-               spin_unlock_irq(&host->lock);
-               usleep_range(900, 1100);
-               spin_lock_irq(&host->lock);
+               udelay(10);
        }
 
        clk |= SDHCI_CLOCK_CARD_EN;
@@ -1393,9 +1406,7 @@ static void sdhci_set_power_reg(struct sdhci_host *host, unsigned char mode,
 {
        struct mmc_host *mmc = host->mmc;
 
-       spin_unlock_irq(&host->lock);
        mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd);
-       spin_lock_irq(&host->lock);
 
        if (mode != MMC_POWER_OFF)
                sdhci_writeb(host, SDHCI_POWER_ON, SDHCI_POWER_CONTROL);
@@ -1572,19 +1583,15 @@ void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
 }
 EXPORT_SYMBOL_GPL(sdhci_set_uhs_signaling);
 
-static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 {
        struct sdhci_host *host = mmc_priv(mmc);
-       unsigned long flags;
        u8 ctrl;
 
        if (ios->power_mode == MMC_POWER_UNDEFINED)
                return;
 
-       spin_lock_irqsave(&host->lock, flags);
-
        if (host->flags & SDHCI_DEVICE_DEAD) {
-               spin_unlock_irqrestore(&host->lock, flags);
                if (!IS_ERR(mmc->supply.vmmc) &&
                    ios->power_mode == MMC_POWER_OFF)
                        mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
@@ -1730,8 +1737,8 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                sdhci_do_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
 
        mmiowb();
-       spin_unlock_irqrestore(&host->lock, flags);
 }
+EXPORT_SYMBOL_GPL(sdhci_set_ios);
 
 static int sdhci_get_cd(struct mmc_host *mmc)
 {
@@ -1825,7 +1832,7 @@ static void sdhci_enable_sdio_irq_nolock(struct sdhci_host *host, int enable)
        }
 }
 
-static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
+void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
 {
        struct sdhci_host *host = mmc_priv(mmc);
        unsigned long flags;
@@ -1845,9 +1852,10 @@ static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
        if (!enable)
                pm_runtime_put_noidle(host->mmc->parent);
 }
+EXPORT_SYMBOL_GPL(sdhci_enable_sdio_irq);
 
-static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
-                                            struct mmc_ios *ios)
+int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
+                                     struct mmc_ios *ios)
 {
        struct sdhci_host *host = mmc_priv(mmc);
        u16 ctrl;
@@ -1939,6 +1947,7 @@ static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
                return 0;
        }
 }
+EXPORT_SYMBOL_GPL(sdhci_start_signal_voltage_switch);
 
 static int sdhci_card_busy(struct mmc_host *mmc)
 {
@@ -2003,8 +2012,7 @@ static void sdhci_reset_tuning(struct sdhci_host *host)
        sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
 }
 
-static void sdhci_abort_tuning(struct sdhci_host *host, u32 opcode,
-                              unsigned long flags)
+static void sdhci_abort_tuning(struct sdhci_host *host, u32 opcode)
 {
        sdhci_reset_tuning(host);
 
@@ -2013,9 +2021,7 @@ static void sdhci_abort_tuning(struct sdhci_host *host, u32 opcode,
 
        sdhci_end_tuning(host);
 
-       spin_unlock_irqrestore(&host->lock, flags);
        mmc_abort_tuning(host->mmc, opcode);
-       spin_lock_irqsave(&host->lock, flags);
 }
 
 /*
@@ -2025,12 +2031,14 @@ static void sdhci_abort_tuning(struct sdhci_host *host, u32 opcode,
  * interrupt setup is different to other commands and there is no timeout
  * interrupt so special handling is needed.
  */
-static void sdhci_send_tuning(struct sdhci_host *host, u32 opcode,
-                             unsigned long flags)
+static void sdhci_send_tuning(struct sdhci_host *host, u32 opcode)
 {
        struct mmc_host *mmc = host->mmc;
        struct mmc_command cmd = {};
        struct mmc_request mrq = {};
+       unsigned long flags;
+
+       spin_lock_irqsave(&host->lock, flags);
 
        cmd.opcode = opcode;
        cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
@@ -2064,17 +2072,16 @@ static void sdhci_send_tuning(struct sdhci_host *host, u32 opcode,
 
        host->tuning_done = 0;
 
+       mmiowb();
        spin_unlock_irqrestore(&host->lock, flags);
 
        /* Wait for Buffer Read Ready interrupt */
        wait_event_timeout(host->buf_ready_int, (host->tuning_done == 1),
                           msecs_to_jiffies(50));
 
-       spin_lock_irqsave(&host->lock, flags);
 }
 
-static void __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode,
-                                  unsigned long flags)
+static void __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode)
 {
        int i;
 
@@ -2085,12 +2092,12 @@ static void __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode,
        for (i = 0; i < MAX_TUNING_LOOP; i++) {
                u16 ctrl;
 
-               sdhci_send_tuning(host, opcode, flags);
+               sdhci_send_tuning(host, opcode);
 
                if (!host->tuning_done) {
                        pr_info("%s: Tuning timeout, falling back to fixed sampling clock\n",
                                mmc_hostname(host->mmc));
-                       sdhci_abort_tuning(host, opcode, flags);
+                       sdhci_abort_tuning(host, opcode);
                        return;
                }
 
@@ -2115,12 +2122,9 @@ int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
 {
        struct sdhci_host *host = mmc_priv(mmc);
        int err = 0;
-       unsigned long flags;
        unsigned int tuning_count = 0;
        bool hs400_tuning;
 
-       spin_lock_irqsave(&host->lock, flags);
-
        hs400_tuning = host->flags & SDHCI_HS400_TUNING;
 
        if (host->tuning_mode == SDHCI_TUNING_MODE_1)
@@ -2137,7 +2141,7 @@ int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
        /* HS400 tuning is done in HS200 mode */
        case MMC_TIMING_MMC_HS400:
                err = -EINVAL;
-               goto out_unlock;
+               goto out;
 
        case MMC_TIMING_MMC_HS200:
                /*
@@ -2158,44 +2162,28 @@ int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
                /* FALLTHROUGH */
 
        default:
-               goto out_unlock;
+               goto out;
        }
 
        if (host->ops->platform_execute_tuning) {
-               spin_unlock_irqrestore(&host->lock, flags);
                err = host->ops->platform_execute_tuning(host, opcode);
-               spin_lock_irqsave(&host->lock, flags);
-               goto out_unlock;
+               goto out;
        }
 
        host->mmc->retune_period = tuning_count;
 
        sdhci_start_tuning(host);
 
-       __sdhci_execute_tuning(host, opcode, flags);
+       __sdhci_execute_tuning(host, opcode);
 
        sdhci_end_tuning(host);
-out_unlock:
+out:
        host->flags &= ~SDHCI_HS400_TUNING;
-       spin_unlock_irqrestore(&host->lock, flags);
 
        return err;
 }
 EXPORT_SYMBOL_GPL(sdhci_execute_tuning);
 
-static int sdhci_select_drive_strength(struct mmc_card *card,
-                                      unsigned int max_dtr, int host_drv,
-                                      int card_drv, int *drv_type)
-{
-       struct sdhci_host *host = mmc_priv(card->host);
-
-       if (!host->ops->select_drive_strength)
-               return 0;
-
-       return host->ops->select_drive_strength(host, card, max_dtr, host_drv,
-                                               card_drv, drv_type);
-}
-
 static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable)
 {
        /* Host Controller v3.00 defines preset value registers */
@@ -2233,8 +2221,7 @@ static void sdhci_post_req(struct mmc_host *mmc, struct mmc_request *mrq,
 
        if (data->host_cookie != COOKIE_UNMAPPED)
                dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
-                            data->flags & MMC_DATA_WRITE ?
-                              DMA_TO_DEVICE : DMA_FROM_DEVICE);
+                            mmc_get_dma_dir(data));
 
        data->host_cookie = COOKIE_UNMAPPED;
 }
@@ -2309,7 +2296,6 @@ static const struct mmc_host_ops sdhci_ops = {
        .start_signal_voltage_switch    = sdhci_start_signal_voltage_switch,
        .prepare_hs400_tuning           = sdhci_prepare_hs400_tuning,
        .execute_tuning                 = sdhci_execute_tuning,
-       .select_drive_strength          = sdhci_select_drive_strength,
        .card_event                     = sdhci_card_event,
        .card_busy      = sdhci_card_busy,
 };
@@ -2351,8 +2337,7 @@ static bool sdhci_request_done(struct sdhci_host *host)
 
                if (data && data->host_cookie == COOKIE_MAPPED) {
                        dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
-                                    (data->flags & MMC_DATA_READ) ?
-                                    DMA_FROM_DEVICE : DMA_TO_DEVICE);
+                                    mmc_get_dma_dir(data));
                        data->host_cookie = COOKIE_UNMAPPED;
                }
        }
@@ -2517,7 +2502,6 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask)
 #ifdef CONFIG_MMC_DEBUG
 static void sdhci_adma_show_error(struct sdhci_host *host)
 {
-       const char *name = mmc_hostname(host->mmc);
        void *desc = host->adma_table;
 
        sdhci_dumpregs(host);
@@ -2526,14 +2510,14 @@ static void sdhci_adma_show_error(struct sdhci_host *host)
                struct sdhci_adma2_64_desc *dma_desc = desc;
 
                if (host->flags & SDHCI_USE_64_BIT_DMA)
-                       DBG("%s: %p: DMA 0x%08x%08x, LEN 0x%04x, Attr=0x%02x\n",
-                           name, desc, le32_to_cpu(dma_desc->addr_hi),
+                       DBG("%p: DMA 0x%08x%08x, LEN 0x%04x, Attr=0x%02x\n",
+                           desc, le32_to_cpu(dma_desc->addr_hi),
                            le32_to_cpu(dma_desc->addr_lo),
                            le16_to_cpu(dma_desc->len),
                            le16_to_cpu(dma_desc->cmd));
                else
-                       DBG("%s: %p: DMA 0x%08x, LEN 0x%04x, Attr=0x%02x\n",
-                           name, desc, le32_to_cpu(dma_desc->addr_lo),
+                       DBG("%p: DMA 0x%08x, LEN 0x%04x, Attr=0x%02x\n",
+                           desc, le32_to_cpu(dma_desc->addr_lo),
                            le16_to_cpu(dma_desc->len),
                            le16_to_cpu(dma_desc->cmd));
 
@@ -2649,10 +2633,8 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
                                ~(SDHCI_DEFAULT_BOUNDARY_SIZE - 1)) +
                                SDHCI_DEFAULT_BOUNDARY_SIZE;
                        host->data->bytes_xfered = dmanow - dmastart;
-                       DBG("%s: DMA base 0x%08x, transferred 0x%06x bytes,"
-                               " next 0x%08x\n",
-                               mmc_hostname(host->mmc), dmastart,
-                               host->data->bytes_xfered, dmanow);
+                       DBG("DMA base 0x%08x, transferred 0x%06x bytes, next 0x%08x\n",
+                           dmastart, host->data->bytes_xfered, dmanow);
                        sdhci_writel(host, dmanow, SDHCI_DMA_ADDRESS);
                }
 
@@ -2692,14 +2674,19 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
        }
 
        do {
+               DBG("IRQ status 0x%08x\n", intmask);
+
+               if (host->ops->irq) {
+                       intmask = host->ops->irq(host, intmask);
+                       if (!intmask)
+                               goto cont;
+               }
+
                /* Clear selected interrupts. */
                mask = intmask & (SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK |
                                  SDHCI_INT_BUS_POWER);
                sdhci_writel(host, mask, SDHCI_INT_STATUS);
 
-               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;
@@ -2759,7 +2746,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
                        unexpected |= intmask;
                        sdhci_writel(host, intmask, SDHCI_INT_STATUS);
                }
-
+cont:
                if (result == IRQ_NONE)
                        result = IRQ_HANDLED;
 
@@ -2858,8 +2845,6 @@ int sdhci_suspend_host(struct sdhci_host *host)
        sdhci_disable_card_detection(host);
 
        mmc_retune_timer_stop(host->mmc);
-       if (host->tuning_mode != SDHCI_TUNING_MODE_3)
-               mmc_retune_needed(host->mmc);
 
        if (!device_may_wakeup(mmc_dev(host->mmc))) {
                host->ier = 0;
@@ -2920,8 +2905,6 @@ int sdhci_runtime_suspend_host(struct sdhci_host *host)
        unsigned long flags;
 
        mmc_retune_timer_stop(host->mmc);
-       if (host->tuning_mode != SDHCI_TUNING_MODE_3)
-               mmc_retune_needed(host->mmc);
 
        spin_lock_irqsave(&host->lock, flags);
        host->ier &= SDHCI_INT_CARD_INT;
@@ -2990,6 +2973,119 @@ EXPORT_SYMBOL_GPL(sdhci_runtime_resume_host);
 
 #endif /* CONFIG_PM */
 
+/*****************************************************************************\
+ *                                                                           *
+ * Command Queue Engine (CQE) helpers                                        *
+ *                                                                           *
+\*****************************************************************************/
+
+void sdhci_cqe_enable(struct mmc_host *mmc)
+{
+       struct sdhci_host *host = mmc_priv(mmc);
+       unsigned long flags;
+       u8 ctrl;
+
+       spin_lock_irqsave(&host->lock, flags);
+
+       ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
+       ctrl &= ~SDHCI_CTRL_DMA_MASK;
+       if (host->flags & SDHCI_USE_64_BIT_DMA)
+               ctrl |= SDHCI_CTRL_ADMA64;
+       else
+               ctrl |= SDHCI_CTRL_ADMA32;
+       sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
+
+       sdhci_writew(host, SDHCI_MAKE_BLKSZ(SDHCI_DEFAULT_BOUNDARY_ARG, 512),
+                    SDHCI_BLOCK_SIZE);
+
+       /* Set maximum timeout */
+       sdhci_writeb(host, 0xE, SDHCI_TIMEOUT_CONTROL);
+
+       host->ier = host->cqe_ier;
+
+       sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+       sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
+
+       host->cqe_on = true;
+
+       pr_debug("%s: sdhci: CQE on, IRQ mask %#x, IRQ status %#x\n",
+                mmc_hostname(mmc), host->ier,
+                sdhci_readl(host, SDHCI_INT_STATUS));
+
+       mmiowb();
+       spin_unlock_irqrestore(&host->lock, flags);
+}
+EXPORT_SYMBOL_GPL(sdhci_cqe_enable);
+
+void sdhci_cqe_disable(struct mmc_host *mmc, bool recovery)
+{
+       struct sdhci_host *host = mmc_priv(mmc);
+       unsigned long flags;
+
+       spin_lock_irqsave(&host->lock, flags);
+
+       sdhci_set_default_irqs(host);
+
+       host->cqe_on = false;
+
+       if (recovery) {
+               sdhci_do_reset(host, SDHCI_RESET_CMD);
+               sdhci_do_reset(host, SDHCI_RESET_DATA);
+       }
+
+       pr_debug("%s: sdhci: CQE off, IRQ mask %#x, IRQ status %#x\n",
+                mmc_hostname(mmc), host->ier,
+                sdhci_readl(host, SDHCI_INT_STATUS));
+
+       mmiowb();
+       spin_unlock_irqrestore(&host->lock, flags);
+}
+EXPORT_SYMBOL_GPL(sdhci_cqe_disable);
+
+bool sdhci_cqe_irq(struct sdhci_host *host, u32 intmask, int *cmd_error,
+                  int *data_error)
+{
+       u32 mask;
+
+       if (!host->cqe_on)
+               return false;
+
+       if (intmask & (SDHCI_INT_INDEX | SDHCI_INT_END_BIT | SDHCI_INT_CRC))
+               *cmd_error = -EILSEQ;
+       else if (intmask & SDHCI_INT_TIMEOUT)
+               *cmd_error = -ETIMEDOUT;
+       else
+               *cmd_error = 0;
+
+       if (intmask & (SDHCI_INT_DATA_END_BIT | SDHCI_INT_DATA_CRC))
+               *data_error = -EILSEQ;
+       else if (intmask & SDHCI_INT_DATA_TIMEOUT)
+               *data_error = -ETIMEDOUT;
+       else if (intmask & SDHCI_INT_ADMA_ERROR)
+               *data_error = -EIO;
+       else
+               *data_error = 0;
+
+       /* Clear selected interrupts. */
+       mask = intmask & host->cqe_ier;
+       sdhci_writel(host, mask, SDHCI_INT_STATUS);
+
+       if (intmask & SDHCI_INT_BUS_POWER)
+               pr_err("%s: Card is consuming too much power!\n",
+                      mmc_hostname(host->mmc));
+
+       intmask &= ~(host->cqe_ier | SDHCI_INT_ERROR);
+       if (intmask) {
+               sdhci_writel(host, intmask, SDHCI_INT_STATUS);
+               pr_err("%s: CQE: Unexpected interrupt 0x%08x.\n",
+                      mmc_hostname(host->mmc), intmask);
+               sdhci_dumpregs(host);
+       }
+
+       return true;
+}
+EXPORT_SYMBOL_GPL(sdhci_cqe_irq);
+
 /*****************************************************************************\
  *                                                                           *
  * Device allocation/registration                                            *
@@ -3015,6 +3111,9 @@ struct sdhci_host *sdhci_alloc_host(struct device *dev,
 
        host->flags = SDHCI_SIGNALING_330;
 
+       host->cqe_ier     = SDHCI_CQE_INT_MASK;
+       host->cqe_err_ier = SDHCI_CQE_INT_ERR_MASK;
+
        return host;
 }
 
@@ -3297,20 +3396,22 @@ int sdhci_setup_host(struct sdhci_host *host)
        if (!(host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)) {
                host->timeout_clk = (host->caps & SDHCI_TIMEOUT_CLK_MASK) >>
                                        SDHCI_TIMEOUT_CLK_SHIFT;
+
+               if (host->caps & SDHCI_TIMEOUT_CLK_UNIT)
+                       host->timeout_clk *= 1000;
+
                if (host->timeout_clk == 0) {
-                       if (host->ops->get_timeout_clock) {
-                               host->timeout_clk =
-                                       host->ops->get_timeout_clock(host);
-                       } else {
+                       if (!host->ops->get_timeout_clock) {
                                pr_err("%s: Hardware doesn't specify timeout clock frequency.\n",
                                        mmc_hostname(mmc));
                                ret = -ENODEV;
                                goto undma;
                        }
-               }
 
-               if (host->caps & SDHCI_TIMEOUT_CLK_UNIT)
-                       host->timeout_clk *= 1000;
+                       host->timeout_clk =
+                               DIV_ROUND_UP(host->ops->get_timeout_clock(host),
+                                            1000);
+               }
 
                if (override_timeout_clk)
                        host->timeout_clk = override_timeout_clk;
@@ -3332,9 +3433,9 @@ int sdhci_setup_host(struct sdhci_host *host)
             !(host->flags & SDHCI_USE_SDMA)) &&
             !(host->quirks2 & SDHCI_QUIRK2_ACMD23_BROKEN)) {
                host->flags |= SDHCI_AUTO_CMD23;
-               DBG("%s: Auto-CMD23 available\n", mmc_hostname(mmc));
+               DBG("Auto-CMD23 available\n");
        } else {
-               DBG("%s: Auto-CMD23 unavailable\n", mmc_hostname(mmc));
+               DBG("Auto-CMD23 unavailable\n");
        }
 
        /*
@@ -3598,6 +3699,22 @@ undma:
 }
 EXPORT_SYMBOL_GPL(sdhci_setup_host);
 
+void sdhci_cleanup_host(struct sdhci_host *host)
+{
+       struct mmc_host *mmc = host->mmc;
+
+       if (!IS_ERR(mmc->supply.vqmmc))
+               regulator_disable(mmc->supply.vqmmc);
+
+       if (host->align_buffer)
+               dma_free_coherent(mmc_dev(mmc), host->align_buffer_sz +
+                                 host->adma_table_sz, host->align_buffer,
+                                 host->align_addr);
+       host->adma_table = NULL;
+       host->align_buffer = NULL;
+}
+EXPORT_SYMBOL_GPL(sdhci_cleanup_host);
+
 int __sdhci_add_host(struct sdhci_host *host)
 {
        struct mmc_host *mmc = host->mmc;
@@ -3662,16 +3779,6 @@ unirq:
 untasklet:
        tasklet_kill(&host->finish_tasklet);
 
-       if (!IS_ERR(mmc->supply.vqmmc))
-               regulator_disable(mmc->supply.vqmmc);
-
-       if (host->align_buffer)
-               dma_free_coherent(mmc_dev(mmc), host->align_buffer_sz +
-                                 host->adma_table_sz, host->align_buffer,
-                                 host->align_addr);
-       host->adma_table = NULL;
-       host->align_buffer = NULL;
-
        return ret;
 }
 EXPORT_SYMBOL_GPL(__sdhci_add_host);
@@ -3684,7 +3791,16 @@ int sdhci_add_host(struct sdhci_host *host)
        if (ret)
                return ret;
 
-       return __sdhci_add_host(host);
+       ret = __sdhci_add_host(host);
+       if (ret)
+               goto cleanup;
+
+       return 0;
+
+cleanup:
+       sdhci_cleanup_host(host);
+
+       return ret;
 }
 EXPORT_SYMBOL_GPL(sdhci_add_host);