aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdrian Hunter <adrian.hunter@nokia.com>2009-09-22 19:44:33 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-09-23 10:39:33 -0400
commiteae1aeeed852aae37621b82a9e7f6c05096a18fd (patch)
tree6a1b108032a5cf08ccfa6fffa29c81cccbe8c82d
parent9feae246963c648b212abad0f0eb8938de5f5fe5 (diff)
mmc: add ability to save power by powering off cards
Power can be saved by powering off cards that are not in use. This is similar to suspend / resume except it is under the control of the driver, and does not require any power management support. It can only be used when the driver can monitor whether the card is removed, otherwise it is unsafe. This is possible because, unlike suspend, the driver still receives card detect and / or cover switch interrupts. Signed-off-by: Adrian Hunter <adrian.hunter@nokia.com> Acked-by: Matt Fleming <matt@console-pimps.org> Cc: Ian Molton <ian@mnementh.co.uk> Cc: "Roberto A. Foglietta" <roberto.foglietta@gmail.com> Cc: Jarkko Lavinen <jarkko.lavinen@nokia.com> Cc: Denis Karpov <ext-denis.2.karpov@nokia.com> Cc: Pierre Ossman <pierre@ossman.eu> Cc: Philip Langdale <philipl@overt.org> Cc: "Madhusudhan" <madhu.cr@ti.com> Cc: <linux-mmc@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--drivers/mmc/core/core.c34
-rw-r--r--drivers/mmc/core/core.h2
-rw-r--r--drivers/mmc/core/mmc.c11
-rw-r--r--drivers/mmc/core/sd.c11
-rw-r--r--include/linux/mmc/host.h3
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
1154void 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}
1170EXPORT_SYMBOL(mmc_power_save_host);
1171
1172void 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}
1186EXPORT_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
25void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops); 27void 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
552static 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
554static const struct mmc_bus_ops mmc_ops = { 562static 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
561static void mmc_attach_bus_ops(struct mmc_host *host) 570static 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
575static const struct mmc_bus_ops mmc_ops_unsafe = { 585static 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
582static void mmc_attach_bus_ops(struct mmc_host *host) 593static 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
606static 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
608static const struct mmc_bus_ops mmc_sd_ops = { 616static 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
615static void mmc_sd_attach_bus_ops(struct mmc_host *host) 624static 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
629static const struct mmc_bus_ops mmc_sd_ops_unsafe = { 639static 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
636static void mmc_sd_attach_bus_ops(struct mmc_host *host) 647static 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)
223extern int mmc_suspend_host(struct mmc_host *, pm_message_t); 223extern int mmc_suspend_host(struct mmc_host *, pm_message_t);
224extern int mmc_resume_host(struct mmc_host *); 224extern int mmc_resume_host(struct mmc_host *);
225 225
226extern void mmc_power_save_host(struct mmc_host *host);
227extern void mmc_power_restore_host(struct mmc_host *host);
228
226extern void mmc_detect_change(struct mmc_host *, unsigned long delay); 229extern void mmc_detect_change(struct mmc_host *, unsigned long delay);
227extern void mmc_request_done(struct mmc_host *, struct mmc_request *); 230extern void mmc_request_done(struct mmc_host *, struct mmc_request *);
228 231