aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/core/core.c35
-rw-r--r--drivers/mmc/core/core.h4
-rw-r--r--drivers/mmc/core/mmc.c15
-rw-r--r--drivers/mmc/core/sd.c15
-rw-r--r--drivers/mmc/core/sdio.c54
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 */
1237int mmc_suspend_host(struct mmc_host *host, pm_message_t state) 1237int 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
1264EXPORT_SYMBOL(mmc_suspend_host); 1271EXPORT_SYMBOL(mmc_suspend_host);
@@ -1269,12 +1276,26 @@ EXPORT_SYMBOL(mmc_suspend_host);
1269 */ 1276 */
1270int mmc_resume_host(struct mmc_host *host) 1277int 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
1290EXPORT_SYMBOL(mmc_resume_host); 1311EXPORT_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 */
533static void mmc_suspend(struct mmc_host *host) 533static 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 */
551static void mmc_resume(struct mmc_host *host) 553static 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
572static void mmc_power_restore(struct mmc_host *host) 567static 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 */
567static void mmc_sd_suspend(struct mmc_host *host) 567static 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 */
585static void mmc_sd_resume(struct mmc_host *host) 587static 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
606static void mmc_sd_power_restore(struct mmc_host *host) 601static 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 */
402static void mmc_sdio_suspend(struct mmc_host *host) 403static 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
432static void mmc_sdio_resume(struct mmc_host *host) 431static 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
460static const struct mmc_bus_ops mmc_sdio_ops = { 464static const struct mmc_bus_ops mmc_sdio_ops = {