diff options
-rw-r--r-- | drivers/mmc/core/core.c | 34 | ||||
-rw-r--r-- | drivers/mmc/core/core.h | 2 | ||||
-rw-r--r-- | drivers/mmc/core/mmc.c | 11 | ||||
-rw-r--r-- | drivers/mmc/core/sd.c | 11 | ||||
-rw-r--r-- | include/linux/mmc/host.h | 3 |
5 files changed, 61 insertions, 0 deletions
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 02f2b1871a38..be1fc013fbe9 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c | |||
@@ -1151,6 +1151,40 @@ void mmc_stop_host(struct mmc_host *host) | |||
1151 | mmc_power_off(host); | 1151 | mmc_power_off(host); |
1152 | } | 1152 | } |
1153 | 1153 | ||
1154 | void mmc_power_save_host(struct mmc_host *host) | ||
1155 | { | ||
1156 | mmc_bus_get(host); | ||
1157 | |||
1158 | if (!host->bus_ops || host->bus_dead || !host->bus_ops->power_restore) { | ||
1159 | mmc_bus_put(host); | ||
1160 | return; | ||
1161 | } | ||
1162 | |||
1163 | if (host->bus_ops->power_save) | ||
1164 | host->bus_ops->power_save(host); | ||
1165 | |||
1166 | mmc_bus_put(host); | ||
1167 | |||
1168 | mmc_power_off(host); | ||
1169 | } | ||
1170 | EXPORT_SYMBOL(mmc_power_save_host); | ||
1171 | |||
1172 | void mmc_power_restore_host(struct mmc_host *host) | ||
1173 | { | ||
1174 | mmc_bus_get(host); | ||
1175 | |||
1176 | if (!host->bus_ops || host->bus_dead || !host->bus_ops->power_restore) { | ||
1177 | mmc_bus_put(host); | ||
1178 | return; | ||
1179 | } | ||
1180 | |||
1181 | mmc_power_up(host); | ||
1182 | host->bus_ops->power_restore(host); | ||
1183 | |||
1184 | mmc_bus_put(host); | ||
1185 | } | ||
1186 | EXPORT_SYMBOL(mmc_power_restore_host); | ||
1187 | |||
1154 | #ifdef CONFIG_PM | 1188 | #ifdef CONFIG_PM |
1155 | 1189 | ||
1156 | /** | 1190 | /** |
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h index c819effa1032..f7eb4c4ca014 100644 --- a/drivers/mmc/core/core.h +++ b/drivers/mmc/core/core.h | |||
@@ -20,6 +20,8 @@ struct mmc_bus_ops { | |||
20 | void (*detect)(struct mmc_host *); | 20 | void (*detect)(struct mmc_host *); |
21 | void (*suspend)(struct mmc_host *); | 21 | void (*suspend)(struct mmc_host *); |
22 | void (*resume)(struct mmc_host *); | 22 | void (*resume)(struct mmc_host *); |
23 | void (*power_save)(struct mmc_host *); | ||
24 | void (*power_restore)(struct mmc_host *); | ||
23 | }; | 25 | }; |
24 | 26 | ||
25 | void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops); | 27 | void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops); |
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 995db1853a81..27e842df6a6f 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c | |||
@@ -549,6 +549,14 @@ static void mmc_resume(struct mmc_host *host) | |||
549 | 549 | ||
550 | } | 550 | } |
551 | 551 | ||
552 | static void mmc_power_restore(struct mmc_host *host) | ||
553 | { | ||
554 | host->card->state &= ~MMC_STATE_HIGHSPEED; | ||
555 | mmc_claim_host(host); | ||
556 | mmc_init_card(host, host->ocr, host->card); | ||
557 | mmc_release_host(host); | ||
558 | } | ||
559 | |||
552 | #ifdef CONFIG_MMC_UNSAFE_RESUME | 560 | #ifdef CONFIG_MMC_UNSAFE_RESUME |
553 | 561 | ||
554 | static const struct mmc_bus_ops mmc_ops = { | 562 | static const struct mmc_bus_ops mmc_ops = { |
@@ -556,6 +564,7 @@ static const struct mmc_bus_ops mmc_ops = { | |||
556 | .detect = mmc_detect, | 564 | .detect = mmc_detect, |
557 | .suspend = mmc_suspend, | 565 | .suspend = mmc_suspend, |
558 | .resume = mmc_resume, | 566 | .resume = mmc_resume, |
567 | .power_restore = mmc_power_restore, | ||
559 | }; | 568 | }; |
560 | 569 | ||
561 | static void mmc_attach_bus_ops(struct mmc_host *host) | 570 | static void mmc_attach_bus_ops(struct mmc_host *host) |
@@ -570,6 +579,7 @@ static const struct mmc_bus_ops mmc_ops = { | |||
570 | .detect = mmc_detect, | 579 | .detect = mmc_detect, |
571 | .suspend = NULL, | 580 | .suspend = NULL, |
572 | .resume = NULL, | 581 | .resume = NULL, |
582 | .power_restore = mmc_power_restore, | ||
573 | }; | 583 | }; |
574 | 584 | ||
575 | static const struct mmc_bus_ops mmc_ops_unsafe = { | 585 | static const struct mmc_bus_ops mmc_ops_unsafe = { |
@@ -577,6 +587,7 @@ static const struct mmc_bus_ops mmc_ops_unsafe = { | |||
577 | .detect = mmc_detect, | 587 | .detect = mmc_detect, |
578 | .suspend = mmc_suspend, | 588 | .suspend = mmc_suspend, |
579 | .resume = mmc_resume, | 589 | .resume = mmc_resume, |
590 | .power_restore = mmc_power_restore, | ||
580 | }; | 591 | }; |
581 | 592 | ||
582 | static void mmc_attach_bus_ops(struct mmc_host *host) | 593 | static void mmc_attach_bus_ops(struct mmc_host *host) |
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 92fa9dceca79..222a60928cdb 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c | |||
@@ -603,6 +603,14 @@ static void mmc_sd_resume(struct mmc_host *host) | |||
603 | 603 | ||
604 | } | 604 | } |
605 | 605 | ||
606 | static void mmc_sd_power_restore(struct mmc_host *host) | ||
607 | { | ||
608 | host->card->state &= ~MMC_STATE_HIGHSPEED; | ||
609 | mmc_claim_host(host); | ||
610 | mmc_sd_init_card(host, host->ocr, host->card); | ||
611 | mmc_release_host(host); | ||
612 | } | ||
613 | |||
606 | #ifdef CONFIG_MMC_UNSAFE_RESUME | 614 | #ifdef CONFIG_MMC_UNSAFE_RESUME |
607 | 615 | ||
608 | static const struct mmc_bus_ops mmc_sd_ops = { | 616 | static const struct mmc_bus_ops mmc_sd_ops = { |
@@ -610,6 +618,7 @@ static const struct mmc_bus_ops mmc_sd_ops = { | |||
610 | .detect = mmc_sd_detect, | 618 | .detect = mmc_sd_detect, |
611 | .suspend = mmc_sd_suspend, | 619 | .suspend = mmc_sd_suspend, |
612 | .resume = mmc_sd_resume, | 620 | .resume = mmc_sd_resume, |
621 | .power_restore = mmc_sd_power_restore, | ||
613 | }; | 622 | }; |
614 | 623 | ||
615 | static void mmc_sd_attach_bus_ops(struct mmc_host *host) | 624 | static void mmc_sd_attach_bus_ops(struct mmc_host *host) |
@@ -624,6 +633,7 @@ static const struct mmc_bus_ops mmc_sd_ops = { | |||
624 | .detect = mmc_sd_detect, | 633 | .detect = mmc_sd_detect, |
625 | .suspend = NULL, | 634 | .suspend = NULL, |
626 | .resume = NULL, | 635 | .resume = NULL, |
636 | .power_restore = mmc_sd_power_restore, | ||
627 | }; | 637 | }; |
628 | 638 | ||
629 | static const struct mmc_bus_ops mmc_sd_ops_unsafe = { | 639 | static const struct mmc_bus_ops mmc_sd_ops_unsafe = { |
@@ -631,6 +641,7 @@ static const struct mmc_bus_ops mmc_sd_ops_unsafe = { | |||
631 | .detect = mmc_sd_detect, | 641 | .detect = mmc_sd_detect, |
632 | .suspend = mmc_sd_suspend, | 642 | .suspend = mmc_sd_suspend, |
633 | .resume = mmc_sd_resume, | 643 | .resume = mmc_sd_resume, |
644 | .power_restore = mmc_sd_power_restore, | ||
634 | }; | 645 | }; |
635 | 646 | ||
636 | static void mmc_sd_attach_bus_ops(struct mmc_host *host) | 647 | static void mmc_sd_attach_bus_ops(struct mmc_host *host) |
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index bb867d2c26bd..c1cbe598d470 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h | |||
@@ -223,6 +223,9 @@ static inline void *mmc_priv(struct mmc_host *host) | |||
223 | extern int mmc_suspend_host(struct mmc_host *, pm_message_t); | 223 | extern int mmc_suspend_host(struct mmc_host *, pm_message_t); |
224 | extern int mmc_resume_host(struct mmc_host *); | 224 | extern int mmc_resume_host(struct mmc_host *); |
225 | 225 | ||
226 | extern void mmc_power_save_host(struct mmc_host *host); | ||
227 | extern void mmc_power_restore_host(struct mmc_host *host); | ||
228 | |||
226 | extern void mmc_detect_change(struct mmc_host *, unsigned long delay); | 229 | extern void mmc_detect_change(struct mmc_host *, unsigned long delay); |
227 | extern void mmc_request_done(struct mmc_host *, struct mmc_request *); | 230 | extern void mmc_request_done(struct mmc_host *, struct mmc_request *); |
228 | 231 | ||