]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/mmc/host/sdhci.c
KARO: cleanup after merge of Freescale 3.10.17 stuff
[karo-tx-linux.git] / drivers / mmc / host / sdhci.c
index 9a79fc4b60ca82bb7319fa34a3ae2d79d093833e..47055f3f01b8580e01ff147232d106bc14db3667 100644 (file)
@@ -44,6 +44,8 @@
 
 #define MAX_TUNING_LOOP 40
 
+#define ADMA_SIZE      ((128 * 2 + 1) * 4)
+
 static unsigned int debug_quirks = 0;
 static unsigned int debug_quirks2;
 
@@ -131,43 +133,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 +165,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,16 +192,27 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask)
                timeout--;
                mdelay(1);
        }
+}
+EXPORT_SYMBOL_GPL(sdhci_reset);
+
+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->ops->platform_reset_exit)
-               host->ops->platform_reset_exit(host, mask);
+       host->ops->reset(host, mask);
 
-       if (host->quirks & SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET)
-               sdhci_clear_set_irqs(host, SDHCI_INT_ALL_MASK, ier);
+       if (mask & SDHCI_RESET_ALL) {
+               if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
+                       if (host->ops->enable_dma)
+                               host->ops->enable_dma(host);
+               }
 
-       if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
-               if ((host->ops->enable_dma) && (mask & SDHCI_RESET_ALL))
-                       host->ops->enable_dma(host);
+               /* Resetting the controller clears many */
+               host->preset_enabled = false;
        }
 }
 
@@ -238,15 +221,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 */
@@ -502,11 +488,6 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
        else
                direction = DMA_TO_DEVICE;
 
-       /*
-        * The ADMA descriptor table is mapped further down as we
-        * need to fill it with data first.
-        */
-
        host->align_addr = dma_map_single(mmc_dev(host->mmc),
                host->align_buffer, 128 * 4, direction);
        if (dma_mapping_error(mmc_dev(host->mmc), host->align_addr))
@@ -567,7 +548,7 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
                 * If this triggers then we have a calculation bug
                 * somewhere. :/
                 */
-               WARN_ON((desc - host->adma_desc) > (128 * 2 + 1) * 4);
+               WARN_ON((desc - host->adma_desc) > ADMA_SIZE);
        }
 
        if (host->quirks & SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC) {
@@ -595,17 +576,8 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
                        host->align_addr, 128 * 4, direction);
        }
 
-       host->adma_addr = dma_map_single(mmc_dev(host->mmc),
-               host->adma_desc, (128 * 2 + 1) * 4, DMA_TO_DEVICE);
-       if (dma_mapping_error(mmc_dev(host->mmc), host->adma_addr))
-               goto unmap_entries;
-       BUG_ON(host->adma_addr & 0x3);
-
        return 0;
 
-unmap_entries:
-       dma_unmap_sg(mmc_dev(host->mmc), data->sg,
-               data->sg_len, direction);
 unmap_align:
        dma_unmap_single(mmc_dev(host->mmc), host->align_addr,
                128 * 4, direction);
@@ -623,19 +595,25 @@ static void sdhci_adma_table_post(struct sdhci_host *host,
        u8 *align;
        char *buffer;
        unsigned long flags;
+       bool has_unaligned;
 
        if (data->flags & MMC_DATA_READ)
                direction = DMA_FROM_DEVICE;
        else
                direction = DMA_TO_DEVICE;
 
-       dma_unmap_single(mmc_dev(host->mmc), host->adma_addr,
-               (128 * 2 + 1) * 4, DMA_TO_DEVICE);
-
        dma_unmap_single(mmc_dev(host->mmc), host->align_addr,
                128 * 4, direction);
 
-       if (data->flags & MMC_DATA_READ) {
+       /* Do a quick scan of the SG list for any unaligned mappings */
+       has_unaligned = false;
+       for_each_sg(data->sg, sg, host->sg_count, i)
+               if (sg_dma_address(sg) & 3) {
+                       has_unaligned = true;
+                       break;
+               }
+
+       if (has_unaligned && data->flags & MMC_DATA_READ) {
                dma_sync_sg_for_cpu(mmc_dev(host->mmc), data->sg,
                        data->sg_len, direction);
 
@@ -721,9 +699,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 +957,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);
@@ -1107,24 +1088,23 @@ static void sdhci_finish_command(struct sdhci_host *host)
 
 static u16 sdhci_get_preset_value(struct sdhci_host *host)
 {
-       u16 ctrl, preset = 0;
-
-       ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+       u16 preset = 0;
 
-       switch (ctrl & SDHCI_CTRL_UHS_MASK) {
-       case SDHCI_CTRL_UHS_SDR12:
+       switch (host->timing) {
+       case MMC_TIMING_UHS_SDR12:
                preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR12);
                break;
-       case SDHCI_CTRL_UHS_SDR25:
+       case MMC_TIMING_UHS_SDR25:
                preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR25);
                break;
-       case SDHCI_CTRL_UHS_SDR50:
+       case MMC_TIMING_UHS_SDR50:
                preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR50);
                break;
-       case SDHCI_CTRL_UHS_SDR104:
+       case MMC_TIMING_UHS_SDR104:
+       case MMC_TIMING_MMC_HS200:
                preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR104);
                break;
-       case SDHCI_CTRL_UHS_DDR50:
+       case MMC_TIMING_UHS_DDR50:
                preset = sdhci_readw(host, SDHCI_PRESET_FOR_DDR50);
                break;
        default:
@@ -1136,32 +1116,22 @@ static u16 sdhci_get_preset_value(struct sdhci_host *host)
        return preset;
 }
 
-static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
+void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
 {
        int div = 0; /* Initialized for compiler warning */
        int real_div = div, clk_mul = 1;
        u16 clk = 0;
        unsigned long timeout;
 
-       if (clock && clock == host->clock)
-               return;
-
        host->mmc->actual_clock = 0;
 
-       if (host->ops->set_clock) {
-               host->ops->set_clock(host, clock);
-               if (host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK)
-                       return;
-       }
-
        sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
 
        if (clock == 0)
-               goto out;
+               return;
 
        if (host->version >= SDHCI_SPEC_300) {
-               if (sdhci_readw(host, SDHCI_HOST_CONTROL2) &
-                       SDHCI_CTRL_PRESET_VAL_ENABLE) {
+               if (host->preset_enabled) {
                        u16 pre_val;
 
                        clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
@@ -1247,26 +1217,16 @@ clock_set:
 
        clk |= SDHCI_CLOCK_CARD_EN;
        sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
-
-out:
-       host->clock = clock;
 }
+EXPORT_SYMBOL_GPL(sdhci_set_clock);
 
-static inline void sdhci_update_clock(struct sdhci_host *host)
-{
-       unsigned int clock;
-
-       clock = host->clock;
-       host->clock = 0;
-       sdhci_set_clock(host, clock);
-}
-
-static int sdhci_set_power(struct sdhci_host *host, unsigned short power)
+static void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
+                           unsigned short vdd)
 {
        u8 pwr = 0;
 
-       if (power != (unsigned short)-1) {
-               switch (1 << power) {
+       if (mode != MMC_POWER_OFF) {
+               switch (1 << vdd) {
                case MMC_VDD_165_195:
                        pwr = SDHCI_POWER_180;
                        break;
@@ -1284,7 +1244,7 @@ static int sdhci_set_power(struct sdhci_host *host, unsigned short power)
        }
 
        if (host->pwr == pwr)
-               return -1;
+               return;
 
        host->pwr = pwr;
 
@@ -1292,38 +1252,43 @@ static int sdhci_set_power(struct sdhci_host *host, unsigned short power)
                sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
                if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON)
                        sdhci_runtime_pm_bus_off(host);
-               return 0;
-       }
-
-       /*
-        * Spec says that we should clear the power reg before setting
-        * a new value. Some controllers don't seem to like this though.
-        */
-       if (!(host->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE))
-               sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
+               vdd = 0;
+       } else {
+               /*
+                * Spec says that we should clear the power reg before setting
+                * a new value. Some controllers don't seem to like this though.
+                */
+               if (!(host->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE))
+                       sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
 
-       /*
-        * At least the Marvell CaFe chip gets confused if we set the voltage
-        * and set turn on power at the same time, so set the voltage first.
-        */
-       if (host->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER)
-               sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
+               /*
+                * At least the Marvell CaFe chip gets confused if we set the
+                * voltage and set turn on power at the same time, so set the
+                * voltage first.
+                */
+               if (host->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER)
+                       sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
 
-       pwr |= SDHCI_POWER_ON;
+               pwr |= SDHCI_POWER_ON;
 
-       sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
+               sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
 
-       if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON)
-               sdhci_runtime_pm_bus_on(host);
+               if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON)
+                       sdhci_runtime_pm_bus_on(host);
 
-       /*
-        * Some controllers need an extra 10ms delay of 10ms before they
-        * can apply clock after applying power
-        */
-       if (host->quirks & SDHCI_QUIRK_DELAY_AFTER_POWER)
-               mdelay(10);
+               /*
+                * Some controllers need an extra 10ms delay of 10ms before
+                * they can apply clock after applying power
+                */
+               if (host->quirks & SDHCI_QUIRK_DELAY_AFTER_POWER)
+                       mdelay(10);
+       }
 
-       return power;
+       if (host->vmmc) {
+               spin_unlock_irq(&host->lock);
+               mmc_regulator_set_ocr(host->mmc, host->vmmc, vdd);
+               spin_lock_irq(&host->lock);
+       }
 }
 
 /*****************************************************************************\
@@ -1427,10 +1392,53 @@ 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);
+
+void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
+{
+       u16 ctrl_2;
+
+       ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+       /* Select Bus Speed Mode for host */
+       ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
+       if ((timing == MMC_TIMING_MMC_HS200) ||
+           (timing == MMC_TIMING_UHS_SDR104))
+               ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
+       else if (timing == MMC_TIMING_UHS_SDR12)
+               ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
+       else if (timing == MMC_TIMING_UHS_SDR25)
+               ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
+       else if (timing == MMC_TIMING_UHS_SDR50)
+               ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
+       else if ((timing == MMC_TIMING_UHS_DDR50) ||
+                (timing == MMC_TIMING_MMC_DDR52))
+               ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
+       sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
+}
+EXPORT_SYMBOL_GPL(sdhci_set_uhs_signaling);
+
 static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
 {
        unsigned long flags;
-       int vdd_bit = -1;
        u8 ctrl;
 
        spin_lock_irqsave(&host->lock, flags);
@@ -1456,45 +1464,17 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
                !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN))
                sdhci_enable_preset_value(host, false);
 
-       sdhci_set_clock(host, ios->clock);
-
-       if (ios->power_mode == MMC_POWER_OFF)
-               vdd_bit = sdhci_set_power(host, -1);
-       else
-               vdd_bit = sdhci_set_power(host, ios->vdd);
-
-       if (host->vmmc && vdd_bit != -1) {
-               spin_unlock_irqrestore(&host->lock, flags);
-               mmc_regulator_set_ocr(host->mmc, host->vmmc, vdd_bit);
-               spin_lock_irqsave(&host->lock, flags);
+       if (!ios->clock || ios->clock != host->clock) {
+               host->ops->set_clock(host, ios->clock);
+               host->clock = ios->clock;
        }
 
+       sdhci_set_power(host, ios->power_mode, ios->vdd);
+
        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,19 +1490,20 @@ 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) ||
                    (ios->timing == MMC_TIMING_UHS_SDR25))
                        ctrl |= SDHCI_CTRL_HISPD;
 
-               ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
-               if (!(ctrl_2 & SDHCI_CTRL_PRESET_VAL_ENABLE)) {
+               if (!host->preset_enabled) {
                        sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
                        /*
                         * We only need to set Driver Strength if the
                         * preset value enable is not set.
                         */
+                       ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
                        ctrl_2 &= ~SDHCI_CTRL_DRV_TYPE_MASK;
                        if (ios->drv_type == MMC_SET_DRIVER_TYPE_A)
                                ctrl_2 |= SDHCI_CTRL_DRV_TYPE_A;
@@ -1546,7 +1527,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
                        sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
 
                        /* Re-enable SD Clock */
-                       sdhci_update_clock(host);
+                       host->ops->set_clock(host, host->clock);
                }
 
 
@@ -1555,25 +1536,8 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
                clk &= ~SDHCI_CLOCK_CARD_EN;
                sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
 
-               if (host->ops->set_uhs_signaling)
-                       host->ops->set_uhs_signaling(host, ios->timing);
-               else {
-                       ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
-                       /* Select Bus Speed Mode for host */
-                       ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
-                       if ((ios->timing == MMC_TIMING_MMC_HS200) ||
-                           (ios->timing == MMC_TIMING_UHS_SDR104))
-                               ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
-                       else if (ios->timing == MMC_TIMING_UHS_SDR12)
-                               ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
-                       else if (ios->timing == MMC_TIMING_UHS_SDR25)
-                               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)
-                               ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
-                       sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
-               }
+               host->ops->set_uhs_signaling(host, ios->timing);
+               host->timing = ios->timing;
 
                if (!(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN) &&
                                ((ios->timing == MMC_TIMING_UHS_SDR12) ||
@@ -1590,7 +1554,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
                }
 
                /* Re-enable SD Clock */
-               sdhci_update_clock(host);
+               host->ops->set_clock(host, host->clock);
        } else
                sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
 
@@ -1600,7 +1564,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 +1673,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 +1690,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,
@@ -1855,22 +1820,15 @@ static int sdhci_card_busy(struct mmc_host *mmc)
 
 static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
 {
-       struct sdhci_host *host;
+       struct sdhci_host *host = mmc_priv(mmc);
        u16 ctrl;
-       u32 ier;
        int tuning_loop_counter = MAX_TUNING_LOOP;
-       unsigned long timeout;
        int err = 0;
-       bool requires_tuning_nonuhs = false;
        unsigned long flags;
 
-       host = mmc_priv(mmc);
-
        sdhci_runtime_pm_get(host);
        spin_lock_irqsave(&host->lock, flags);
 
-       ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
-
        /*
         * The Host Controller needs tuning only in case of SDR104 mode
         * and for SDR50 mode when Use Tuning for SDR50 is set in the
@@ -1878,15 +1836,18 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
         * If the Host Controller supports the HS200 mode then the
         * tuning function has to be executed.
         */
-       if (((ctrl & SDHCI_CTRL_UHS_MASK) == SDHCI_CTRL_UHS_SDR50) &&
-           (host->flags & SDHCI_SDR50_NEEDS_TUNING ||
-            host->flags & SDHCI_SDR104_NEEDS_TUNING))
-               requires_tuning_nonuhs = true;
-
-       if (((ctrl & SDHCI_CTRL_UHS_MASK) == SDHCI_CTRL_UHS_SDR104) ||
-           requires_tuning_nonuhs)
-               ctrl |= SDHCI_CTRL_EXEC_TUNING;
-       else {
+       switch (host->timing) {
+       case MMC_TIMING_MMC_HS200:
+       case MMC_TIMING_UHS_SDR104:
+               break;
+
+       case MMC_TIMING_UHS_SDR50:
+               if (host->flags & SDHCI_SDR50_NEEDS_TUNING ||
+                   host->flags & SDHCI_SDR104_NEEDS_TUNING)
+                       break;
+               /* FALLTHROUGH */
+
+       default:
                spin_unlock_irqrestore(&host->lock, flags);
                sdhci_runtime_pm_put(host);
                return 0;
@@ -1899,6 +1860,8 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
                return err;
        }
 
+       ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+       ctrl |= SDHCI_CTRL_EXEC_TUNING;
        sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
 
        /*
@@ -1911,21 +1874,17 @@ 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
         * of loops reaches 40 times or a timeout of 150ms occurs.
         */
-       timeout = 150;
        do {
                struct mmc_command cmd = {0};
                struct mmc_request mrq = {NULL};
 
-               if (!tuning_loop_counter && !timeout)
-                       break;
-
                cmd.opcode = opcode;
                cmd.arg = 0;
                cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
@@ -1933,6 +1892,9 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
                cmd.data = NULL;
                cmd.error = 0;
 
+               if (tuning_loop_counter-- == 0)
+                       break;
+
                mrq.cmd = &cmd;
                host->mrq = &mrq;
 
@@ -1990,26 +1952,25 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
                host->tuning_done = 0;
 
                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);
 
        /*
         * The Host Driver has exhausted the maximum number of loops allowed,
         * so use fixed sampling frequency.
         */
-       if (!tuning_loop_counter || !timeout) {
+       if (tuning_loop_counter < 0) {
                ctrl &= ~SDHCI_CTRL_TUNED_CLK;
                sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
+       }
+       if (!(ctrl & SDHCI_CTRL_TUNED_CLK)) {
+               pr_info(DRIVER_NAME ": Tuning procedure"
+                       " failed, falling back to fixed sampling"
+                       " clock\n");
                err = -EIO;
-       } else {
-               if (!(ctrl & SDHCI_CTRL_TUNED_CLK)) {
-                       pr_info(DRIVER_NAME ": Tuning procedure"
-                               " failed, falling back to fixed sampling"
-                               " clock\n");
-                       err = -EIO;
-               }
        }
 
 out:
@@ -2044,7 +2005,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);
 
@@ -2054,26 +2016,30 @@ out:
 
 static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable)
 {
-       u16 ctrl;
-
        /* Host Controller v3.00 defines preset value registers */
        if (host->version < SDHCI_SPEC_300)
                return;
 
-       ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
-
        /*
         * We only enable or disable Preset Value if they are not already
         * enabled or disabled respectively. Otherwise, we bail out.
         */
-       if (enable && !(ctrl & SDHCI_CTRL_PRESET_VAL_ENABLE)) {
-               ctrl |= SDHCI_CTRL_PRESET_VAL_ENABLE;
-               sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
-               host->flags |= SDHCI_PV_ENABLED;
-       } else if (!enable && (ctrl & SDHCI_CTRL_PRESET_VAL_ENABLE)) {
-               ctrl &= ~SDHCI_CTRL_PRESET_VAL_ENABLE;
+       if (host->preset_enabled != enable) {
+               u16 ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+
+               if (enable)
+                       ctrl |= SDHCI_CTRL_PRESET_VAL_ENABLE;
+               else
+                       ctrl &= ~SDHCI_CTRL_PRESET_VAL_ENABLE;
+
                sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
-               host->flags &= ~SDHCI_PV_ENABLED;
+
+               if (enable)
+                       host->flags |= SDHCI_PV_ENABLED;
+               else
+                       host->flags &= ~SDHCI_PV_ENABLED;
+
+               host->preset_enabled = enable;
        }
 }
 
@@ -2095,8 +2061,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);
@@ -2124,15 +2090,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;
@@ -2169,12 +2126,12 @@ static void sdhci_tasklet_finish(unsigned long param)
                /* Some controllers need this kick or reset won't work here */
                if (host->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET)
                        /* This is to force an update */
-                       sdhci_update_clock(host);
+                       host->ops->set_clock(host, host->clock);
 
                /* 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;
@@ -2424,101 +2381,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);
                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);
 
@@ -2527,15 +2477,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                                                            *
@@ -2572,9 +2545,6 @@ EXPORT_SYMBOL_GPL(sdhci_disable_irq_wakeups);
 
 int sdhci_suspend_host(struct sdhci_host *host)
 {
-       if (host->ops->platform_suspend)
-               host->ops->platform_suspend(host);
-
        sdhci_disable_card_detection(host);
 
        /* Disable tuning since we are suspending */
@@ -2584,7 +2554,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);
@@ -2605,8 +2577,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 {
@@ -2628,9 +2601,6 @@ int sdhci_resume_host(struct sdhci_host *host)
 
        sdhci_enable_card_detection(host);
 
-       if (host->ops->platform_resume)
-               host->ops->platform_resume(host);
-
        /* Set the re-tuning expiration flag */
        if (host->flags & SDHCI_USING_RETUNING_TIMER)
                host->flags |= SDHCI_NEEDS_RETUNING;
@@ -2682,10 +2652,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;
@@ -2729,7 +2701,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 */
@@ -2788,7 +2760,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)
@@ -2848,15 +2820,29 @@ int sdhci_add_host(struct sdhci_host *host)
                 * (128) and potentially one alignment transfer for
                 * each of those entries.
                 */
-               host->adma_desc = kmalloc((128 * 2 + 1) * 4, GFP_KERNEL);
+               host->adma_desc = dma_alloc_coherent(mmc_dev(host->mmc),
+                                                    ADMA_SIZE, &host->adma_addr,
+                                                    GFP_KERNEL);
                host->align_buffer = kmalloc(128 * 4, GFP_KERNEL);
                if (!host->adma_desc || !host->align_buffer) {
-                       kfree(host->adma_desc);
+                       dma_free_coherent(mmc_dev(host->mmc), ADMA_SIZE,
+                                         host->adma_desc, host->adma_addr);
                        kfree(host->align_buffer);
                        pr_warning("%s: Unable to allocate ADMA "
                                "buffers. Falling back to standard DMA.\n",
                                mmc_hostname(mmc));
                        host->flags &= ~SDHCI_USE_ADMA;
+                       host->adma_desc = NULL;
+                       host->align_buffer = NULL;
+               } else if (host->adma_addr & 3) {
+                       pr_warning("%s: unable to allocate aligned ADMA descriptor\n",
+                                  mmc_hostname(mmc));
+                       host->flags &= ~SDHCI_USE_ADMA;
+                       dma_free_coherent(mmc_dev(host->mmc), ADMA_SIZE,
+                                         host->adma_desc, host->adma_addr);
+                       kfree(host->align_buffer);
+                       host->adma_desc = NULL;
+                       host->align_buffer = NULL;
                }
        }
 
@@ -2941,6 +2927,7 @@ int sdhci_add_host(struct sdhci_host *host)
        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;
@@ -3212,8 +3199,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);
 
@@ -3230,8 +3215,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);
@@ -3273,12 +3258,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;
@@ -3315,14 +3300,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) {
@@ -3335,7 +3320,9 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
                regulator_put(host->vqmmc);
        }
 
-       kfree(host->adma_desc);
+       if (host->adma_desc)
+               dma_free_coherent(mmc_dev(host->mmc), ADMA_SIZE,
+                                 host->adma_desc, host->adma_addr);
        kfree(host->align_buffer);
 
        host->adma_desc = NULL;