diff options
Diffstat (limited to 'drivers/mmc/core/core.c')
-rw-r--r-- | drivers/mmc/core/core.c | 83 |
1 files changed, 57 insertions, 26 deletions
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index b69ce91b11e..83240faa1dc 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 | |||
1341 | EXPORT_SYMBOL(mmc_resume_host); | 1326 | EXPORT_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 | */ | ||
1332 | int 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 | ||
1345 | static int __init mmc_init(void) | 1376 | static int __init mmc_init(void) |