Maemo patchset 20101501+0m5
[h-e-n] / drivers / mmc / core / mmc.c
index fdd7c76..f87cc0b 100644 (file)
@@ -160,7 +160,6 @@ static int mmc_read_ext_csd(struct mmc_card *card)
 {
        int err;
        u8 *ext_csd;
-       unsigned int ext_csd_struct;
 
        BUG_ON(!card);
 
@@ -207,16 +206,16 @@ static int mmc_read_ext_csd(struct mmc_card *card)
                goto out;
        }
 
-       ext_csd_struct = ext_csd[EXT_CSD_REV];
-       if (ext_csd_struct > 2) {
+       card->ext_csd.rev = ext_csd[EXT_CSD_REV];
+       if (card->ext_csd.rev > 3) {
                printk(KERN_ERR "%s: unrecognised EXT_CSD structure "
                        "version %d\n", mmc_hostname(card->host),
-                       ext_csd_struct);
+                       card->ext_csd.rev);
                err = -EINVAL;
                goto out;
        }
 
-       if (ext_csd_struct >= 2) {
+       if (card->ext_csd.rev >= 2) {
                card->ext_csd.sectors =
                        ext_csd[EXT_CSD_SEC_CNT + 0] << 0 |
                        ext_csd[EXT_CSD_SEC_CNT + 1] << 8 |
@@ -241,6 +240,15 @@ static int mmc_read_ext_csd(struct mmc_card *card)
                goto out;
        }
 
+       if (card->ext_csd.rev >= 3) {
+               u8 sa_shift = ext_csd[EXT_CSD_S_A_TIMEOUT];
+
+               /* Sleep / awake timeout in 100ns units */
+               if (sa_shift > 0 && sa_shift <= 0x17)
+                       card->ext_csd.sa_timeout =
+                                       1 << ext_csd[EXT_CSD_S_A_TIMEOUT];
+       }
+
 out:
        kfree(ext_csd);
 
@@ -408,12 +416,17 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
                (host->caps & MMC_CAP_MMC_HIGHSPEED)) {
                err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
                        EXT_CSD_HS_TIMING, 1);
-               if (err)
+               if (err && err != -EBADMSG)
                        goto free_card;
 
-               mmc_card_set_highspeed(card);
-
-               mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
+               if (err) {
+                       printk(KERN_WARNING "%s: switch to highspeed failed\n",
+                              mmc_hostname(card->host));
+                       err = 0;
+               } else {
+                       mmc_card_set_highspeed(card);
+                       mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
+               }
        }
 
        /*
@@ -434,13 +447,31 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
         * Activate wide bus (if supported).
         */
        if ((card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
-               (host->caps & MMC_CAP_4_BIT_DATA)) {
+           (host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) {
+               unsigned ext_csd_bit, bus_width;
+
+               if (host->caps & MMC_CAP_8_BIT_DATA) {
+                       ext_csd_bit = EXT_CSD_BUS_WIDTH_8;
+                       bus_width = MMC_BUS_WIDTH_8;
+               } else {
+                       ext_csd_bit = EXT_CSD_BUS_WIDTH_4;
+                       bus_width = MMC_BUS_WIDTH_4;
+               }
+
                err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-                       EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_4);
-               if (err)
+                                EXT_CSD_BUS_WIDTH, ext_csd_bit);
+
+               if (err && err != -EBADMSG)
                        goto free_card;
 
-               mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
+               if (err) {
+                       printk(KERN_WARNING "%s: switch to bus width %d "
+                              "failed\n", mmc_hostname(card->host),
+                              1 << bus_width);
+                       err = 0;
+               } else {
+                       mmc_set_bus_width(card->host, bus_width);
+               }
        }
 
        if (!oldcard)
@@ -496,8 +527,6 @@ static void mmc_detect(struct mmc_host *host)
        }
 }
 
-#ifdef CONFIG_MMC_UNSAFE_RESUME
-
 /*
  * Suspend callback from host.
  */
@@ -540,20 +569,96 @@ static void mmc_resume(struct mmc_host *host)
 
 }
 
-#else
+static void mmc_power_restore(struct mmc_host *host)
+{
+       host->card->state &= ~MMC_STATE_HIGHSPEED;
+       mmc_claim_host(host);
+       mmc_init_card(host, host->ocr, host->card);
+       mmc_release_host(host);
+}
 
-#define mmc_suspend NULL
-#define mmc_resume NULL
+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);
+       }
 
-#endif
+       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;
+}
+
+#ifdef CONFIG_MMC_UNSAFE_RESUME
+
+static const struct mmc_bus_ops mmc_ops = {
+       .awake = mmc_awake,
+       .sleep = mmc_sleep,
+       .remove = mmc_remove,
+       .detect = mmc_detect,
+       .suspend = mmc_suspend,
+       .resume = mmc_resume,
+       .power_restore = mmc_power_restore,
+};
+
+static void mmc_attach_bus_ops(struct mmc_host *host)
+{
+       mmc_attach_bus(host, &mmc_ops);
+}
+
+#else
 
 static const struct mmc_bus_ops mmc_ops = {
+       .awake = mmc_awake,
+       .sleep = mmc_sleep,
+       .remove = mmc_remove,
+       .detect = mmc_detect,
+       .suspend = NULL,
+       .resume = NULL,
+       .power_restore = mmc_power_restore,
+};
+
+static const struct mmc_bus_ops mmc_ops_unsafe = {
+       .awake = mmc_awake,
+       .sleep = mmc_sleep,
        .remove = mmc_remove,
        .detect = mmc_detect,
        .suspend = mmc_suspend,
        .resume = mmc_resume,
+       .power_restore = mmc_power_restore,
 };
 
+static void mmc_attach_bus_ops(struct mmc_host *host)
+{
+       const struct mmc_bus_ops *bus_ops;
+
+       if (host->caps & MMC_CAP_NONREMOVABLE)
+               bus_ops = &mmc_ops_unsafe;
+       else
+               bus_ops = &mmc_ops;
+       mmc_attach_bus(host, bus_ops);
+}
+
+#endif
+
 /*
  * Starting point for MMC card init.
  */
@@ -564,7 +669,7 @@ int mmc_attach_mmc(struct mmc_host *host, u32 ocr)
        BUG_ON(!host);
        WARN_ON(!host->claimed);
 
-       mmc_attach_bus(host, &mmc_ops);
+       mmc_attach_bus_ops(host);
 
        /*
         * We need to get OCR a different way for SPI.
@@ -624,4 +729,3 @@ err:
 
        return err;
 }
-