]> Pileus Git - ~andy/linux/blobdiff - drivers/mmc/core/mmc.c
Merge branch 'drm-tda998x-3.12-fixes' of git://ftp.arm.linux.org.uk/~rmk/linux-cubox...
[~andy/linux] / drivers / mmc / core / mmc.c
index 8f0c51686849d90fdcf62815e36e6ce9533dfd43..f631f5a9bf7948b848754cc3ba475619c957a79b 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/err.h>
 #include <linux/slab.h>
 #include <linux/stat.h>
+#include <linux/pm_runtime.h>
 
 #include <linux/mmc/host.h>
 #include <linux/mmc/card.h>
@@ -934,6 +935,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
                        goto err;
                }
 
+               card->ocr = ocr;
                card->type = MMC_TYPE_MMC;
                card->rca = 1;
                memcpy(card->raw_cid, cid, sizeof(card->raw_cid));
@@ -1477,6 +1479,9 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
 
        mmc_claim_host(host);
 
+       if (mmc_card_suspended(host->card))
+               goto out;
+
        if (mmc_card_doing_bkops(host->card)) {
                err = mmc_stop_bkops(host->card);
                if (err)
@@ -1496,51 +1501,93 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
                err = mmc_deselect_cards(host);
        host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
 
-       if (!err)
+       if (!err) {
                mmc_power_off(host);
+               mmc_card_set_suspended(host->card);
+       }
 out:
        mmc_release_host(host);
        return err;
 }
 
 /*
- * Suspend callback from host.
+ * Suspend callback
  */
 static int mmc_suspend(struct mmc_host *host)
 {
-       return _mmc_suspend(host, true);
-}
+       int err;
 
-/*
- * Shutdown callback
- */
-static int mmc_shutdown(struct mmc_host *host)
-{
-       return _mmc_suspend(host, false);
+       err = _mmc_suspend(host, true);
+       if (!err) {
+               pm_runtime_disable(&host->card->dev);
+               pm_runtime_set_suspended(&host->card->dev);
+       }
+
+       return err;
 }
 
 /*
- * Resume callback from host.
- *
  * This function tries to determine if the same card is still present
  * and, if so, restore all state to it.
  */
-static int mmc_resume(struct mmc_host *host)
+static int _mmc_resume(struct mmc_host *host)
 {
-       int err;
+       int err = 0;
 
        BUG_ON(!host);
        BUG_ON(!host->card);
 
        mmc_claim_host(host);
-       mmc_power_up(host);
-       mmc_select_voltage(host, host->ocr);
-       err = mmc_init_card(host, host->ocr, host->card);
+
+       if (!mmc_card_suspended(host->card))
+               goto out;
+
+       mmc_power_up(host, host->card->ocr);
+       err = mmc_init_card(host, host->card->ocr, host->card);
+       mmc_card_clr_suspended(host->card);
+
+out:
        mmc_release_host(host);
+       return err;
+}
+
+/*
+ * Shutdown callback
+ */
+static int mmc_shutdown(struct mmc_host *host)
+{
+       int err = 0;
+
+       /*
+        * In a specific case for poweroff notify, we need to resume the card
+        * before we can shutdown it properly.
+        */
+       if (mmc_can_poweroff_notify(host->card) &&
+               !(host->caps2 & MMC_CAP2_FULL_PWR_CYCLE))
+               err = _mmc_resume(host);
+
+       if (!err)
+               err = _mmc_suspend(host, false);
 
        return err;
 }
 
+/*
+ * Callback for resume.
+ */
+static int mmc_resume(struct mmc_host *host)
+{
+       int err = 0;
+
+       if (!(host->caps & MMC_CAP_RUNTIME_RESUME)) {
+               err = _mmc_resume(host);
+               pm_runtime_set_active(&host->card->dev);
+               pm_runtime_mark_last_busy(&host->card->dev);
+       }
+       pm_runtime_enable(&host->card->dev);
+
+       return err;
+}
 
 /*
  * Callback for runtime_suspend.
@@ -1552,18 +1599,11 @@ static int mmc_runtime_suspend(struct mmc_host *host)
        if (!(host->caps & MMC_CAP_AGGRESSIVE_PM))
                return 0;
 
-       mmc_claim_host(host);
-
-       err = mmc_suspend(host);
-       if (err) {
+       err = _mmc_suspend(host, true);
+       if (err)
                pr_err("%s: error %d doing aggessive suspend\n",
                        mmc_hostname(host), err);
-               goto out;
-       }
-       mmc_power_off(host);
 
-out:
-       mmc_release_host(host);
        return err;
 }
 
@@ -1574,18 +1614,14 @@ static int mmc_runtime_resume(struct mmc_host *host)
 {
        int err;
 
-       if (!(host->caps & MMC_CAP_AGGRESSIVE_PM))
+       if (!(host->caps & (MMC_CAP_AGGRESSIVE_PM | MMC_CAP_RUNTIME_RESUME)))
                return 0;
 
-       mmc_claim_host(host);
-
-       mmc_power_up(host);
-       err = mmc_resume(host);
+       err = _mmc_resume(host);
        if (err)
                pr_err("%s: error %d doing aggessive resume\n",
                        mmc_hostname(host), err);
 
-       mmc_release_host(host);
        return 0;
 }
 
@@ -1595,7 +1631,7 @@ static int mmc_power_restore(struct mmc_host *host)
 
        host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
        mmc_claim_host(host);
-       ret = mmc_init_card(host, host->ocr, host->card);
+       ret = mmc_init_card(host, host->card->ocr, host->card);
        mmc_release_host(host);
 
        return ret;
@@ -1640,7 +1676,7 @@ static void mmc_attach_bus_ops(struct mmc_host *host)
 int mmc_attach_mmc(struct mmc_host *host)
 {
        int err;
-       u32 ocr;
+       u32 ocr, rocr;
 
        BUG_ON(!host);
        WARN_ON(!host->claimed);
@@ -1666,23 +1702,12 @@ int mmc_attach_mmc(struct mmc_host *host)
                        goto err;
        }
 
-       /*
-        * Sanity check the voltages that the card claims to
-        * support.
-        */
-       if (ocr & 0x7F) {
-               pr_warning("%s: card claims to support voltages "
-                      "below the defined range. These will be ignored.\n",
-                      mmc_hostname(host));
-               ocr &= ~0x7F;
-       }
-
-       host->ocr = mmc_select_voltage(host, ocr);
+       rocr = mmc_select_voltage(host, ocr);
 
        /*
         * Can we support the voltage of the card?
         */
-       if (!host->ocr) {
+       if (!rocr) {
                err = -EINVAL;
                goto err;
        }
@@ -1690,7 +1715,7 @@ int mmc_attach_mmc(struct mmc_host *host)
        /*
         * Detect and init the card.
         */
-       err = mmc_init_card(host, host->ocr, NULL);
+       err = mmc_init_card(host, rocr, NULL);
        if (err)
                goto err;