]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/mmc/core/mmc.c
Merge tag 'v2.6.38' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[mv-sheeva.git] / drivers / mmc / core / mmc.c
index 77f93c3b88086d5ee802da97ae03754d86c82e9a..16006ef153fe081c2f0f0a09cd4443ce7f3c49a1 100644 (file)
@@ -534,39 +534,57 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
         */
        if ((card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
            (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) {
-                       if (ddr)
-                               ext_csd_bit = EXT_CSD_DDR_BUS_WIDTH_8;
-                       else
-                               ext_csd_bit = EXT_CSD_BUS_WIDTH_8;
-                       bus_width = MMC_BUS_WIDTH_8;
-               } else {
-                       if (ddr)
-                               ext_csd_bit = EXT_CSD_DDR_BUS_WIDTH_4;
-                       else
-                               ext_csd_bit = EXT_CSD_BUS_WIDTH_4;
-                       bus_width = MMC_BUS_WIDTH_4;
+               static unsigned ext_csd_bits[][2] = {
+                       { EXT_CSD_BUS_WIDTH_8, EXT_CSD_DDR_BUS_WIDTH_8 },
+                       { EXT_CSD_BUS_WIDTH_4, EXT_CSD_DDR_BUS_WIDTH_4 },
+                       { EXT_CSD_BUS_WIDTH_1, EXT_CSD_BUS_WIDTH_1 },
+               };
+               static unsigned bus_widths[] = {
+                       MMC_BUS_WIDTH_8,
+                       MMC_BUS_WIDTH_4,
+                       MMC_BUS_WIDTH_1
+               };
+               unsigned idx, bus_width = 0;
+
+               if (host->caps & MMC_CAP_8_BIT_DATA)
+                       idx = 0;
+               else
+                       idx = 1;
+               for (; idx < ARRAY_SIZE(bus_widths); idx++) {
+                       bus_width = bus_widths[idx];
+                       if (bus_width == MMC_BUS_WIDTH_1)
+                               ddr = 0; /* no DDR for 1-bit width */
+                       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+                                        EXT_CSD_BUS_WIDTH,
+                                        ext_csd_bits[idx][0]);
+                       if (!err) {
+                               mmc_set_bus_width_ddr(card->host,
+                                                     bus_width, MMC_SDR_MODE);
+                               /*
+                                * If controller can't handle bus width test,
+                                * use the highest bus width to maintain
+                                * compatibility with previous MMC behavior.
+                                */
+                               if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
+                                       break;
+                               err = mmc_bus_test(card, bus_width);
+                               if (!err)
+                                       break;
+                       }
                }
 
-               err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-                                EXT_CSD_BUS_WIDTH, ext_csd_bit);
-
-               if (err && err != -EBADMSG)
-                       goto free_card;
-
+               if (!err && ddr) {
+                       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+                                       EXT_CSD_BUS_WIDTH,
+                                       ext_csd_bits[idx][1]);
+               }
                if (err) {
                        printk(KERN_WARNING "%s: switch to bus width %d ddr %d "
-                              "failed\n", mmc_hostname(card->host),
-                              1 << bus_width, ddr);
-                       err = 0;
-               } else {
-                       if (ddr)
-                               mmc_card_set_ddr_mode(card);
-                       else
-                               ddr = MMC_SDR_MODE;
-
+                               "failed\n", mmc_hostname(card->host),
+                               1 << bus_width, ddr);
+                       goto free_card;
+               } else if (ddr) {
+                       mmc_card_set_ddr_mode(card);
                        mmc_set_bus_width_ddr(card->host, bus_width, ddr);
                }
        }
@@ -737,14 +755,21 @@ static void mmc_attach_bus_ops(struct mmc_host *host)
 /*
  * Starting point for MMC card init.
  */
-int mmc_attach_mmc(struct mmc_host *host, u32 ocr)
+int mmc_attach_mmc(struct mmc_host *host)
 {
        int err;
+       u32 ocr;
 
        BUG_ON(!host);
        WARN_ON(!host->claimed);
 
+       err = mmc_send_op_cond(host, 0, &ocr);
+       if (err)
+               return err;
+
        mmc_attach_bus_ops(host);
+       if (host->ocr_avail_mmc)
+               host->ocr_avail = host->ocr_avail_mmc;
 
        /*
         * We need to get OCR a different way for SPI.
@@ -784,20 +809,20 @@ int mmc_attach_mmc(struct mmc_host *host, u32 ocr)
                goto err;
 
        mmc_release_host(host);
-
        err = mmc_add_card(host->card);
+       mmc_claim_host(host);
        if (err)
                goto remove_card;
 
        return 0;
 
 remove_card:
+       mmc_release_host(host);
        mmc_remove_card(host->card);
-       host->card = NULL;
        mmc_claim_host(host);
+       host->card = NULL;
 err:
        mmc_detach_bus(host);
-       mmc_release_host(host);
 
        printk(KERN_ERR "%s: error %d whilst initialising MMC card\n",
                mmc_hostname(host), err);