diff options
-rw-r--r-- | drivers/mmc/core/core.c | 12 | ||||
-rw-r--r-- | drivers/mmc/core/sdio_io.c | 49 | ||||
-rw-r--r-- | include/linux/mmc/host.h | 5 | ||||
-rw-r--r-- | include/linux/mmc/pm.h | 30 | ||||
-rw-r--r-- | include/linux/mmc/sdio_func.h | 5 |
5 files changed, 98 insertions, 3 deletions
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 30acd5265821..f4b97d3c3d0f 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c | |||
@@ -1151,6 +1151,9 @@ void mmc_stop_host(struct mmc_host *host) | |||
1151 | cancel_delayed_work(&host->detect); | 1151 | cancel_delayed_work(&host->detect); |
1152 | mmc_flush_scheduled_work(); | 1152 | mmc_flush_scheduled_work(); |
1153 | 1153 | ||
1154 | /* clear pm flags now and let card drivers set them as needed */ | ||
1155 | host->pm_flags = 0; | ||
1156 | |||
1154 | mmc_bus_get(host); | 1157 | mmc_bus_get(host); |
1155 | if (host->bus_ops && !host->bus_dead) { | 1158 | if (host->bus_ops && !host->bus_dead) { |
1156 | if (host->bus_ops->remove) | 1159 | if (host->bus_ops->remove) |
@@ -1273,12 +1276,13 @@ int mmc_suspend_host(struct mmc_host *host, pm_message_t state) | |||
1273 | mmc_claim_host(host); | 1276 | mmc_claim_host(host); |
1274 | mmc_detach_bus(host); | 1277 | mmc_detach_bus(host); |
1275 | mmc_release_host(host); | 1278 | mmc_release_host(host); |
1279 | host->pm_flags = 0; | ||
1276 | err = 0; | 1280 | err = 0; |
1277 | } | 1281 | } |
1278 | } | 1282 | } |
1279 | mmc_bus_put(host); | 1283 | mmc_bus_put(host); |
1280 | 1284 | ||
1281 | if (!err) | 1285 | if (!err && !(host->pm_flags & MMC_PM_KEEP_POWER)) |
1282 | mmc_power_off(host); | 1286 | mmc_power_off(host); |
1283 | 1287 | ||
1284 | return err; | 1288 | return err; |
@@ -1296,8 +1300,10 @@ int mmc_resume_host(struct mmc_host *host) | |||
1296 | 1300 | ||
1297 | mmc_bus_get(host); | 1301 | mmc_bus_get(host); |
1298 | if (host->bus_ops && !host->bus_dead) { | 1302 | if (host->bus_ops && !host->bus_dead) { |
1299 | mmc_power_up(host); | 1303 | if (!(host->pm_flags & MMC_PM_KEEP_POWER)) { |
1300 | mmc_select_voltage(host, host->ocr); | 1304 | mmc_power_up(host); |
1305 | mmc_select_voltage(host, host->ocr); | ||
1306 | } | ||
1301 | BUG_ON(!host->bus_ops->resume); | 1307 | BUG_ON(!host->bus_ops->resume); |
1302 | err = host->bus_ops->resume(host); | 1308 | err = host->bus_ops->resume(host); |
1303 | if (err) { | 1309 | if (err) { |
diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c index 87c618904ee2..ff27c8c71355 100644 --- a/drivers/mmc/core/sdio_io.c +++ b/drivers/mmc/core/sdio_io.c | |||
@@ -640,3 +640,52 @@ void sdio_f0_writeb(struct sdio_func *func, unsigned char b, unsigned int addr, | |||
640 | *err_ret = ret; | 640 | *err_ret = ret; |
641 | } | 641 | } |
642 | EXPORT_SYMBOL_GPL(sdio_f0_writeb); | 642 | EXPORT_SYMBOL_GPL(sdio_f0_writeb); |
643 | |||
644 | /** | ||
645 | * sdio_get_host_pm_caps - get host power management capabilities | ||
646 | * @func: SDIO function attached to host | ||
647 | * | ||
648 | * Returns a capability bitmask corresponding to power management | ||
649 | * features supported by the host controller that the card function | ||
650 | * might rely upon during a system suspend. The host doesn't need | ||
651 | * to be claimed, nor the function active, for this information to be | ||
652 | * obtained. | ||
653 | */ | ||
654 | mmc_pm_flag_t sdio_get_host_pm_caps(struct sdio_func *func) | ||
655 | { | ||
656 | BUG_ON(!func); | ||
657 | BUG_ON(!func->card); | ||
658 | |||
659 | return func->card->host->pm_caps; | ||
660 | } | ||
661 | EXPORT_SYMBOL_GPL(sdio_get_host_pm_caps); | ||
662 | |||
663 | /** | ||
664 | * sdio_set_host_pm_flags - set wanted host power management capabilities | ||
665 | * @func: SDIO function attached to host | ||
666 | * | ||
667 | * Set a capability bitmask corresponding to wanted host controller | ||
668 | * power management features for the upcoming suspend state. | ||
669 | * This must be called, if needed, each time the suspend method of | ||
670 | * the function driver is called, and must contain only bits that | ||
671 | * were returned by sdio_get_host_pm_caps(). | ||
672 | * The host doesn't need to be claimed, nor the function active, | ||
673 | * for this information to be set. | ||
674 | */ | ||
675 | int sdio_set_host_pm_flags(struct sdio_func *func, mmc_pm_flag_t flags) | ||
676 | { | ||
677 | struct mmc_host *host; | ||
678 | |||
679 | BUG_ON(!func); | ||
680 | BUG_ON(!func->card); | ||
681 | |||
682 | host = func->card->host; | ||
683 | |||
684 | if (flags & ~host->pm_caps) | ||
685 | return -EINVAL; | ||
686 | |||
687 | /* function suspend methods are serialized, hence no lock needed */ | ||
688 | host->pm_flags |= flags; | ||
689 | return 0; | ||
690 | } | ||
691 | EXPORT_SYMBOL_GPL(sdio_set_host_pm_flags); | ||
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index eaf36364b7d4..43eaf5ca5848 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/sched.h> | 14 | #include <linux/sched.h> |
15 | 15 | ||
16 | #include <linux/mmc/core.h> | 16 | #include <linux/mmc/core.h> |
17 | #include <linux/mmc/pm.h> | ||
17 | 18 | ||
18 | struct mmc_ios { | 19 | struct mmc_ios { |
19 | unsigned int clock; /* clock rate */ | 20 | unsigned int clock; /* clock rate */ |
@@ -152,6 +153,8 @@ struct mmc_host { | |||
152 | #define MMC_CAP_NONREMOVABLE (1 << 8) /* Nonremovable e.g. eMMC */ | 153 | #define MMC_CAP_NONREMOVABLE (1 << 8) /* Nonremovable e.g. eMMC */ |
153 | #define MMC_CAP_WAIT_WHILE_BUSY (1 << 9) /* Waits while card is busy */ | 154 | #define MMC_CAP_WAIT_WHILE_BUSY (1 << 9) /* Waits while card is busy */ |
154 | 155 | ||
156 | mmc_pm_flag_t pm_caps; /* supported pm features */ | ||
157 | |||
155 | /* host specific block data */ | 158 | /* host specific block data */ |
156 | unsigned int max_seg_size; /* see blk_queue_max_segment_size */ | 159 | unsigned int max_seg_size; /* see blk_queue_max_segment_size */ |
157 | unsigned short max_hw_segs; /* see blk_queue_max_hw_segments */ | 160 | unsigned short max_hw_segs; /* see blk_queue_max_hw_segments */ |
@@ -197,6 +200,8 @@ struct mmc_host { | |||
197 | struct task_struct *sdio_irq_thread; | 200 | struct task_struct *sdio_irq_thread; |
198 | atomic_t sdio_irq_thread_abort; | 201 | atomic_t sdio_irq_thread_abort; |
199 | 202 | ||
203 | mmc_pm_flag_t pm_flags; /* requested pm features */ | ||
204 | |||
200 | #ifdef CONFIG_LEDS_TRIGGERS | 205 | #ifdef CONFIG_LEDS_TRIGGERS |
201 | struct led_trigger *led; /* activity led */ | 206 | struct led_trigger *led; /* activity led */ |
202 | #endif | 207 | #endif |
diff --git a/include/linux/mmc/pm.h b/include/linux/mmc/pm.h new file mode 100644 index 000000000000..d37aac49cf9a --- /dev/null +++ b/include/linux/mmc/pm.h | |||
@@ -0,0 +1,30 @@ | |||
1 | /* | ||
2 | * linux/include/linux/mmc/pm.h | ||
3 | * | ||
4 | * Author: Nicolas Pitre | ||
5 | * Copyright: (C) 2009 Marvell Technology Group Ltd. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #ifndef LINUX_MMC_PM_H | ||
13 | #define LINUX_MMC_PM_H | ||
14 | |||
15 | /* | ||
16 | * These flags are used to describe power management features that | ||
17 | * some cards (typically SDIO cards) might wish to benefit from when | ||
18 | * the host system is being suspended. There are several layers of | ||
19 | * abstractions involved, from the host controller driver, to the MMC core | ||
20 | * code, to the SDIO core code, to finally get to the actual SDIO function | ||
21 | * driver. This file is therefore used for common definitions shared across | ||
22 | * all those layers. | ||
23 | */ | ||
24 | |||
25 | typedef unsigned int mmc_pm_flag_t; | ||
26 | |||
27 | #define MMC_PM_KEEP_POWER (1 << 0) /* preserve card power during suspend */ | ||
28 | #define MMC_PM_WAKE_SDIO_IRQ (1 << 1) /* wake up host system on SDIO IRQ assertion */ | ||
29 | |||
30 | #endif | ||
diff --git a/include/linux/mmc/sdio_func.h b/include/linux/mmc/sdio_func.h index ac3ab683fec6..c6c0cceba5fe 100644 --- a/include/linux/mmc/sdio_func.h +++ b/include/linux/mmc/sdio_func.h | |||
@@ -15,6 +15,8 @@ | |||
15 | #include <linux/device.h> | 15 | #include <linux/device.h> |
16 | #include <linux/mod_devicetable.h> | 16 | #include <linux/mod_devicetable.h> |
17 | 17 | ||
18 | #include <linux/mmc/pm.h> | ||
19 | |||
18 | struct mmc_card; | 20 | struct mmc_card; |
19 | struct sdio_func; | 21 | struct sdio_func; |
20 | 22 | ||
@@ -153,5 +155,8 @@ extern unsigned char sdio_f0_readb(struct sdio_func *func, | |||
153 | extern void sdio_f0_writeb(struct sdio_func *func, unsigned char b, | 155 | extern void sdio_f0_writeb(struct sdio_func *func, unsigned char b, |
154 | unsigned int addr, int *err_ret); | 156 | unsigned int addr, int *err_ret); |
155 | 157 | ||
158 | extern mmc_pm_flag_t sdio_get_host_pm_caps(struct sdio_func *func); | ||
159 | extern int sdio_set_host_pm_flags(struct sdio_func *func, mmc_pm_flag_t flags); | ||
160 | |||
156 | #endif | 161 | #endif |
157 | 162 | ||