mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-23 17:30:02 +00:00
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>
This commit is contained in:
parent
113a87f868
commit
f0710a557c
2 changed files with 36 additions and 1 deletions
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in a new issue