summaryrefslogtreecommitdiff
path: root/drivers/mmc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/host/Kconfig12
-rw-r--r--drivers/mmc/host/sdhci.c26
-rwxr-xr-x[-rw-r--r--]drivers/mmc/host/sdhci.h5
3 files changed, 40 insertions, 3 deletions
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 3f8a5bb69e42..aca32075e12d 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -37,6 +37,18 @@ config MMC_SDHCI
If unsure, say N.
+config MMC_SDHCI_DYNAMIC_SDMEM_CLOCK
+ depends on MMC_SDHCI
+ bool "Dynamically control the card clock for SD memory devices"
+ default y
+ help
+ On certain embedded devices, leaving the card clock enabled to
+ SD memory devices with no active transactions can increase power
+ consumption. Enable this option to automatically disable the card
+ clock after transfers complete.
+
+ If unsure, say N here.
+
config MMC_SDHCI_PCI
tristate "SDHCI support on PCI bus"
depends on MMC_SDHCI && PCI
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 8bb9366bbf0c..a0591db8c152 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -18,6 +18,7 @@
#include <linux/io.h>
#include <linux/dma-mapping.h>
#include <linux/scatterlist.h>
+#include <linux/mmc/card.h>
#include <linux/leds.h>
@@ -134,6 +135,9 @@ static void sdhci_init(struct sdhci_host *host)
writel(intmask, host->ioaddr + SDHCI_INT_ENABLE);
writel(intmask, host->ioaddr + SDHCI_SIGNAL_ENABLE);
+#ifdef CONFIG_MMC_SDHCI_DYNAMIC_SDMEM_CLOCK
+ host->last_clock = 0;
+#endif
}
static void sdhci_activate_led(struct sdhci_host *host)
@@ -909,7 +913,9 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
if (clock == 0)
goto out;
-
+#ifdef CONFIG_MMC_SDHCI_DYNAMIC_SDMEM_CLOCK
+ host->last_clock = clock;
+#endif
div = 0;
if (host->ops->set_clock)
div = host->ops->set_clock(host, clock);
@@ -1010,6 +1016,15 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
unsigned long flags;
host = mmc_priv(mmc);
+#ifdef CONFIG_MMC_SDHCI_DYNAMIC_SDMEM_CLOCK
+ if (host->mmc->card != NULL) {
+ if (host->mmc->card->type != MMC_TYPE_SDIO) {
+ if (host->last_clock)
+ /* Enable clock */
+ sdhci_set_clock(host, host->last_clock);
+ }
+ }
+#endif
spin_lock_irqsave(&host->lock, flags);
@@ -1240,7 +1255,14 @@ static void sdhci_tasklet_finish(unsigned long param)
mmiowb();
spin_unlock_irqrestore(&host->lock, flags);
-
+#ifdef CONFIG_MMC_SDHCI_DYNAMIC_SDMEM_CLOCK
+ /* Disable clock */
+ if (host->mmc->card != NULL) {
+ if (host->mmc->card->type != MMC_TYPE_SDIO) {
+ sdhci_set_clock(host, 0);
+ }
+ }
+#endif
mmc_request_done(host->mmc, mrq);
}
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 5805e301e604..fe800af6b7d0 100644..100755
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -58,7 +58,7 @@
#define SDHCI_CARD_PRESENT 0x00010000
#define SDHCI_WRITE_PROTECT 0x00080000
-#define SDHCI_HOST_CONTROL 0x28
+#define SDHCI_HOST_CONTROL 0x28
#define SDHCI_CTRL_LED 0x01
#define SDHCI_CTRL_4BITBUS 0x02
#define SDHCI_CTRL_8BITBUS 0x20
@@ -246,6 +246,9 @@ struct sdhci_host {
unsigned int timeout_clk; /* Timeout freq (KHz) */
unsigned int clock; /* Current clock (MHz) */
+#ifdef CONFIG_MMC_SDHCI_DYNAMIC_SDMEM_CLOCK
+ unsigned int last_clock; /* Last used clock (MHz) */
+#endif
unsigned short power; /* Current voltage */
struct mmc_request *mrq; /* Current request */