summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mmc/host/sdhci.c35
-rw-r--r--drivers/mmc/host/sdhci.h3
2 files changed, 38 insertions, 0 deletions
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 466a64683d5f..b57c8fa9a569 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -22,6 +22,7 @@
#include <linux/leds.h>
#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
#include "sdhci.h"
@@ -183,6 +184,8 @@ static void sdhci_init(struct sdhci_host *host)
SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_INDEX |
SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT |
SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE);
+
+ host->last_clk = 0;
}
static void sdhci_reinit(struct sdhci_host *host)
@@ -1013,6 +1016,8 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
if (clock == 0)
goto out;
+ host->last_clk = clock;
+
for (div = 1;div < 256;div *= 2) {
if ((host->max_clk / div) <= clock)
break;
@@ -1267,6 +1272,29 @@ out:
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 (host->last_clk)
+ sdhci_set_clock(host, host->last_clk);
+ 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);
+ return 0;
+}
+
#ifdef CONFIG_EMBEDDED_MMC_START_OFFSET
static unsigned int sdhci_get_host_offset(struct mmc_host *mmc) {
struct sdhci_host *host;
@@ -1279,6 +1307,8 @@ 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,
#ifdef CONFIG_EMBEDDED_MMC_START_OFFSET
.get_host_offset = sdhci_get_host_offset,
@@ -1841,6 +1871,11 @@ int sdhci_add_host(struct sdhci_host *host)
mmc->caps |= MMC_CAP_NEEDS_POLL;
}
+ if (host->quirks & SDHCI_QUIRK_RUNTIME_DISABLE) {
+ mmc->caps |= MMC_CAP_DISABLE;
+ mmc_set_disable_delay(mmc, msecs_to_jiffies(50));
+ }
+
if (host->data_width >= 8)
mmc->caps |= MMC_CAP_8_BIT_DATA;
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index b72cf351cb45..9b78ef8cdb88 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -247,6 +247,8 @@ struct sdhci_host {
#define SDHCI_QUIRK_BROKEN_SPEC_VERSION (1<<29)
/* Controller should not use SDIO IRQ */
#define SDHCI_QUIRK_NO_SDIO_IRQ (1<<30)
+/* Controller allows runtime enable / disable */
+#define SDHCI_QUIRK_RUNTIME_DISABLE (1<<31)
int irq; /* Device IRQ */
void __iomem * ioaddr; /* Mapped address */
@@ -272,6 +274,7 @@ struct sdhci_host {
unsigned int version; /* SDHCI spec. version */
+ unsigned int last_clk; /* Last configured clock */
unsigned int max_clk; /* Max possible freq (MHz) */
unsigned int timeout_clk; /* Timeout freq (KHz) */