mmc: core: Fix PowerOff Notify suspend/resume
Pavan Kunapuli [Fri, 27 Jul 2012 09:48:02 +0000 (14:48 +0530)]
Modified the mmc_poweroff to resume before sending the poweroff
notification command. In sleep mode only AWAKE and RESET commands are
allowed, so before sending the poweroff notification command resume from
sleep mode and then send the notification command.

PowerOff Notify is tested on a Synopsis Designware Host Controller
(eMMC 4.5). The suspend to RAM and resume works fine.

Change-Id: Ib4642a29e423aee6041a92cc72a388d677674ae3
Signed-off-by: Girish K S <girish.shivananjappa@linaro.org>
Tested-by: Girish K S <girish.shivananjappa@linaro.org>
Reviewed-by: Saugata Das <saugata.das@linaro.org>
Signed-off-by: Chris Ball <cjb@laptop.org>

Bug 1007644
Bug 936069

Signed-off-by: Pavan Kunapuli <pkunapuli@nvidia.com>
Change-Id: I2e3d421c82eb765cb640876691ffe4818d7e146b
Reviewed-on: http://git-master/r/118918
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Min-wuk Lee <mlee@nvidia.com>
Reviewed-by: Naveen Kumar Arepalli <naveenk@nvidia.com>
Reviewed-by: Laxman Dewangan <ldewangan@nvidia.com>

drivers/mmc/core/mmc.c
include/linux/mmc/card.h

index 40c93b3..0e8001f 100644 (file)
@@ -976,13 +976,19 @@ static void mmc_detect(struct mmc_host *host)
  */
 static int mmc_suspend(struct mmc_host *host)
 {
+       int err;
+
        BUG_ON(!host);
        BUG_ON(!host->card);
 
        mmc_claim_host(host);
-       if (!mmc_host_is_spi(host))
+       if (mmc_card_can_sleep(host)) {
+               err = mmc_card_sleep(host);
+               if (!err)
+                       mmc_card_set_sleep(host->card);
+       } else if (!mmc_host_is_spi(host))
                mmc_deselect_cards(host);
-       host->card->state &= ~MMC_STATE_HIGHSPEED;
+       host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
        mmc_release_host(host);
 
        return 0;
@@ -1002,7 +1008,11 @@ static int mmc_resume(struct mmc_host *host)
        BUG_ON(!host->card);
 
        mmc_claim_host(host);
-       err = mmc_init_card(host, host->ocr, host->card);
+       if (mmc_card_is_sleep(host->card)) {
+               err = mmc_card_awake(host);
+               mmc_card_clr_sleep(host->card);
+       } else
+               err = mmc_init_card(host, host->ocr, host->card);
        mmc_release_host(host);
 
        return err;
@@ -1012,7 +1022,8 @@ static int mmc_power_restore(struct mmc_host *host)
 {
        int ret;
 
-       host->card->state &= ~MMC_STATE_HIGHSPEED;
+       host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
+       mmc_card_clr_sleep(host->card);
        mmc_claim_host(host);
        ret = mmc_init_card(host, host->ocr, host->card);
        mmc_release_host(host);
index 8f17619..4d50754 100644 (file)
@@ -188,7 +188,11 @@ struct mmc_card {
 #define MMC_STATE_ULTRAHIGHSPEED (1<<5)                /* card is in ultra high speed mode */
 #define MMC_STATE_DOING_BKOPS  (1<<6)          /* Card doing bkops */
 #define MMC_STATE_NEED_BKOPS   (1<<7)          /* Card needs to do bkops */
-#define MMC_CARD_SDXC          (1<<6)          /* card is SDXC */
+#define MMC_CARD_SDXC          (1<<8)          /* card is SDXC */
+#define MMC_CARD_REMOVED       (1<<9)          /* card has been removed */
+#define MMC_STATE_HIGHSPEED_200        (1<<10)         /* card is in HS200 mode */
+#define MMC_STATE_SLEEP                (1<<11)         /* card is in sleep state */
+
        unsigned int            quirks;         /* card quirks */
 #define MMC_QUIRK_LENIENT_FN0  (1<<0)          /* allow SDIO FN0 writes outside of the VS CCCR range */
 #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1)   /* use func->cur_blksize */
@@ -332,6 +336,9 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
 #define mmc_card_ext_capacity(c) ((c)->state & MMC_CARD_SDXC)
 #define mmc_card_doing_bkops(c) ((c)->state & MMC_STATE_DOING_BKOPS)
 #define mmc_card_need_bkops(c) ((c)->state & MMC_STATE_NEED_BKOPS)
+#define mmc_card_removed(c)    ((c) && ((c)->state & MMC_CARD_REMOVED))
+#define mmc_card_is_sleep(c)   ((c)->state & MMC_STATE_SLEEP)
+
 #define mmc_card_set_present(c)        ((c)->state |= MMC_STATE_PRESENT)
 #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
 #define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED)
@@ -339,7 +346,10 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
 #define mmc_card_set_ddr_mode(c) ((c)->state |= MMC_STATE_HIGHSPEED_DDR)
 #define mmc_sd_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED)
 #define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC)
+#define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED)
+#define mmc_card_set_sleep(c)  ((c)->state |= MMC_STATE_SLEEP)
 
+#define mmc_card_clr_sleep(c)  ((c)->state &= ~MMC_STATE_SLEEP)
 /*
  * Quirk add/remove for MMC products.
  */