|
@@ -1321,6 +1321,45 @@ err:
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
+static int mmc_can_sleep(struct mmc_card *card)
|
|
|
+{
|
|
|
+ return (card && card->ext_csd.rev >= 3);
|
|
|
+}
|
|
|
+
|
|
|
+static int mmc_sleep(struct mmc_host *host)
|
|
|
+{
|
|
|
+ struct mmc_command cmd = {0};
|
|
|
+ struct mmc_card *card = host->card;
|
|
|
+ int err;
|
|
|
+
|
|
|
+ if (host->caps2 & MMC_CAP2_NO_SLEEP_CMD)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ err = mmc_deselect_cards(host);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
+
|
|
|
+ cmd.opcode = MMC_SLEEP_AWAKE;
|
|
|
+ cmd.arg = card->rca << 16;
|
|
|
+ cmd.arg |= 1 << 15;
|
|
|
+
|
|
|
+ cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
|
|
|
+ err = mmc_wait_for_cmd(host, &cmd, 0);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If the host does not wait while the card signals busy, then we will
|
|
|
+ * will have to wait the sleep/awake timeout. Note, we cannot use the
|
|
|
+ * SEND_STATUS command to poll the status because that command (and most
|
|
|
+ * others) is invalid while the card sleeps.
|
|
|
+ */
|
|
|
+ if (!(host->caps & MMC_CAP_WAIT_WHILE_BUSY))
|
|
|
+ mmc_delay(DIV_ROUND_UP(card->ext_csd.sa_timeout, 10000));
|
|
|
+
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
static int mmc_can_poweroff_notify(const struct mmc_card *card)
|
|
|
{
|
|
|
return card &&
|
|
@@ -1423,8 +1462,8 @@ static int mmc_suspend(struct mmc_host *host)
|
|
|
|
|
|
if (mmc_can_poweroff_notify(host->card))
|
|
|
err = mmc_poweroff_notify(host->card, EXT_CSD_POWER_OFF_SHORT);
|
|
|
- else if (mmc_card_can_sleep(host))
|
|
|
- err = mmc_card_sleep(host);
|
|
|
+ else if (mmc_can_sleep(host->card))
|
|
|
+ err = mmc_sleep(host);
|
|
|
else if (!mmc_host_is_spi(host))
|
|
|
err = mmc_deselect_cards(host);
|
|
|
host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
|
|
@@ -1514,39 +1553,7 @@ static int mmc_power_restore(struct mmc_host *host)
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-static int mmc_sleep(struct mmc_host *host)
|
|
|
-{
|
|
|
- struct mmc_card *card = host->card;
|
|
|
- int err = -ENOSYS;
|
|
|
-
|
|
|
- if (card && card->ext_csd.rev >= 3) {
|
|
|
- err = mmc_card_sleepawake(host, 1);
|
|
|
- if (err < 0)
|
|
|
- pr_debug("%s: Error %d while putting card into sleep",
|
|
|
- mmc_hostname(host), err);
|
|
|
- }
|
|
|
-
|
|
|
- return err;
|
|
|
-}
|
|
|
-
|
|
|
-static int mmc_awake(struct mmc_host *host)
|
|
|
-{
|
|
|
- struct mmc_card *card = host->card;
|
|
|
- int err = -ENOSYS;
|
|
|
-
|
|
|
- if (card && card->ext_csd.rev >= 3) {
|
|
|
- err = mmc_card_sleepawake(host, 0);
|
|
|
- if (err < 0)
|
|
|
- pr_debug("%s: Error %d while awaking sleeping card",
|
|
|
- mmc_hostname(host), err);
|
|
|
- }
|
|
|
-
|
|
|
- return err;
|
|
|
-}
|
|
|
-
|
|
|
static const struct mmc_bus_ops mmc_ops = {
|
|
|
- .awake = mmc_awake,
|
|
|
- .sleep = mmc_sleep,
|
|
|
.remove = mmc_remove,
|
|
|
.detect = mmc_detect,
|
|
|
.suspend = NULL,
|
|
@@ -1556,8 +1563,6 @@ static const struct mmc_bus_ops mmc_ops = {
|
|
|
};
|
|
|
|
|
|
static const struct mmc_bus_ops mmc_ops_unsafe = {
|
|
|
- .awake = mmc_awake,
|
|
|
- .sleep = mmc_sleep,
|
|
|
.remove = mmc_remove,
|
|
|
.detect = mmc_detect,
|
|
|
.suspend = mmc_suspend,
|