diff options
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/core/core.c | 35 | ||||
-rw-r--r-- | drivers/mmc/core/core.h | 4 | ||||
-rw-r--r-- | drivers/mmc/core/mmc.c | 15 | ||||
-rw-r--r-- | drivers/mmc/core/sd.c | 15 | ||||
-rw-r--r-- | drivers/mmc/core/sdio.c | 54 |
5 files changed, 69 insertions, 54 deletions
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 0842f6829250..7dab2e5f4bc9 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c | |||
@@ -1236,6 +1236,8 @@ EXPORT_SYMBOL(mmc_card_can_sleep); | |||
1236 | */ | 1236 | */ |
1237 | int mmc_suspend_host(struct mmc_host *host, pm_message_t state) | 1237 | int mmc_suspend_host(struct mmc_host *host, pm_message_t state) |
1238 | { | 1238 | { |
1239 | int err = 0; | ||
1240 | |||
1239 | if (host->caps & MMC_CAP_DISABLE) | 1241 | if (host->caps & MMC_CAP_DISABLE) |
1240 | cancel_delayed_work(&host->disable); | 1242 | cancel_delayed_work(&host->disable); |
1241 | cancel_delayed_work(&host->detect); | 1243 | cancel_delayed_work(&host->detect); |
@@ -1244,21 +1246,26 @@ int mmc_suspend_host(struct mmc_host *host, pm_message_t state) | |||
1244 | mmc_bus_get(host); | 1246 | mmc_bus_get(host); |
1245 | if (host->bus_ops && !host->bus_dead) { | 1247 | if (host->bus_ops && !host->bus_dead) { |
1246 | if (host->bus_ops->suspend) | 1248 | if (host->bus_ops->suspend) |
1247 | host->bus_ops->suspend(host); | 1249 | err = host->bus_ops->suspend(host); |
1248 | if (!host->bus_ops->resume) { | 1250 | if (err == -ENOSYS || !host->bus_ops->resume) { |
1251 | /* | ||
1252 | * We simply "remove" the card in this case. | ||
1253 | * It will be redetected on resume. | ||
1254 | */ | ||
1249 | if (host->bus_ops->remove) | 1255 | if (host->bus_ops->remove) |
1250 | host->bus_ops->remove(host); | 1256 | host->bus_ops->remove(host); |
1251 | |||
1252 | mmc_claim_host(host); | 1257 | mmc_claim_host(host); |
1253 | mmc_detach_bus(host); | 1258 | mmc_detach_bus(host); |
1254 | mmc_release_host(host); | 1259 | mmc_release_host(host); |
1260 | err = 0; | ||
1255 | } | 1261 | } |
1256 | } | 1262 | } |
1257 | mmc_bus_put(host); | 1263 | mmc_bus_put(host); |
1258 | 1264 | ||
1259 | mmc_power_off(host); | 1265 | if (!err) |
1266 | mmc_power_off(host); | ||
1260 | 1267 | ||
1261 | return 0; | 1268 | return err; |
1262 | } | 1269 | } |
1263 | 1270 | ||
1264 | EXPORT_SYMBOL(mmc_suspend_host); | 1271 | EXPORT_SYMBOL(mmc_suspend_host); |
@@ -1269,12 +1276,26 @@ EXPORT_SYMBOL(mmc_suspend_host); | |||
1269 | */ | 1276 | */ |
1270 | int mmc_resume_host(struct mmc_host *host) | 1277 | int mmc_resume_host(struct mmc_host *host) |
1271 | { | 1278 | { |
1279 | int err = 0; | ||
1280 | |||
1272 | mmc_bus_get(host); | 1281 | mmc_bus_get(host); |
1273 | if (host->bus_ops && !host->bus_dead) { | 1282 | if (host->bus_ops && !host->bus_dead) { |
1274 | mmc_power_up(host); | 1283 | mmc_power_up(host); |
1275 | mmc_select_voltage(host, host->ocr); | 1284 | mmc_select_voltage(host, host->ocr); |
1276 | BUG_ON(!host->bus_ops->resume); | 1285 | BUG_ON(!host->bus_ops->resume); |
1277 | host->bus_ops->resume(host); | 1286 | err = host->bus_ops->resume(host); |
1287 | if (err) { | ||
1288 | printk(KERN_WARNING "%s: error %d during resume " | ||
1289 | "(card was removed?)\n", | ||
1290 | mmc_hostname(host), err); | ||
1291 | if (host->bus_ops->remove) | ||
1292 | host->bus_ops->remove(host); | ||
1293 | mmc_claim_host(host); | ||
1294 | mmc_detach_bus(host); | ||
1295 | mmc_release_host(host); | ||
1296 | /* no need to bother upper layers */ | ||
1297 | err = 0; | ||
1298 | } | ||
1278 | } | 1299 | } |
1279 | mmc_bus_put(host); | 1300 | mmc_bus_put(host); |
1280 | 1301 | ||
@@ -1284,7 +1305,7 @@ int mmc_resume_host(struct mmc_host *host) | |||
1284 | */ | 1305 | */ |
1285 | mmc_detect_change(host, 1); | 1306 | mmc_detect_change(host, 1); |
1286 | 1307 | ||
1287 | return 0; | 1308 | return err; |
1288 | } | 1309 | } |
1289 | 1310 | ||
1290 | EXPORT_SYMBOL(mmc_resume_host); | 1311 | EXPORT_SYMBOL(mmc_resume_host); |
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h index c386348f5f73..67ae6abc4230 100644 --- a/drivers/mmc/core/core.h +++ b/drivers/mmc/core/core.h | |||
@@ -20,8 +20,8 @@ struct mmc_bus_ops { | |||
20 | int (*sleep)(struct mmc_host *); | 20 | int (*sleep)(struct mmc_host *); |
21 | void (*remove)(struct mmc_host *); | 21 | void (*remove)(struct mmc_host *); |
22 | void (*detect)(struct mmc_host *); | 22 | void (*detect)(struct mmc_host *); |
23 | void (*suspend)(struct mmc_host *); | 23 | int (*suspend)(struct mmc_host *); |
24 | void (*resume)(struct mmc_host *); | 24 | int (*resume)(struct mmc_host *); |
25 | void (*power_save)(struct mmc_host *); | 25 | void (*power_save)(struct mmc_host *); |
26 | void (*power_restore)(struct mmc_host *); | 26 | void (*power_restore)(struct mmc_host *); |
27 | }; | 27 | }; |
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index ddddad46b402..bfefce365ae7 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c | |||
@@ -530,7 +530,7 @@ static void mmc_detect(struct mmc_host *host) | |||
530 | /* | 530 | /* |
531 | * Suspend callback from host. | 531 | * Suspend callback from host. |
532 | */ | 532 | */ |
533 | static void mmc_suspend(struct mmc_host *host) | 533 | static int mmc_suspend(struct mmc_host *host) |
534 | { | 534 | { |
535 | BUG_ON(!host); | 535 | BUG_ON(!host); |
536 | BUG_ON(!host->card); | 536 | BUG_ON(!host->card); |
@@ -540,6 +540,8 @@ static void mmc_suspend(struct mmc_host *host) | |||
540 | mmc_deselect_cards(host); | 540 | mmc_deselect_cards(host); |
541 | host->card->state &= ~MMC_STATE_HIGHSPEED; | 541 | host->card->state &= ~MMC_STATE_HIGHSPEED; |
542 | mmc_release_host(host); | 542 | mmc_release_host(host); |
543 | |||
544 | return 0; | ||
543 | } | 545 | } |
544 | 546 | ||
545 | /* | 547 | /* |
@@ -548,7 +550,7 @@ static void mmc_suspend(struct mmc_host *host) | |||
548 | * This function tries to determine if the same card is still present | 550 | * This function tries to determine if the same card is still present |
549 | * and, if so, restore all state to it. | 551 | * and, if so, restore all state to it. |
550 | */ | 552 | */ |
551 | static void mmc_resume(struct mmc_host *host) | 553 | static int mmc_resume(struct mmc_host *host) |
552 | { | 554 | { |
553 | int err; | 555 | int err; |
554 | 556 | ||
@@ -559,14 +561,7 @@ static void mmc_resume(struct mmc_host *host) | |||
559 | err = mmc_init_card(host, host->ocr, host->card); | 561 | err = mmc_init_card(host, host->ocr, host->card); |
560 | mmc_release_host(host); | 562 | mmc_release_host(host); |
561 | 563 | ||
562 | if (err) { | 564 | return err; |
563 | mmc_remove(host); | ||
564 | |||
565 | mmc_claim_host(host); | ||
566 | mmc_detach_bus(host); | ||
567 | mmc_release_host(host); | ||
568 | } | ||
569 | |||
570 | } | 565 | } |
571 | 566 | ||
572 | static void mmc_power_restore(struct mmc_host *host) | 567 | static void mmc_power_restore(struct mmc_host *host) |
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 13b3a6b8f5b5..10b2a4d20f5a 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c | |||
@@ -564,7 +564,7 @@ static void mmc_sd_detect(struct mmc_host *host) | |||
564 | /* | 564 | /* |
565 | * Suspend callback from host. | 565 | * Suspend callback from host. |
566 | */ | 566 | */ |
567 | static void mmc_sd_suspend(struct mmc_host *host) | 567 | static int mmc_sd_suspend(struct mmc_host *host) |
568 | { | 568 | { |
569 | BUG_ON(!host); | 569 | BUG_ON(!host); |
570 | BUG_ON(!host->card); | 570 | BUG_ON(!host->card); |
@@ -574,6 +574,8 @@ static void mmc_sd_suspend(struct mmc_host *host) | |||
574 | mmc_deselect_cards(host); | 574 | mmc_deselect_cards(host); |
575 | host->card->state &= ~MMC_STATE_HIGHSPEED; | 575 | host->card->state &= ~MMC_STATE_HIGHSPEED; |
576 | mmc_release_host(host); | 576 | mmc_release_host(host); |
577 | |||
578 | return 0; | ||
577 | } | 579 | } |
578 | 580 | ||
579 | /* | 581 | /* |
@@ -582,7 +584,7 @@ static void mmc_sd_suspend(struct mmc_host *host) | |||
582 | * This function tries to determine if the same card is still present | 584 | * This function tries to determine if the same card is still present |
583 | * and, if so, restore all state to it. | 585 | * and, if so, restore all state to it. |
584 | */ | 586 | */ |
585 | static void mmc_sd_resume(struct mmc_host *host) | 587 | static int mmc_sd_resume(struct mmc_host *host) |
586 | { | 588 | { |
587 | int err; | 589 | int err; |
588 | 590 | ||
@@ -593,14 +595,7 @@ static void mmc_sd_resume(struct mmc_host *host) | |||
593 | err = mmc_sd_init_card(host, host->ocr, host->card); | 595 | err = mmc_sd_init_card(host, host->ocr, host->card); |
594 | mmc_release_host(host); | 596 | mmc_release_host(host); |
595 | 597 | ||
596 | if (err) { | 598 | return err; |
597 | mmc_sd_remove(host); | ||
598 | |||
599 | mmc_claim_host(host); | ||
600 | mmc_detach_bus(host); | ||
601 | mmc_release_host(host); | ||
602 | } | ||
603 | |||
604 | } | 599 | } |
605 | 600 | ||
606 | static void mmc_sd_power_restore(struct mmc_host *host) | 601 | static void mmc_sd_power_restore(struct mmc_host *host) |
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index f4c8637fd072..cdb845b68ab5 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c | |||
@@ -302,6 +302,7 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, | |||
302 | goto err; | 302 | goto err; |
303 | } | 303 | } |
304 | card = oldcard; | 304 | card = oldcard; |
305 | return 0; | ||
305 | } | 306 | } |
306 | 307 | ||
307 | /* | 308 | /* |
@@ -399,62 +400,65 @@ static void mmc_sdio_detect(struct mmc_host *host) | |||
399 | * Therefore all registered functions must have drivers with suspend | 400 | * Therefore all registered functions must have drivers with suspend |
400 | * and resume methods. Failing that we simply remove the whole card. | 401 | * and resume methods. Failing that we simply remove the whole card. |
401 | */ | 402 | */ |
402 | static void mmc_sdio_suspend(struct mmc_host *host) | 403 | static int mmc_sdio_suspend(struct mmc_host *host) |
403 | { | 404 | { |
404 | int i; | 405 | int i, err = 0; |
405 | 406 | ||
406 | /* make sure all registered functions can suspend/resume */ | ||
407 | for (i = 0; i < host->card->sdio_funcs; i++) { | 407 | for (i = 0; i < host->card->sdio_funcs; i++) { |
408 | struct sdio_func *func = host->card->sdio_func[i]; | 408 | struct sdio_func *func = host->card->sdio_func[i]; |
409 | if (func && sdio_func_present(func) && func->dev.driver) { | 409 | if (func && sdio_func_present(func) && func->dev.driver) { |
410 | const struct dev_pm_ops *pmops = func->dev.driver->pm; | 410 | const struct dev_pm_ops *pmops = func->dev.driver->pm; |
411 | if (!pmops || !pmops->suspend || !pmops->resume) { | 411 | if (!pmops || !pmops->suspend || !pmops->resume) { |
412 | /* just remove the entire card in that case */ | 412 | /* force removal of entire card in that case */ |
413 | mmc_sdio_remove(host); | 413 | err = -ENOSYS; |
414 | mmc_claim_host(host); | 414 | } else |
415 | mmc_detach_bus(host); | 415 | err = pmops->suspend(&func->dev); |
416 | mmc_release_host(host); | 416 | if (err) |
417 | return; | 417 | break; |
418 | } | ||
419 | } | 418 | } |
420 | } | 419 | } |
421 | 420 | while (err && --i >= 0) { | |
422 | /* now suspend them */ | ||
423 | for (i = 0; i < host->card->sdio_funcs; i++) { | ||
424 | struct sdio_func *func = host->card->sdio_func[i]; | 421 | struct sdio_func *func = host->card->sdio_func[i]; |
425 | if (func && sdio_func_present(func) && func->dev.driver) { | 422 | if (func && sdio_func_present(func) && func->dev.driver) { |
426 | const struct dev_pm_ops *pmops = func->dev.driver->pm; | 423 | const struct dev_pm_ops *pmops = func->dev.driver->pm; |
427 | pmops->suspend(&func->dev); | 424 | pmops->resume(&func->dev); |
428 | } | 425 | } |
429 | } | 426 | } |
427 | |||
428 | return err; | ||
430 | } | 429 | } |
431 | 430 | ||
432 | static void mmc_sdio_resume(struct mmc_host *host) | 431 | static int mmc_sdio_resume(struct mmc_host *host) |
433 | { | 432 | { |
434 | int i, err; | 433 | int i, err; |
435 | 434 | ||
436 | BUG_ON(!host); | 435 | BUG_ON(!host); |
437 | BUG_ON(!host->card); | 436 | BUG_ON(!host->card); |
438 | 437 | ||
438 | /* Basic card reinitialization. */ | ||
439 | mmc_claim_host(host); | 439 | mmc_claim_host(host); |
440 | err = mmc_sdio_init_card(host, host->ocr, host->card); | 440 | err = mmc_sdio_init_card(host, host->ocr, host->card); |
441 | mmc_release_host(host); | 441 | mmc_release_host(host); |
442 | if (err) { | ||
443 | mmc_sdio_remove(host); | ||
444 | mmc_claim_host(host); | ||
445 | mmc_detach_bus(host); | ||
446 | mmc_release_host(host); | ||
447 | return; | ||
448 | } | ||
449 | 442 | ||
450 | /* resume all functions */ | 443 | /* |
451 | for (i = 0; i < host->card->sdio_funcs; i++) { | 444 | * If the card looked to be the same as before suspending, then |
445 | * we proceed to resume all card functions. If one of them returns | ||
446 | * an error then we simply return that error to the core and the | ||
447 | * card will be redetected as new. It is the responsibility of | ||
448 | * the function driver to perform further tests with the extra | ||
449 | * knowledge it has of the card to confirm the card is indeed the | ||
450 | * same as before suspending (same MAC address for network cards, | ||
451 | * etc.) and return an error otherwise. | ||
452 | */ | ||
453 | for (i = 0; !err && i < host->card->sdio_funcs; i++) { | ||
452 | struct sdio_func *func = host->card->sdio_func[i]; | 454 | struct sdio_func *func = host->card->sdio_func[i]; |
453 | if (func && sdio_func_present(func) && func->dev.driver) { | 455 | if (func && sdio_func_present(func) && func->dev.driver) { |
454 | const struct dev_pm_ops *pmops = func->dev.driver->pm; | 456 | const struct dev_pm_ops *pmops = func->dev.driver->pm; |
455 | pmops->resume(&func->dev); | 457 | err = pmops->resume(&func->dev); |
456 | } | 458 | } |
457 | } | 459 | } |
460 | |||
461 | return err; | ||
458 | } | 462 | } |
459 | 463 | ||
460 | static const struct mmc_bus_ops mmc_sdio_ops = { | 464 | static const struct mmc_bus_ops mmc_sdio_ops = { |