diff options
Diffstat (limited to 'drivers/mmc/host/sdhci.c')
-rw-r--r-- | drivers/mmc/host/sdhci.c | 54 |
1 files changed, 42 insertions, 12 deletions
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 63db84481dff..e368f2dabf20 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -9,6 +9,7 @@ * - JMicron (hardware and technical support) */ +#include <linux/bitfield.h> #include <linux/delay.h> #include <linux/dmaengine.h> #include <linux/ktime.h> @@ -153,7 +154,7 @@ static void sdhci_set_card_detection(struct sdhci_host *host, bool enable) u32 present; if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) || - !mmc_card_is_removable(host->mmc)) + !mmc_card_is_removable(host->mmc) || mmc_can_gpio_cd(host->mmc)) return; if (enable) { @@ -1766,10 +1767,9 @@ u16 sdhci_calc_clk(struct sdhci_host *host, unsigned int clock, 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; + div = FIELD_GET(SDHCI_PRESET_SDCLK_FREQ_MASK, pre_val); if (host->clk_mul && - (pre_val & SDHCI_PRESET_CLKGEN_SEL_MASK)) { + (pre_val & SDHCI_PRESET_CLKGEN_SEL)) { clk = SDHCI_PROG_CLOCK_MODE; real_div = div + 1; clk_mul = host->clk_mul; @@ -2010,6 +2010,25 @@ void sdhci_set_power(struct sdhci_host *host, unsigned char mode, } EXPORT_SYMBOL_GPL(sdhci_set_power); +/* + * Some controllers need to configure a valid bus voltage on their power + * register regardless of whether an external regulator is taking care of power + * supply. This helper function takes care of it if set as the controller's + * sdhci_ops.set_power callback. + */ +void sdhci_set_power_and_bus_voltage(struct sdhci_host *host, + unsigned char mode, + unsigned short vdd) +{ + if (!IS_ERR(host->mmc->supply.vmmc)) { + struct mmc_host *mmc = host->mmc; + + mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd); + } + sdhci_set_power_noreg(host, mode, vdd); +} +EXPORT_SYMBOL_GPL(sdhci_set_power_and_bus_voltage); + /*****************************************************************************\ * * * MMC callbacks * @@ -2227,8 +2246,8 @@ void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) sdhci_enable_preset_value(host, true); preset = sdhci_get_preset_value(host); - ios->drv_type = (preset & SDHCI_PRESET_DRV_MASK) - >> SDHCI_PRESET_DRV_SHIFT; + ios->drv_type = FIELD_GET(SDHCI_PRESET_DRV_MASK, + preset); } /* Re-enable SD Clock */ @@ -2944,7 +2963,10 @@ static bool sdhci_request_done(struct sdhci_host *host) spin_unlock_irqrestore(&host->lock, flags); - mmc_request_done(host->mmc, mrq); + if (host->ops->request_done) + host->ops->request_done(host, mrq); + else + mmc_request_done(host->mmc, mrq); return false; } @@ -3247,7 +3269,7 @@ static inline bool sdhci_defer_done(struct sdhci_host *host, { struct mmc_data *data = mrq->data; - return host->pending_reset || + return host->pending_reset || host->always_defer_done || ((host->flags & SDHCI_REQ_USE_DMA) && data && data->host_cookie == COOKIE_MAPPED); } @@ -3372,7 +3394,12 @@ out: /* Process mrqs ready for immediate completion */ for (i = 0; i < SDHCI_MAX_MRQS; i++) { - if (mrqs_done[i]) + if (!mrqs_done[i]) + continue; + + if (host->ops->request_done) + host->ops->request_done(host, mrqs_done[i]); + else mmc_request_done(host->mmc, mrqs_done[i]); } @@ -3973,9 +4000,6 @@ int sdhci_setup_host(struct sdhci_host *host) mmc_hostname(mmc), host->version); } - if (host->quirks & SDHCI_QUIRK_BROKEN_CQE) - mmc->caps2 &= ~MMC_CAP2_CQE; - if (host->quirks & SDHCI_QUIRK_FORCE_DMA) host->flags |= SDHCI_USE_SDMA; else if (!(host->caps & SDHCI_CAN_DO_SDMA)) @@ -4512,6 +4536,12 @@ int __sdhci_add_host(struct sdhci_host *host) struct mmc_host *mmc = host->mmc; int ret; + if ((mmc->caps2 & MMC_CAP2_CQE) && + (host->quirks & SDHCI_QUIRK_BROKEN_CQE)) { + mmc->caps2 &= ~MMC_CAP2_CQE; + mmc->cqe_ops = NULL; + } + host->complete_wq = alloc_workqueue("sdhci", flags, 0); if (!host->complete_wq) return -ENOMEM; |