summaryrefslogtreecommitdiff
path: root/drivers/mmc/host/sdhci.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc/host/sdhci.c')
-rw-r--r--drivers/mmc/host/sdhci.c198
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 */