aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/mmc/core/core.c12
-rw-r--r--drivers/mmc/core/sdio_io.c49
-rw-r--r--include/linux/mmc/host.h5
-rw-r--r--include/linux/mmc/pm.h30
-rw-r--r--include/linux/mmc/sdio_func.h5
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}
642EXPORT_SYMBOL_GPL(sdio_f0_writeb); 642EXPORT_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 */
654mmc_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}
661EXPORT_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 */
675int 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}
691EXPORT_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
18struct mmc_ios { 19struct 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
25typedef 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
18struct mmc_card; 20struct mmc_card;
19struct sdio_func; 21struct sdio_func;
20 22
@@ -153,5 +155,8 @@ extern unsigned char sdio_f0_readb(struct sdio_func *func,
153extern void sdio_f0_writeb(struct sdio_func *func, unsigned char b, 155extern 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
158extern mmc_pm_flag_t sdio_get_host_pm_caps(struct sdio_func *func);
159extern int sdio_set_host_pm_flags(struct sdio_func *func, mmc_pm_flag_t flags);
160
156#endif 161#endif
157 162