aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/core/core.c83
-rw-r--r--drivers/mmc/core/host.c4
2 files changed, 61 insertions, 26 deletions
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index b69ce91b11e1..83240faa1dc8 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -1057,6 +1057,17 @@ void mmc_rescan(struct work_struct *work)
1057 container_of(work, struct mmc_host, detect.work); 1057 container_of(work, struct mmc_host, detect.work);
1058 u32 ocr; 1058 u32 ocr;
1059 int err; 1059 int err;
1060 unsigned long flags;
1061
1062 spin_lock_irqsave(&host->lock, flags);
1063
1064 if (host->rescan_disable) {
1065 spin_unlock_irqrestore(&host->lock, flags);
1066 return;
1067 }
1068
1069 spin_unlock_irqrestore(&host->lock, flags);
1070
1060 1071
1061 mmc_bus_get(host); 1072 mmc_bus_get(host);
1062 1073
@@ -1274,19 +1285,6 @@ int mmc_suspend_host(struct mmc_host *host)
1274 if (host->bus_ops && !host->bus_dead) { 1285 if (host->bus_ops && !host->bus_dead) {
1275 if (host->bus_ops->suspend) 1286 if (host->bus_ops->suspend)
1276 err = host->bus_ops->suspend(host); 1287 err = host->bus_ops->suspend(host);
1277 if (err == -ENOSYS || !host->bus_ops->resume) {
1278 /*
1279 * We simply "remove" the card in this case.
1280 * It will be redetected on resume.
1281 */
1282 if (host->bus_ops->remove)
1283 host->bus_ops->remove(host);
1284 mmc_claim_host(host);
1285 mmc_detach_bus(host);
1286 mmc_release_host(host);
1287 host->pm_flags = 0;
1288 err = 0;
1289 }
1290 } 1288 }
1291 mmc_bus_put(host); 1289 mmc_bus_put(host);
1292 1290
@@ -1318,28 +1316,61 @@ int mmc_resume_host(struct mmc_host *host)
1318 printk(KERN_WARNING "%s: error %d during resume " 1316 printk(KERN_WARNING "%s: error %d during resume "
1319 "(card was removed?)\n", 1317 "(card was removed?)\n",
1320 mmc_hostname(host), err); 1318 mmc_hostname(host), err);
1321 if (host->bus_ops->remove)
1322 host->bus_ops->remove(host);
1323 mmc_claim_host(host);
1324 mmc_detach_bus(host);
1325 mmc_release_host(host);
1326 /* no need to bother upper layers */
1327 err = 0; 1319 err = 0;
1328 } 1320 }
1329 } 1321 }
1330 mmc_bus_put(host); 1322 mmc_bus_put(host);
1331 1323
1332 /*
1333 * We add a slight delay here so that resume can progress
1334 * in parallel.
1335 */
1336 mmc_detect_change(host, 1);
1337
1338 return err; 1324 return err;
1339} 1325}
1340
1341EXPORT_SYMBOL(mmc_resume_host); 1326EXPORT_SYMBOL(mmc_resume_host);
1342 1327
1328/* Do the card removal on suspend if card is assumed removeable
1329 * Do that in pm notifier while userspace isn't yet frozen, so we will be able
1330 to sync the card.
1331*/
1332int mmc_pm_notify(struct notifier_block *notify_block,
1333 unsigned long mode, void *unused)
1334{
1335 struct mmc_host *host = container_of(
1336 notify_block, struct mmc_host, pm_notify);
1337 unsigned long flags;
1338
1339
1340 switch (mode) {
1341 case PM_HIBERNATION_PREPARE:
1342 case PM_SUSPEND_PREPARE:
1343
1344 spin_lock_irqsave(&host->lock, flags);
1345 host->rescan_disable = 1;
1346 spin_unlock_irqrestore(&host->lock, flags);
1347 cancel_delayed_work_sync(&host->detect);
1348
1349 if (!host->bus_ops || host->bus_ops->suspend)
1350 break;
1351
1352 mmc_claim_host(host);
1353
1354 if (host->bus_ops->remove)
1355 host->bus_ops->remove(host);
1356
1357 mmc_detach_bus(host);
1358 mmc_release_host(host);
1359 host->pm_flags = 0;
1360 break;
1361
1362 case PM_POST_SUSPEND:
1363 case PM_POST_HIBERNATION:
1364
1365 spin_lock_irqsave(&host->lock, flags);
1366 host->rescan_disable = 0;
1367 spin_unlock_irqrestore(&host->lock, flags);
1368 mmc_detect_change(host, 0);
1369
1370 }
1371
1372 return 0;
1373}
1343#endif 1374#endif
1344 1375
1345static int __init mmc_init(void) 1376static int __init mmc_init(void)
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 47353909e345..0efe631e50ca 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -17,6 +17,7 @@
17#include <linux/pagemap.h> 17#include <linux/pagemap.h>
18#include <linux/leds.h> 18#include <linux/leds.h>
19#include <linux/slab.h> 19#include <linux/slab.h>
20#include <linux/suspend.h>
20 21
21#include <linux/mmc/host.h> 22#include <linux/mmc/host.h>
22 23
@@ -85,6 +86,7 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
85 init_waitqueue_head(&host->wq); 86 init_waitqueue_head(&host->wq);
86 INIT_DELAYED_WORK(&host->detect, mmc_rescan); 87 INIT_DELAYED_WORK(&host->detect, mmc_rescan);
87 INIT_DELAYED_WORK_DEFERRABLE(&host->disable, mmc_host_deeper_disable); 88 INIT_DELAYED_WORK_DEFERRABLE(&host->disable, mmc_host_deeper_disable);
89 host->pm_notify.notifier_call = mmc_pm_notify;
88 90
89 /* 91 /*
90 * By default, hosts do not support SGIO or large requests. 92 * By default, hosts do not support SGIO or large requests.
@@ -133,6 +135,7 @@ int mmc_add_host(struct mmc_host *host)
133#endif 135#endif
134 136
135 mmc_start_host(host); 137 mmc_start_host(host);
138 register_pm_notifier(&host->pm_notify);
136 139
137 return 0; 140 return 0;
138} 141}
@@ -149,6 +152,7 @@ EXPORT_SYMBOL(mmc_add_host);
149 */ 152 */
150void mmc_remove_host(struct mmc_host *host) 153void mmc_remove_host(struct mmc_host *host)
151{ 154{
155 unregister_pm_notifier(&host->pm_notify);
152 mmc_stop_host(host); 156 mmc_stop_host(host);
153 157
154#ifdef CONFIG_DEBUG_FS 158#ifdef CONFIG_DEBUG_FS