diff options
-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 b2910dc97121..66604499c3cb 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c | |||
@@ -57,6 +57,8 @@ static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable); | |||
57 | #ifdef CONFIG_PM_RUNTIME | 57 | #ifdef CONFIG_PM_RUNTIME |
58 | static int sdhci_runtime_pm_get(struct sdhci_host *host); | 58 | static int sdhci_runtime_pm_get(struct sdhci_host *host); |
59 | static int sdhci_runtime_pm_put(struct sdhci_host *host); | 59 | static int sdhci_runtime_pm_put(struct sdhci_host *host); |
60 | static void sdhci_runtime_pm_bus_on(struct sdhci_host *host); | ||
61 | static void sdhci_runtime_pm_bus_off(struct sdhci_host *host); | ||
60 | #else | 62 | #else |
61 | static inline int sdhci_runtime_pm_get(struct sdhci_host *host) | 63 | static inline int sdhci_runtime_pm_get(struct sdhci_host *host) |
62 | { | 64 | { |
@@ -66,6 +68,12 @@ static inline int sdhci_runtime_pm_put(struct sdhci_host *host) | |||
66 | { | 68 | { |
67 | return 0; | 69 | return 0; |
68 | } | 70 | } |
71 | static void sdhci_runtime_pm_bus_on(struct sdhci_host *host) | ||
72 | { | ||
73 | } | ||
74 | static void sdhci_runtime_pm_bus_off(struct sdhci_host *host) | ||
75 | { | ||
76 | } | ||
69 | #endif | 77 | #endif |
70 | 78 | ||
71 | static void sdhci_dumpregs(struct sdhci_host *host) | 79 | static void sdhci_dumpregs(struct sdhci_host *host) |
@@ -191,8 +199,12 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask) | |||
191 | 199 | ||
192 | sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET); | 200 | sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET); |
193 | 201 | ||
194 | if (mask & SDHCI_RESET_ALL) | 202 | if (mask & SDHCI_RESET_ALL) { |
195 | host->clock = 0; | 203 | host->clock = 0; |
204 | /* Reset-all turns off SD Bus Power */ | ||
205 | if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON) | ||
206 | sdhci_runtime_pm_bus_off(host); | ||
207 | } | ||
196 | 208 | ||
197 | /* Wait max 100 ms */ | 209 | /* Wait max 100 ms */ |
198 | timeout = 100; | 210 | timeout = 100; |
@@ -1273,6 +1285,8 @@ static int sdhci_set_power(struct sdhci_host *host, unsigned short power) | |||
1273 | 1285 | ||
1274 | if (pwr == 0) { | 1286 | if (pwr == 0) { |
1275 | sdhci_writeb(host, 0, SDHCI_POWER_CONTROL); | 1287 | sdhci_writeb(host, 0, SDHCI_POWER_CONTROL); |
1288 | if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON) | ||
1289 | sdhci_runtime_pm_bus_off(host); | ||
1276 | return 0; | 1290 | return 0; |
1277 | } | 1291 | } |
1278 | 1292 | ||
@@ -1294,6 +1308,9 @@ static int sdhci_set_power(struct sdhci_host *host, unsigned short power) | |||
1294 | 1308 | ||
1295 | sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL); | 1309 | sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL); |
1296 | 1310 | ||
1311 | if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON) | ||
1312 | sdhci_runtime_pm_bus_on(host); | ||
1313 | |||
1297 | /* | 1314 | /* |
1298 | * Some controllers need an extra 10ms delay of 10ms before they | 1315 | * Some controllers need an extra 10ms delay of 10ms before they |
1299 | * can apply clock after applying power | 1316 | * can apply clock after applying power |
@@ -2647,6 +2664,22 @@ static int sdhci_runtime_pm_put(struct sdhci_host *host) | |||
2647 | return pm_runtime_put_autosuspend(host->mmc->parent); | 2664 | return pm_runtime_put_autosuspend(host->mmc->parent); |
2648 | } | 2665 | } |
2649 | 2666 | ||
2667 | static void sdhci_runtime_pm_bus_on(struct sdhci_host *host) | ||
2668 | { | ||
2669 | if (host->runtime_suspended || host->bus_on) | ||
2670 | return; | ||
2671 | host->bus_on = true; | ||
2672 | pm_runtime_get_noresume(host->mmc->parent); | ||
2673 | } | ||
2674 | |||
2675 | static void sdhci_runtime_pm_bus_off(struct sdhci_host *host) | ||
2676 | { | ||
2677 | if (host->runtime_suspended || !host->bus_on) | ||
2678 | return; | ||
2679 | host->bus_on = false; | ||
2680 | pm_runtime_put_noidle(host->mmc->parent); | ||
2681 | } | ||
2682 | |||
2650 | int sdhci_runtime_suspend_host(struct sdhci_host *host) | 2683 | int sdhci_runtime_suspend_host(struct sdhci_host *host) |
2651 | { | 2684 | { |
2652 | unsigned long flags; | 2685 | 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 { | |||
95 | /* The system physically doesn't support 1.8v, even if the host does */ | 95 | /* The system physically doesn't support 1.8v, even if the host does */ |
96 | #define SDHCI_QUIRK2_NO_1_8_V (1<<2) | 96 | #define SDHCI_QUIRK2_NO_1_8_V (1<<2) |
97 | #define SDHCI_QUIRK2_PRESET_VALUE_BROKEN (1<<3) | 97 | #define SDHCI_QUIRK2_PRESET_VALUE_BROKEN (1<<3) |
98 | #define SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON (1<<4) | ||
98 | 99 | ||
99 | int irq; /* Device IRQ */ | 100 | int irq; /* Device IRQ */ |
100 | void __iomem *ioaddr; /* Mapped address */ | 101 | void __iomem *ioaddr; /* Mapped address */ |
@@ -139,6 +140,7 @@ struct sdhci_host { | |||
139 | u8 pwr; /* Current voltage */ | 140 | u8 pwr; /* Current voltage */ |
140 | 141 | ||
141 | bool runtime_suspended; /* Host is runtime suspended */ | 142 | bool runtime_suspended; /* Host is runtime suspended */ |
143 | bool bus_on; /* Bus power prevents runtime suspend */ | ||
142 | 144 | ||
143 | struct mmc_request *mrq; /* Current request */ | 145 | struct mmc_request *mrq; /* Current request */ |
144 | struct mmc_command *cmd; /* Current command */ | 146 | struct mmc_command *cmd; /* Current command */ |