diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/mmc/host/sdhci.c | 35 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci.h | 3 |
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) */ |