diff options
Diffstat (limited to 'drivers/mmc/host/sdhci.c')
-rw-r--r-- | drivers/mmc/host/sdhci.c | 448 |
1 files changed, 247 insertions, 201 deletions
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 6f0bfc0c8c9..51bbba486f3 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -53,6 +53,7 @@ static void sdhci_send_command(struct sdhci_host *, struct mmc_command *); static void sdhci_finish_command(struct sdhci_host *); static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode); static void sdhci_tuning_timer(unsigned long data); +static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable); #ifdef CONFIG_PM_RUNTIME static int sdhci_runtime_pm_get(struct sdhci_host *host); @@ -1082,6 +1083,37 @@ 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); + + switch (ctrl & SDHCI_CTRL_UHS_MASK) { + case SDHCI_CTRL_UHS_SDR12: + preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR12); + break; + case SDHCI_CTRL_UHS_SDR25: + preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR25); + break; + case SDHCI_CTRL_UHS_SDR50: + preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR50); + break; + case SDHCI_CTRL_UHS_SDR104: + preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR104); + break; + case SDHCI_CTRL_UHS_DDR50: + preset = sdhci_readw(host, SDHCI_PRESET_FOR_DDR50); + break; + default: + pr_warn("%s: Invalid UHS-I mode selected\n", + mmc_hostname(host->mmc)); + preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR12); + break; + } + return preset; +} + static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) { int div = 0; /* Initialized for compiler warning */ @@ -1106,35 +1138,43 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) goto out; if (host->version >= SDHCI_SPEC_300) { + if (sdhci_readw(host, SDHCI_HOST_CONTROL2) & + SDHCI_CTRL_PRESET_VAL_ENABLE) { + u16 pre_val; + + clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); + pre_val = sdhci_get_preset_value(host); + div = (pre_val & SDHCI_PRESET_SDCLK_FREQ_MASK) + >> SDHCI_PRESET_SDCLK_FREQ_SHIFT; + if (host->clk_mul && + (pre_val & SDHCI_PRESET_CLKGEN_SEL_MASK)) { + clk = SDHCI_PROG_CLOCK_MODE; + real_div = div + 1; + clk_mul = host->clk_mul; + } else { + real_div = max_t(int, 1, div << 1); + } + goto clock_set; + } + /* * Check if the Host Controller supports Programmable Clock * Mode. */ if (host->clk_mul) { - u16 ctrl; - + for (div = 1; div <= 1024; div++) { + if ((host->max_clk * host->clk_mul / div) + <= clock) + break; + } /* - * We need to figure out whether the Host Driver needs - * to select Programmable Clock Mode, or the value can - * be set automatically by the Host Controller based on - * the Preset Value registers. + * Set Programmable Clock Mode in the Clock + * Control register. */ - ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); - if (!(ctrl & SDHCI_CTRL_PRESET_VAL_ENABLE)) { - for (div = 1; div <= 1024; div++) { - if (((host->max_clk * host->clk_mul) / - div) <= clock) - break; - } - /* - * Set Programmable Clock Mode in the Clock - * Control register. - */ - clk = SDHCI_PROG_CLOCK_MODE; - real_div = div; - clk_mul = host->clk_mul; - div--; - } + clk = SDHCI_PROG_CLOCK_MODE; + real_div = div; + clk_mul = host->clk_mul; + div--; } else { /* Version 3.00 divisors must be a multiple of 2. */ if (host->max_clk <= clock) @@ -1159,6 +1199,7 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) div >>= 1; } +clock_set: if (real_div) host->mmc->actual_clock = (host->max_clk * clk_mul) / real_div; @@ -1189,6 +1230,15 @@ out: host->clock = 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) { u8 pwr = 0; @@ -1258,7 +1308,7 @@ static int sdhci_set_power(struct sdhci_host *host, unsigned short power) static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) { struct sdhci_host *host; - bool present; + int present; unsigned long flags; u32 tuning_opcode; @@ -1287,18 +1337,21 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) host->mrq = mrq; - /* If polling, assume that the card is always present. */ - if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) - present = true; - else - present = sdhci_readl(host, SDHCI_PRESENT_STATE) & - SDHCI_CARD_PRESENT; - - /* If we're using a cd-gpio, testing the presence bit might fail. */ - if (!present) { - int ret = mmc_gpio_get_cd(host->mmc); - if (ret > 0) - present = true; + /* + * Firstly check card presence from cd-gpio. The return could + * be one of the following possibilities: + * negative: cd-gpio is not available + * zero: cd-gpio is used, and card is removed + * one: cd-gpio is used, and card is present + */ + present = mmc_gpio_get_cd(host->mmc); + if (present < 0) { + /* If polling, assume that the card is always present. */ + if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) + present = 1; + else + present = sdhci_readl(host, SDHCI_PRESENT_STATE) & + SDHCI_CARD_PRESENT; } if (!present || host->flags & SDHCI_DEVICE_DEAD) { @@ -1364,6 +1417,10 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) sdhci_reinit(host); } + if (host->version >= SDHCI_SPEC_300 && + (ios->power_mode == MMC_POWER_UP)) + sdhci_enable_preset_value(host, false); + sdhci_set_clock(host, ios->clock); if (ios->power_mode == MMC_POWER_OFF) @@ -1383,11 +1440,11 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) /* * 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_8bit_width(). + * platform_bus_width(). */ - if (host->ops->platform_8bit_width) - host->ops->platform_8bit_width(host, ios->bus_width); - else { + 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; @@ -1415,7 +1472,6 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) if (host->version >= SDHCI_SPEC_300) { u16 clk, ctrl_2; - unsigned int clock; /* In case of UHS-I modes, set High Speed Enable */ if ((ios->timing == MMC_TIMING_MMC_HS200) || @@ -1455,9 +1511,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 */ - clock = host->clock; - host->clock = 0; - sdhci_set_clock(host, clock); + sdhci_update_clock(host); } @@ -1487,10 +1541,22 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); } + if (!(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN) && + ((ios->timing == MMC_TIMING_UHS_SDR12) || + (ios->timing == MMC_TIMING_UHS_SDR25) || + (ios->timing == MMC_TIMING_UHS_SDR50) || + (ios->timing == MMC_TIMING_UHS_SDR104) || + (ios->timing == MMC_TIMING_UHS_DDR50))) { + u16 preset; + + sdhci_enable_preset_value(host, true); + preset = sdhci_get_preset_value(host); + ios->drv_type = (preset & SDHCI_PRESET_DRV_MASK) + >> SDHCI_PRESET_DRV_SHIFT; + } + /* Re-enable SD Clock */ - clock = host->clock; - host->clock = 0; - sdhci_set_clock(host, clock); + sdhci_update_clock(host); } else sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); @@ -1608,141 +1674,91 @@ static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable) spin_unlock_irqrestore(&host->lock, flags); } -static int sdhci_do_3_3v_signal_voltage_switch(struct sdhci_host *host, - u16 ctrl) +static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host, + struct mmc_ios *ios) { + u16 ctrl; int ret; - /* Set 1.8V Signal Enable in the Host Control2 register to 0 */ - ctrl &= ~SDHCI_CTRL_VDD_180; - sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); - - if (host->vqmmc) { - ret = regulator_set_voltage(host->vqmmc, 2700000, 3600000); - if (ret) { - pr_warning("%s: Switching to 3.3V signalling voltage " - " failed\n", mmc_hostname(host->mmc)); - return -EIO; - } - } - /* Wait for 5ms */ - usleep_range(5000, 5500); + /* + * Signal Voltage Switching is only applicable for Host Controllers + * v3.00 and above. + */ + if (host->version < SDHCI_SPEC_300) + return 0; - /* 3.3V regulator output should be stable within 5 ms */ ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); - if (!(ctrl & SDHCI_CTRL_VDD_180)) - return 0; - pr_warning("%s: 3.3V regulator output did not became stable\n", - mmc_hostname(host->mmc)); + switch (ios->signal_voltage) { + case MMC_SIGNAL_VOLTAGE_330: + /* Set 1.8V Signal Enable in the Host Control2 register to 0 */ + ctrl &= ~SDHCI_CTRL_VDD_180; + sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); - return -EIO; -} + if (host->vqmmc) { + ret = regulator_set_voltage(host->vqmmc, 2700000, 3600000); + if (ret) { + pr_warning("%s: Switching to 3.3V signalling voltage " + " failed\n", mmc_hostname(host->mmc)); + return -EIO; + } + } + /* Wait for 5ms */ + usleep_range(5000, 5500); -static int sdhci_do_1_8v_signal_voltage_switch(struct sdhci_host *host, - u16 ctrl) -{ - u8 pwr; - u16 clk; - u32 present_state; - int ret; + /* 3.3V regulator output should be stable within 5 ms */ + ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); + if (!(ctrl & SDHCI_CTRL_VDD_180)) + return 0; - /* Stop SDCLK */ - clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); - clk &= ~SDHCI_CLOCK_CARD_EN; - sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); + pr_warning("%s: 3.3V regulator output did not became stable\n", + mmc_hostname(host->mmc)); + + return -EAGAIN; + case MMC_SIGNAL_VOLTAGE_180: + if (host->vqmmc) { + ret = regulator_set_voltage(host->vqmmc, + 1700000, 1950000); + if (ret) { + pr_warning("%s: Switching to 1.8V signalling voltage " + " failed\n", mmc_hostname(host->mmc)); + return -EIO; + } + } - /* Check whether DAT[3:0] is 0000 */ - present_state = sdhci_readl(host, SDHCI_PRESENT_STATE); - if (!((present_state & SDHCI_DATA_LVL_MASK) >> - SDHCI_DATA_LVL_SHIFT)) { /* * Enable 1.8V Signal Enable in the Host Control2 * register */ - if (host->vqmmc) - ret = regulator_set_voltage(host->vqmmc, - 1700000, 1950000); - else - ret = 0; + ctrl |= SDHCI_CTRL_VDD_180; + sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); - if (!ret) { - ctrl |= SDHCI_CTRL_VDD_180; - sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); + /* Wait for 5ms */ + usleep_range(5000, 5500); - /* Wait for 5ms */ - usleep_range(5000, 5500); + /* 1.8V regulator output should be stable within 5 ms */ + ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); + if (ctrl & SDHCI_CTRL_VDD_180) + return 0; - ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); - if (ctrl & SDHCI_CTRL_VDD_180) { - /* Provide SDCLK again and wait for 1ms */ - clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); - clk |= SDHCI_CLOCK_CARD_EN; - sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); - usleep_range(1000, 1500); + pr_warning("%s: 1.8V regulator output did not became stable\n", + mmc_hostname(host->mmc)); - /* - * If DAT[3:0] level is 1111b, then the card - * was successfully switched to 1.8V signaling. - */ - present_state = sdhci_readl(host, - SDHCI_PRESENT_STATE); - if ((present_state & SDHCI_DATA_LVL_MASK) == - SDHCI_DATA_LVL_MASK) - return 0; + return -EAGAIN; + case MMC_SIGNAL_VOLTAGE_120: + if (host->vqmmc) { + ret = regulator_set_voltage(host->vqmmc, 1100000, 1300000); + if (ret) { + pr_warning("%s: Switching to 1.2V signalling voltage " + " failed\n", mmc_hostname(host->mmc)); + return -EIO; } } - } - - /* - * If we are here, that means the switch to 1.8V signaling - * failed. We power cycle the card, and retry initialization - * sequence by setting S18R to 0. - */ - pwr = sdhci_readb(host, SDHCI_POWER_CONTROL); - pwr &= ~SDHCI_POWER_ON; - sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL); - if (host->vmmc) - regulator_disable(host->vmmc); - - /* Wait for 1ms as per the spec */ - usleep_range(1000, 1500); - pwr |= SDHCI_POWER_ON; - sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL); - if (host->vmmc) - regulator_enable(host->vmmc); - - pr_warning("%s: Switching to 1.8V signalling voltage failed, " - "retrying with S18R set to 0\n", mmc_hostname(host->mmc)); - - return -EAGAIN; -} - -static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host, - struct mmc_ios *ios) -{ - u16 ctrl; - - /* - * Signal Voltage Switching is only applicable for Host Controllers - * v3.00 and above. - */ - if (host->version < SDHCI_SPEC_300) return 0; - - /* - * We first check whether the request is to set signalling voltage - * to 3.3V. If so, we change the voltage to 3.3V and return quickly. - */ - ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); - if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) - return sdhci_do_3_3v_signal_voltage_switch(host, ctrl); - else if (!(ctrl & SDHCI_CTRL_VDD_180) && - (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180)) - return sdhci_do_1_8v_signal_voltage_switch(host, ctrl); - else + default: /* No signal voltage switch required */ return 0; + } } static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, @@ -1759,6 +1775,19 @@ static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, return err; } +static int sdhci_card_busy(struct mmc_host *mmc) +{ + struct sdhci_host *host = mmc_priv(mmc); + u32 present_state; + + sdhci_runtime_pm_get(host); + /* Check whether DAT[3:0] is 0000 */ + present_state = sdhci_readl(host, SDHCI_PRESENT_STATE); + sdhci_runtime_pm_put(host); + + return !(present_state & SDHCI_DATA_LVL_MASK); +} + static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) { struct sdhci_host *host; @@ -1955,17 +1984,15 @@ out: return err; } -static void sdhci_do_enable_preset_value(struct sdhci_host *host, bool enable) + +static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable) { u16 ctrl; - unsigned long flags; /* Host Controller v3.00 defines preset value registers */ if (host->version < SDHCI_SPEC_300) return; - spin_lock_irqsave(&host->lock, flags); - ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); /* @@ -1981,17 +2008,6 @@ static void sdhci_do_enable_preset_value(struct sdhci_host *host, bool enable) sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); host->flags &= ~SDHCI_PV_ENABLED; } - - spin_unlock_irqrestore(&host->lock, flags); -} - -static void sdhci_enable_preset_value(struct mmc_host *mmc, bool enable) -{ - struct sdhci_host *host = mmc_priv(mmc); - - sdhci_runtime_pm_get(host); - sdhci_do_enable_preset_value(host, enable); - sdhci_runtime_pm_put(host); } static void sdhci_card_event(struct mmc_host *mmc) @@ -2027,8 +2043,8 @@ static const struct mmc_host_ops sdhci_ops = { .enable_sdio_irq = sdhci_enable_sdio_irq, .start_signal_voltage_switch = sdhci_start_signal_voltage_switch, .execute_tuning = sdhci_execute_tuning, - .enable_preset_value = sdhci_enable_preset_value, .card_event = sdhci_card_event, + .card_busy = sdhci_card_busy, }; /*****************************************************************************\ @@ -2080,14 +2096,9 @@ static void sdhci_tasklet_finish(unsigned long param) (host->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST))) { /* Some controllers need this kick or reset won't work here */ - if (host->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET) { - unsigned int clock; - + if (host->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET) /* This is to force an update */ - clock = host->clock; - host->clock = 0; - sdhci_set_clock(host, clock); - } + sdhci_update_clock(host); /* Spec says we should do both at the same time, but Ricoh controllers do not like that. */ @@ -2455,6 +2466,32 @@ out: \*****************************************************************************/ #ifdef CONFIG_PM +void sdhci_enable_irq_wakeups(struct sdhci_host *host) +{ + u8 val; + u8 mask = SDHCI_WAKE_ON_INSERT | SDHCI_WAKE_ON_REMOVE + | SDHCI_WAKE_ON_INT; + + val = sdhci_readb(host, SDHCI_WAKE_UP_CONTROL); + val |= mask ; + /* Avoid fake wake up */ + if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) + val &= ~(SDHCI_WAKE_ON_INSERT | SDHCI_WAKE_ON_REMOVE); + sdhci_writeb(host, val, SDHCI_WAKE_UP_CONTROL); +} +EXPORT_SYMBOL_GPL(sdhci_enable_irq_wakeups); + +void sdhci_disable_irq_wakeups(struct sdhci_host *host) +{ + u8 val; + u8 mask = SDHCI_WAKE_ON_INSERT | SDHCI_WAKE_ON_REMOVE + | SDHCI_WAKE_ON_INT; + + val = sdhci_readb(host, SDHCI_WAKE_UP_CONTROL); + val &= ~mask; + sdhci_writeb(host, val, SDHCI_WAKE_UP_CONTROL); +} +EXPORT_SYMBOL_GPL(sdhci_disable_irq_wakeups); int sdhci_suspend_host(struct sdhci_host *host) { @@ -2484,8 +2521,13 @@ int sdhci_suspend_host(struct sdhci_host *host) return ret; } - free_irq(host->irq, host); - + if (!device_may_wakeup(mmc_dev(host->mmc))) { + sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK); + free_irq(host->irq, host); + } else { + sdhci_enable_irq_wakeups(host); + enable_irq_wake(host->irq); + } return ret; } @@ -2500,10 +2542,15 @@ int sdhci_resume_host(struct sdhci_host *host) host->ops->enable_dma(host); } - ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED, - mmc_hostname(host->mmc), host); - if (ret) - return ret; + if (!device_may_wakeup(mmc_dev(host->mmc))) { + ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED, + mmc_hostname(host->mmc), host); + if (ret) + return ret; + } else { + sdhci_disable_irq_wakeups(host); + disable_irq_wake(host->irq); + } if ((host->mmc->pm_flags & MMC_PM_KEEP_POWER) && (host->quirks2 & SDHCI_QUIRK2_HOST_OFF_CARD_ON)) { @@ -2531,17 +2578,6 @@ int sdhci_resume_host(struct sdhci_host *host) } EXPORT_SYMBOL_GPL(sdhci_resume_host); - -void sdhci_enable_irq_wakeups(struct sdhci_host *host) -{ - u8 val; - val = sdhci_readb(host, SDHCI_WAKE_UP_CONTROL); - val |= SDHCI_WAKE_ON_INT; - sdhci_writeb(host, val, SDHCI_WAKE_UP_CONTROL); -} - -EXPORT_SYMBOL_GPL(sdhci_enable_irq_wakeups); - #endif /* CONFIG_PM */ #ifdef CONFIG_PM_RUNTIME @@ -2600,8 +2636,12 @@ int sdhci_runtime_resume_host(struct sdhci_host *host) sdhci_do_set_ios(host, &host->mmc->ios); sdhci_do_start_signal_voltage_switch(host, &host->mmc->ios); - if (host_flags & SDHCI_PV_ENABLED) - sdhci_do_enable_preset_value(host, true); + if ((host_flags & SDHCI_PV_ENABLED) && + !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN)) { + spin_lock_irqsave(&host->lock, flags); + sdhci_enable_preset_value(host, true); + spin_unlock_irqrestore(&host->lock, flags); + } /* Set the re-tuning expiration flag */ if (host->flags & SDHCI_USING_RETUNING_TIMER) @@ -2936,7 +2976,11 @@ int sdhci_add_host(struct sdhci_host *host) } #ifdef CONFIG_REGULATOR - if (host->vmmc) { + /* + * Voltage range check makes sense only if regulator reports + * any voltage value. + */ + if (host->vmmc && regulator_get_voltage(host->vmmc) > 0) { ret = regulator_is_supported_voltage(host->vmmc, 2700000, 3600000); if ((ret <= 0) || (!(caps[0] & SDHCI_CAN_VDD_330))) @@ -3139,6 +3183,7 @@ 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); free_irq(host->irq, host); #endif untasklet: @@ -3181,6 +3226,7 @@ void sdhci_remove_host(struct sdhci_host *host, int dead) if (!dead) sdhci_reset(host, SDHCI_RESET_ALL); + sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK); free_irq(host->irq, host); del_timer_sync(&host->timer); |