|
@@ -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;
|