diff options
Diffstat (limited to 'drivers/mmc/core/mmc_ops.c')
| -rw-r--r-- | drivers/mmc/core/mmc_ops.c | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index 34ce2703d29a..d2cb5c634392 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c | |||
| @@ -57,6 +57,42 @@ int mmc_deselect_cards(struct mmc_host *host) | |||
| 57 | return _mmc_select_card(host, NULL); | 57 | return _mmc_select_card(host, NULL); |
| 58 | } | 58 | } |
| 59 | 59 | ||
| 60 | int mmc_card_sleepawake(struct mmc_host *host, int sleep) | ||
| 61 | { | ||
| 62 | struct mmc_command cmd; | ||
| 63 | struct mmc_card *card = host->card; | ||
| 64 | int err; | ||
| 65 | |||
| 66 | if (sleep) | ||
| 67 | mmc_deselect_cards(host); | ||
| 68 | |||
| 69 | memset(&cmd, 0, sizeof(struct mmc_command)); | ||
| 70 | |||
| 71 | cmd.opcode = MMC_SLEEP_AWAKE; | ||
| 72 | cmd.arg = card->rca << 16; | ||
| 73 | if (sleep) | ||
| 74 | cmd.arg |= 1 << 15; | ||
| 75 | |||
| 76 | cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; | ||
| 77 | err = mmc_wait_for_cmd(host, &cmd, 0); | ||
| 78 | if (err) | ||
| 79 | return err; | ||
| 80 | |||
| 81 | /* | ||
| 82 | * If the host does not wait while the card signals busy, then we will | ||
| 83 | * will have to wait the sleep/awake timeout. Note, we cannot use the | ||
| 84 | * SEND_STATUS command to poll the status because that command (and most | ||
| 85 | * others) is invalid while the card sleeps. | ||
| 86 | */ | ||
| 87 | if (!(host->caps & MMC_CAP_WAIT_WHILE_BUSY)) | ||
| 88 | mmc_delay(DIV_ROUND_UP(card->ext_csd.sa_timeout, 10000)); | ||
| 89 | |||
| 90 | if (!sleep) | ||
| 91 | err = mmc_select_card(card); | ||
| 92 | |||
| 93 | return err; | ||
| 94 | } | ||
| 95 | |||
| 60 | int mmc_go_idle(struct mmc_host *host) | 96 | int mmc_go_idle(struct mmc_host *host) |
| 61 | { | 97 | { |
| 62 | int err; | 98 | int err; |
| @@ -354,6 +390,7 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value) | |||
| 354 | { | 390 | { |
| 355 | int err; | 391 | int err; |
| 356 | struct mmc_command cmd; | 392 | struct mmc_command cmd; |
| 393 | u32 status; | ||
| 357 | 394 | ||
| 358 | BUG_ON(!card); | 395 | BUG_ON(!card); |
| 359 | BUG_ON(!card->host); | 396 | BUG_ON(!card->host); |
| @@ -371,6 +408,28 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value) | |||
| 371 | if (err) | 408 | if (err) |
| 372 | return err; | 409 | return err; |
| 373 | 410 | ||
| 411 | /* Must check status to be sure of no errors */ | ||
| 412 | do { | ||
| 413 | err = mmc_send_status(card, &status); | ||
| 414 | if (err) | ||
| 415 | return err; | ||
| 416 | if (card->host->caps & MMC_CAP_WAIT_WHILE_BUSY) | ||
| 417 | break; | ||
| 418 | if (mmc_host_is_spi(card->host)) | ||
| 419 | break; | ||
| 420 | } while (R1_CURRENT_STATE(status) == 7); | ||
| 421 | |||
| 422 | if (mmc_host_is_spi(card->host)) { | ||
| 423 | if (status & R1_SPI_ILLEGAL_COMMAND) | ||
| 424 | return -EBADMSG; | ||
| 425 | } else { | ||
| 426 | if (status & 0xFDFFA000) | ||
| 427 | printk(KERN_WARNING "%s: unexpected status %#x after " | ||
| 428 | "switch", mmc_hostname(card->host), status); | ||
| 429 | if (status & R1_SWITCH_ERROR) | ||
| 430 | return -EBADMSG; | ||
| 431 | } | ||
| 432 | |||
| 374 | return 0; | 433 | return 0; |
| 375 | } | 434 | } |
| 376 | 435 | ||
