diff options
author | Adrian Hunter <adrian.hunter@intel.com> | 2013-05-06 12:17:32 +0300 |
---|---|---|
committer | Chris Ball <cjb@laptop.org> | 2013-05-26 14:23:23 -0400 |
commit | f0710a557cb17746b09234f01073a2cdafe4f4a5 (patch) | |
tree | f56e5fdd5ba030c74e4a0a73959537cf8254c865 | |
parent | 113a87f868b2f2e086790a68e8b9e41d8f0c3295 (diff) | |
download | linux-stable-f0710a557cb17746b09234f01073a2cdafe4f4a5.tar.gz linux-stable-f0710a557cb17746b09234f01073a2cdafe4f4a5.tar.bz2 linux-stable-f0710a557cb17746b09234f01073a2cdafe4f4a5.zip |
mmc: sdhci: add ability to stay runtime-resumed if the card is powered up
If card power is dependent on SD bus power then the host controller
must not be runtime suspended while the card is powered up. Add
the ability to stay runtime-resumed in that case and enable it with a new
quirk SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON.
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Signed-off-by: Chris Ball <cjb@laptop.org>
-rw-r--r-- | drivers/mmc/host/sdhci.c | 35 | ||||
-rw-r--r-- | include/linux/mmc/sdhci.h | 2 |
2 files changed, 36 insertions, 1 deletions
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 2ea429c27714..c81c2a289dbd 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -58,6 +58,8 @@ static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable); #ifdef CONFIG_PM_RUNTIME static int sdhci_runtime_pm_get(struct sdhci_host *host); static int sdhci_runtime_pm_put(struct sdhci_host *host); +static void sdhci_runtime_pm_bus_on(struct sdhci_host *host); +static void sdhci_runtime_pm_bus_off(struct sdhci_host *host); #else static inline int sdhci_runtime_pm_get(struct sdhci_host *host) { @@ -67,6 +69,12 @@ static inline int sdhci_runtime_pm_put(struct sdhci_host *host) { return 0; } +static void sdhci_runtime_pm_bus_on(struct sdhci_host *host) +{ +} +static void sdhci_runtime_pm_bus_off(struct sdhci_host *host) +{ +} #endif static void sdhci_dumpregs(struct sdhci_host *host) @@ -192,8 +200,12 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask) sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET); - if (mask & SDHCI_RESET_ALL) + if (mask & SDHCI_RESET_ALL) { host->clock = 0; + /* Reset-all turns off SD Bus Power */ + if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON) + sdhci_runtime_pm_bus_off(host); + } /* Wait max 100 ms */ timeout = 100; @@ -1268,6 +1280,8 @@ static int sdhci_set_power(struct sdhci_host *host, unsigned short power) if (pwr == 0) { sdhci_writeb(host, 0, SDHCI_POWER_CONTROL); + if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON) + sdhci_runtime_pm_bus_off(host); return 0; } @@ -1289,6 +1303,9 @@ static int sdhci_set_power(struct sdhci_host *host, unsigned short power) sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL); + if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON) + sdhci_runtime_pm_bus_on(host); + /* * Some controllers need an extra 10ms delay of 10ms before they * can apply clock after applying power @@ -2625,6 +2642,22 @@ static int sdhci_runtime_pm_put(struct sdhci_host *host) return pm_runtime_put_autosuspend(host->mmc->parent); } +static void sdhci_runtime_pm_bus_on(struct sdhci_host *host) +{ + if (host->runtime_suspended || host->bus_on) + return; + host->bus_on = true; + pm_runtime_get_noresume(host->mmc->parent); +} + +static void sdhci_runtime_pm_bus_off(struct sdhci_host *host) +{ + if (host->runtime_suspended || !host->bus_on) + return; + host->bus_on = false; + pm_runtime_put_noidle(host->mmc->parent); +} + int sdhci_runtime_suspend_host(struct sdhci_host *host) { unsigned long flags; diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h index b838ffc49e4a..ba35bdb87d99 100644 --- a/include/linux/mmc/sdhci.h +++ b/include/linux/mmc/sdhci.h @@ -95,6 +95,7 @@ struct sdhci_host { /* The system physically doesn't support 1.8v, even if the host does */ #define SDHCI_QUIRK2_NO_1_8_V (1<<2) #define SDHCI_QUIRK2_PRESET_VALUE_BROKEN (1<<3) +#define SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON (1<<4) int irq; /* Device IRQ */ void __iomem *ioaddr; /* Mapped address */ @@ -139,6 +140,7 @@ struct sdhci_host { u8 pwr; /* Current voltage */ bool runtime_suspended; /* Host is runtime suspended */ + bool bus_on; /* Bus power prevents runtime suspend */ struct mmc_request *mrq; /* Current request */ struct mmc_command *cmd; /* Current command */ |