summaryrefslogtreecommitdiff
path: root/drivers/mmc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/core/sd.c11
-rw-r--r--drivers/mmc/host/sdhci.c71
-rw-r--r--drivers/mmc/host/sdhci.h7
3 files changed, 57 insertions, 32 deletions
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 206b21f9797a..53735815e95e 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -349,6 +349,8 @@ static int mmc_read_switch(struct mmc_card *card)
if (status[13] & 0x08) /* UHS104 mode */
card->sw_caps.hs_max_dtr = 208000000;
+ else if (status[13] & 0x10) /* DDR50 mode */
+ card->sw_caps.hs_max_dtr = 50000000;
else if (status[13] & 0x04) /* UHS50 mode */
card->sw_caps.hs_max_dtr = 104000000;
else if (status[13] & 0x02) /* high speed mode */
@@ -356,7 +358,6 @@ static int mmc_read_switch(struct mmc_card *card)
out:
kfree(status);
-
return err;
}
@@ -486,12 +487,10 @@ int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid)
ocr |= 1 << 30;
/*
- * Check the voltage switching capability if the host supports SDR
- * or DDR modes.
+ * Check voltage switching capability of the card if the host supports it.
*/
- if (((host->caps & MMC_CAP_SDR50) || (host->caps & MMC_CAP_SDR104) ||
- (host->caps & MMC_CAP_DDR50))&& (!mmc_host_is_spi(host)))
- ocr |= (1 << 24);
+ if ((host->caps & MMC_CAP_VOLTAGE_SWITCHING) && (!mmc_host_is_spi(host)))
+ ocr |= (1 << 24);
err = mmc_send_app_op_cond(host, ocr, &rocr);
if (err)
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 1e16944ad2e4..153866bc8e0e 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -176,10 +176,11 @@ static void sdhci_reset(struct sdhci_host *host, u8 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 (mask & SDHCI_RESET_ALL) {
host->ops->configure_capabilities(host);
-
- host->uhs_mode = 0;
+ host->uhs_mode = 0;
+ host->mmc->ios.signalling_voltage = MMC_3_3_VOLT_SIGNALLING;
+ }
}
static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios);
@@ -1256,27 +1257,6 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
}
- if ((ios->signalling_voltage == MMC_1_8_VOLT_SIGNALLING) &&
- (ios->signalling_voltage != host->signalling_voltage)) {
- /* Switch OFF SD clock */
- clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
- clk &= (~SDHCI_CLOCK_CARD_EN);
- sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
-
- ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL_2);
- ctrl |= SDHCI_CTRL_2_VOLT_18_EN;
- sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL_2);
-
- /* Wait for 5msec for the output to be stable */
- mdelay(5);
-
- /* Switch ON sd clock */
- clk |= SDHCI_CLOCK_CARD_EN;
- sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
-
- host->signalling_voltage = ios->signalling_voltage;
- }
-
if (ios->tuning_arg) {
switch(ios->tuning_arg) {
case MMC_EXECUTE_TUNING:
@@ -1304,6 +1284,36 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
}
}
+ if (ios->signalling_voltage != host->signalling_voltage) {
+ /* Switch OFF SD clock */
+ clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+ clk &= (~SDHCI_CLOCK_CARD_EN);
+ sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+
+ if (ios->signalling_voltage == MMC_1_8_VOLT_SIGNALLING) {
+ ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL_2);
+ ctrl |= SDHCI_CTRL_2_VOLT_18_EN;
+ sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL_2);
+ }
+
+ if (host->quirks & SDHCI_QUIRK_BROKEN_VOLTAGE_SWITCHING) {
+ spin_unlock_irqrestore(&host->lock, flags);
+ if (host->ops->set_signalling_voltage) {
+ host->ops->set_signalling_voltage(host,
+ ios->signalling_voltage);
+ }
+ spin_lock_irqsave(&host->lock, flags);
+ }
+
+ /* Wait for 5msec for the output to be stable */
+ mdelay(5);
+
+ /* Switch ON sd clock */
+ clk |= SDHCI_CLOCK_CARD_EN;
+ sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+
+ host->signalling_voltage = ios->signalling_voltage;
+ }
out:
mmiowb();
spin_unlock_irqrestore(&host->lock, flags);
@@ -1878,7 +1888,7 @@ int sdhci_add_host(struct sdhci_host *host)
>> SDHCI_SPEC_VER_SHIFT;
}
- if (host->version > SDHCI_SPEC_200) {
+ if (host->version > SDHCI_SPEC_300) {
printk(KERN_ERR "%s: Unknown controller version (%d). "
"You may experience problems.\n", mmc_hostname(mmc),
host->version);
@@ -2099,6 +2109,17 @@ int sdhci_add_host(struct sdhci_host *host)
if (caps & SDHCI_CAN_SDR50_TUNING)
mmc->caps |= MMC_CAP_SDR50_TUNING;
+ if ((caps & SDHCI_CAN_SUPPORT_DDR50) || (caps & SDHCI_CAN_SUPPORT_SDR104) ||
+ (caps & SDHCI_CAN_SUPPORT_SDR50)) {
+ if (!(host->quirks & SDHCI_QUIRK_BROKEN_VOLTAGE_SWITCHING))
+ mmc->caps |= MMC_CAP_VOLTAGE_SWITCHING;
+ else {
+ /* Do the voltage switching using a regulator */
+ if (host->ops->set_signalling_voltage)
+ mmc->caps |= MMC_CAP_VOLTAGE_SWITCHING;
+ }
+ }
+
/*
* Init tasklets.
*/
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 69576e84fa3d..9dfa40cf393c 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -147,7 +147,7 @@
#define SDHCI_TIMEOUT_CLK_MASK 0x0000003F
#define SDHCI_TIMEOUT_CLK_SHIFT 0
#define SDHCI_TIMEOUT_CLK_UNIT 0x00000080
-#define SDHCI_CLOCK_BASE_MASK 0x00003F00
+#define SDHCI_CLOCK_BASE_MASK 0x0000FF00
#define SDHCI_CLOCK_BASE_SHIFT 8
#define SDHCI_MAX_BLOCK_MASK 0x00030000
#define SDHCI_MAX_BLOCK_SHIFT 16
@@ -190,6 +190,7 @@
#define SDHCI_SPEC_VER_SHIFT 0
#define SDHCI_SPEC_100 0
#define SDHCI_SPEC_200 1
+#define SDHCI_SPEC_300 2
struct sdhci_ops;
@@ -277,6 +278,8 @@ struct sdhci_host {
#define SDHCI_QUIRK_FORCE_HIGH_SPEED_MODE (1LL<<37)
/* Controller allows runtime enable / disable */
#define SDHCI_QUIRK_RUNTIME_DISABLE (1LL<<38)
+/* Controller cannot switch signalling voltage automatically */
+#define SDHCI_QUIRK_BROKEN_VOLTAGE_SWITCHING (1LL<<39)
int irq; /* Device IRQ */
void __iomem * ioaddr; /* Mapped address */
@@ -351,6 +354,8 @@ struct sdhci_ops {
void (*set_clock)(struct sdhci_host *host, unsigned int clock);
void (*configure_capabilities)(struct sdhci_host *host);
+ void (*set_signalling_voltage)(struct sdhci_host *host,
+ unsigned int signalling_voltage);
int (*enable_dma)(struct sdhci_host *host);
int (*get_ro)(struct sdhci_host *host);