summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGary King <gking@nvidia.com>2010-06-09 14:19:52 -0700
committerGary King <gking@nvidia.com>2010-06-09 15:37:41 -0700
commit5c3df65e0a477daca9cac6c8dd558bec659bcc35 (patch)
tree7d6c2f0ff072bfc5de807c69987bf5e361dbdef8
parent6b49e77d7b25f1df7cf732667027ea2329096be4 (diff)
mmc: sdhci: add mmc_host_ops->enable and ->disable
add support for the mmc delayed suspend interface to the sdhci driver, so that hosts which support it (controlled by a new quirk: SDHCI_QUIRK_RUNTIME_DISABLE) can use runtime delayed suspends to reduce the power consumption from idle SD controllers Change-Id: Iaa6a9dfad4cb9496caca715b5a7ce9e1b533d998 Reviewed-on: http://git-master/r/2343 Reviewed-by: Narendra Damahe <ndamahe@nvidia.com> Tested-by: Narendra Damahe <ndamahe@nvidia.com> Reviewed-by: Gary King <gking@nvidia.com>
-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) */