diff options
Diffstat (limited to 'drivers/mmc/host/sdhci.c')
-rw-r--r-- | drivers/mmc/host/sdhci.c | 198 |
1 files changed, 158 insertions, 40 deletions
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 0e02cc1df12e..5b0e1196dd97 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -25,6 +25,7 @@ #include <linux/mmc/mmc.h> #include <linux/mmc/host.h> +#include <linux/mmc/card.h> #include "sdhci.h" @@ -485,7 +486,10 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, if (offset) { if (data->flags & MMC_DATA_WRITE) { buffer = sdhci_kmap_atomic(sg, &flags); +/* Hack to avoid extensive warning messages from Redpine Signals LiteFi driver */ +#ifndef CONFIG_MACH_COLIBRI_T20 WARN_ON(((long)buffer & PAGE_MASK) > (PAGE_SIZE - 3)); +#endif memcpy(align, buffer, offset); sdhci_kunmap_atomic(buffer, &flags); } @@ -1046,14 +1050,11 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) u16 clk = 0; unsigned long timeout; - if (clock == host->clock) + if (clock && clock == host->clock) return; - if (host->ops->set_clock) { - host->ops->set_clock(host, clock); - if (host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK) - return; - } + if (host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK) + return; sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); @@ -1231,11 +1232,15 @@ 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 + if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) { + if (host->ops->get_cd) + present = host->ops->get_cd(host); + else + present = true; + } else { present = sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT; + } if (!present || host->flags & SDHCI_DEVICE_DEAD) { host->mrq->cmd->error = -ENOMEDIUM; @@ -1277,6 +1282,20 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) host = mmc_priv(mmc); + /* + * Controller registers should not be updated without the + * controller clock enabled. Set the minimum controller + * clock if there is no clock. + */ + if (host->ops->set_clock) { + if (!host->clock && !ios->clock) { + host->ops->set_clock(host, host->mmc->f_min); + host->clock = host->mmc->f_min; + } else if (ios->clock && (ios->clock != host->clock)) { + host->ops->set_clock(host, ios->clock); + } + } + spin_lock_irqsave(&host->lock, flags); if (host->flags & SDHCI_DEVICE_DEAD) @@ -1291,13 +1310,13 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) sdhci_reinit(host); } - sdhci_set_clock(host, ios->clock); - if (ios->power_mode == MMC_POWER_OFF) sdhci_set_power(host, -1); else sdhci_set_power(host, ios->vdd); + sdhci_set_clock(host, ios->clock); + if (host->ops->platform_send_init_74_clocks) host->ops->platform_send_init_74_clocks(host, ios->power_mode); @@ -1336,14 +1355,14 @@ static void sdhci_set_ios(struct mmc_host *mmc, 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_UHS_SDR50) || + if (((ios->timing == MMC_TIMING_UHS_SDR50) || (ios->timing == MMC_TIMING_UHS_SDR104) || (ios->timing == MMC_TIMING_UHS_DDR50) || (ios->timing == MMC_TIMING_UHS_SDR25) || (ios->timing == MMC_TIMING_UHS_SDR12)) + && !(host->quirks & SDHCI_QUIRK_NO_HISPD_BIT)) ctrl |= SDHCI_CTRL_HISPD; ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); @@ -1376,9 +1395,9 @@ static void sdhci_set_ios(struct mmc_host *mmc, 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); + clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); + clk |= SDHCI_CLOCK_CARD_EN; + sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); } @@ -1407,9 +1426,9 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) } /* Re-enable SD Clock */ - clock = host->clock; - host->clock = 0; - sdhci_set_clock(host, clock); + clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); + clk |= SDHCI_CLOCK_CARD_EN; + sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); } else sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); @@ -1424,6 +1443,12 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) out: mmiowb(); spin_unlock_irqrestore(&host->lock, flags); + /* + * Controller clock should only be disabled after all the register + * writes are done. + */ + if (!ios->clock && host->ops->set_clock) + host->ops->set_clock(host, ios->clock); } static int check_ro(struct sdhci_host *host) @@ -1510,6 +1535,12 @@ static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, if (host->version < SDHCI_SPEC_300) return 0; + if (host->quirks & SDHCI_QUIRK_NON_STD_VOLTAGE_SWITCHING) { + if (host->ops->switch_signal_voltage) + return host->ops->switch_signal_voltage( + host, ios->signal_voltage); + } + /* * 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. @@ -1552,7 +1583,6 @@ static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, /* Wait for 5ms */ usleep_range(5000, 5500); - ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); if (ctrl & SDHCI_CTRL_VDD_180) { /* Provide SDCLK again and wait for 1ms*/ @@ -1609,6 +1639,14 @@ static int sdhci_execute_tuning(struct mmc_host *mmc) disable_irq(host->irq); spin_lock(&host->lock); + if ((host->quirks & SDHCI_QUIRK_NON_STANDARD_TUNING) && + host->ops->execute_freq_tuning) { + err = host->ops->execute_freq_tuning(host); + spin_unlock(&host->lock); + enable_irq(host->irq); + return err; + } + ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); /* @@ -1782,6 +1820,16 @@ static void sdhci_enable_preset_value(struct mmc_host *mmc, bool enable) if (host->version < SDHCI_SPEC_300) return; + /* + * Enabling preset value would make programming clock + * divider ineffective. The controller would use the + * values present in the preset value registers. In + * case of non-standard clock, let the platform driver + * decide whether to enable preset or not. + */ + if (host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK) + return; + spin_lock_irqsave(&host->lock, flags); ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); @@ -1801,10 +1849,42 @@ static void sdhci_enable_preset_value(struct mmc_host *mmc, bool enable) spin_unlock_irqrestore(&host->lock, flags); } +int sdhci_enable(struct mmc_host *mmc) +{ + struct sdhci_host *host = mmc_priv(mmc); + + if (!mmc->card || mmc->card->type == MMC_TYPE_SDIO) + return 0; + + if (mmc->ios.clock) { + if (host->ops->set_clock) + host->ops->set_clock(host, mmc->ios.clock); + sdhci_set_clock(host, mmc->ios.clock); + } + + return 0; +} + +int sdhci_disable(struct mmc_host *mmc, int lazy) +{ + struct sdhci_host *host = mmc_priv(mmc); + + if (!mmc->card || mmc->card->type == MMC_TYPE_SDIO) + return 0; + + sdhci_set_clock(host, 0); + if (host->ops->set_clock) + host->ops->set_clock(host, 0); + + return 0; +} + static const struct mmc_host_ops sdhci_ops = { .request = sdhci_request, .set_ios = sdhci_set_ios, .get_ro = sdhci_get_ro, + .enable = sdhci_enable, + .disable = sdhci_disable, .enable_sdio_irq = sdhci_enable_sdio_irq, .start_signal_voltage_switch = sdhci_start_signal_voltage_switch, .execute_tuning = sdhci_execute_tuning, @@ -1884,6 +1964,8 @@ static void sdhci_tasklet_finish(unsigned long param) /* This is to force an update */ clock = host->clock; host->clock = 0; + if (host->ops->set_clock) + host->ops->set_clock(host, clock); sdhci_set_clock(host, clock); } @@ -2239,26 +2321,51 @@ out: int sdhci_suspend_host(struct sdhci_host *host, pm_message_t state) { - int ret; + int ret = 0; + bool has_tuning_timer; + struct mmc_host *mmc = host->mmc; sdhci_disable_card_detection(host); /* Disable tuning since we are suspending */ - if (host->version >= SDHCI_SPEC_300 && host->tuning_count && - host->tuning_mode == SDHCI_TUNING_MODE_1) { + has_tuning_timer = host->version >= SDHCI_SPEC_300 && + host->tuning_count && host->tuning_mode == SDHCI_TUNING_MODE_1; + if (has_tuning_timer) { host->flags &= ~SDHCI_NEEDS_RETUNING; mod_timer(&host->tuning_timer, jiffies + host->tuning_count * HZ); } - ret = mmc_suspend_host(host->mmc); - if (ret) - return ret; + if (mmc->card) { + ret = mmc_suspend_host(host->mmc); + if (ret) + goto err_suspend_host; + } - free_irq(host->irq, host); + if (mmc->pm_flags & MMC_PM_KEEP_POWER) + host->card_int_set = sdhci_readl(host, SDHCI_INT_ENABLE) & + SDHCI_INT_CARD_INT; + + sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK); - if (host->vmmc) + if (host->vmmc) { ret = regulator_disable(host->vmmc); + if (ret) + pr_err("%s: failed to disable regulator\n", __func__); + } + + if (host->irq) + disable_irq(host->irq); + + return 0; + +err_suspend_host: + /* Set the re-tuning expiration flag */ + if ((host->version >= SDHCI_SPEC_300) && host->tuning_count && + (host->tuning_mode == SDHCI_TUNING_MODE_1)) + host->flags |= SDHCI_NEEDS_RETUNING; + + sdhci_enable_card_detection(host); return ret; } @@ -2267,7 +2374,8 @@ EXPORT_SYMBOL_GPL(sdhci_suspend_host); int sdhci_resume_host(struct sdhci_host *host) { - int ret; + int ret = 0; + struct mmc_host *mmc = host->mmc; if (host->vmmc) { int ret = regulator_enable(host->vmmc); @@ -2281,15 +2389,21 @@ 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 (host->irq) + enable_irq(host->irq); sdhci_init(host, (host->mmc->pm_flags & MMC_PM_KEEP_POWER)); mmiowb(); - ret = mmc_resume_host(host->mmc); + if (mmc->card) { + ret = mmc_resume_host(host->mmc); + /* Enable card interrupt as it is overwritten in sdhci_init */ + if ((mmc->caps & MMC_CAP_SDIO_IRQ) && + (mmc->pm_flags & MMC_PM_KEEP_POWER)) + if (host->card_int_set) + mmc->ops->enable_sdio_irq(mmc, true); + } + sdhci_enable_card_detection(host); /* Set the re-tuning expiration flag */ @@ -2507,9 +2621,8 @@ int sdhci_add_host(struct sdhci_host *host) if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK) host->timeout_clk = mmc->f_max / 1000; - mmc->max_discard_to = (1 << 27) / host->timeout_clk; - - mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23; + if (!(host->quirks & SDHCI_QUIRK_NO_CALC_MAX_DISCARD_TO)) + mmc->max_discard_to = (1 << 27) / host->timeout_clk; if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12) host->flags |= SDHCI_AUTO_CMD12; @@ -2538,11 +2651,16 @@ int sdhci_add_host(struct sdhci_host *host) mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED; if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) && - mmc_card_is_removable(mmc)) + mmc_card_is_removable(mmc) && !(host->ops->get_cd)) mmc->caps |= MMC_CAP_NEEDS_POLL; - /* UHS-I mode(s) supported by the host controller. */ - if (host->version >= SDHCI_SPEC_300) + if (host->quirks & SDHCI_QUIRK2_NO_1_8_V) + caps[1] &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 | + SDHCI_SUPPORT_DDR50); + + /* Any UHS-I mode in caps implies SDR12 and SDR25 support. */ + if (caps[1] & (SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 | + SDHCI_SUPPORT_DDR50)) mmc->caps |= MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25; /* SDR104 supports also implies SDR50 support */ |