Merge rsync://bughost.org/repos/ieee80211-delta/
[powerpc.git] / drivers / mmc / mmc.c
index 294961a..da52839 100644 (file)
@@ -2,6 +2,8 @@
  *  linux/drivers/mmc/mmc.c
  *
  *  Copyright (C) 2003-2004 Russell King, All Rights Reserved.
+ *  SD support Copyright (C) 2004 Ian Molton, All Rights Reserved.
+ *  SD support Copyright (C) 2005 Pierre Ossman, All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -16,6 +18,8 @@
 #include <linux/delay.h>
 #include <linux/pagemap.h>
 #include <linux/err.h>
+#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
 
 #include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
@@ -246,6 +250,8 @@ int mmc_wait_for_app_cmd(struct mmc_host *host, unsigned int rca,
 
 EXPORT_SYMBOL(mmc_wait_for_app_cmd);
 
+static int mmc_select_card(struct mmc_host *host, struct mmc_card *card);
+
 /**
  *     __mmc_claim_host - exclusively claim a host
  *     @host: mmc host to claim
@@ -278,16 +284,10 @@ int __mmc_claim_host(struct mmc_host *host, struct mmc_card *card)
        spin_unlock_irqrestore(&host->lock, flags);
        remove_wait_queue(&host->wq, &wait);
 
-       if (card != (void *)-1 && host->card_selected != card) {
-               struct mmc_command cmd;
-
-               host->card_selected = card;
-
-               cmd.opcode = MMC_SELECT_CARD;
-               cmd.arg = card->rca << 16;
-               cmd.flags = MMC_RSP_R1;
-
-               err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
+       if (card != (void *)-1) {
+               err = mmc_select_card(host, card);
+               if (err != MMC_ERR_NONE)
+                       return err;
        }
 
        return err;
@@ -317,6 +317,63 @@ void mmc_release_host(struct mmc_host *host)
 
 EXPORT_SYMBOL(mmc_release_host);
 
+static int mmc_select_card(struct mmc_host *host, struct mmc_card *card)
+{
+       int err;
+       struct mmc_command cmd;
+
+       BUG_ON(host->card_busy == NULL);
+
+       if (host->card_selected == card)
+               return MMC_ERR_NONE;
+
+       host->card_selected = card;
+
+       cmd.opcode = MMC_SELECT_CARD;
+       cmd.arg = card->rca << 16;
+       cmd.flags = MMC_RSP_R1;
+
+       err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
+       if (err != MMC_ERR_NONE)
+               return err;
+
+       /*
+        * Default bus width is 1 bit.
+        */
+       host->ios.bus_width = MMC_BUS_WIDTH_1;
+
+       /*
+        * We can only change the bus width of the selected
+        * card so therefore we have to put the handling
+        * here.
+        */
+       if (host->caps & MMC_CAP_4_BIT_DATA) {
+               /*
+                * The card is in 1 bit mode by default so
+                * we only need to change if it supports the
+                * wider version.
+                */
+               if (mmc_card_sd(card) &&
+                       (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
+                       struct mmc_command cmd;
+                       cmd.opcode = SD_APP_SET_BUS_WIDTH;
+                       cmd.arg = SD_BUS_WIDTH_4;
+                       cmd.flags = MMC_RSP_R1;
+
+                       err = mmc_wait_for_app_cmd(host, card->rca, &cmd,
+                               CMD_RETRIES);
+                       if (err != MMC_ERR_NONE)
+                               return err;
+
+                       host->ios.bus_width = MMC_BUS_WIDTH_4;
+               }
+       }
+
+       host->ops->set_ios(host, &host->ios);
+
+       return MMC_ERR_NONE;
+}
+
 /*
  * Ensure that no card is selected.
  */
@@ -413,8 +470,7 @@ static void mmc_decode_cid(struct mmc_card *card)
                card->cid.month                 = UNSTUFF_BITS(resp, 8, 4);
 
                card->cid.year += 2000; /* SD cards year offset */
-       }
-       else {
+       } else {
                /*
                 * The selection of the format here is based upon published
                 * specs from sandisk and from what people have reported.
@@ -494,8 +550,7 @@ static void mmc_decode_csd(struct mmc_card *card)
                csd->capacity     = (1 + m) << (e + 2);
 
                csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
-       }
-       else {
+       } else {
                /*
                 * We only understand CSD structure v1.1 and v1.2.
                 * v1.2 has extra information in bits 15, 11 and 10.
@@ -527,6 +582,32 @@ static void mmc_decode_csd(struct mmc_card *card)
        }
 }
 
+/*
+ * Given a 64-bit response, decode to our card SCR structure.
+ */
+static void mmc_decode_scr(struct mmc_card *card)
+{
+       struct sd_scr *scr = &card->scr;
+       unsigned int scr_struct;
+       u32 resp[4];
+
+       BUG_ON(!mmc_card_sd(card));
+
+       resp[3] = card->raw_scr[1];
+       resp[2] = card->raw_scr[0];
+
+       scr_struct = UNSTUFF_BITS(resp, 60, 4);
+       if (scr_struct != 0) {
+               printk("%s: unrecognised SCR structure version %d\n",
+                       mmc_hostname(card->host), scr_struct);
+               mmc_card_set_bad(card);
+               return;
+       }
+
+       scr->sda_vsn = UNSTUFF_BITS(resp, 56, 4);
+       scr->bus_widths = UNSTUFF_BITS(resp, 48, 4);
+}
+
 /*
  * Locate a MMC card on this MMC host given a raw CID.
  */
@@ -608,6 +689,7 @@ static void mmc_power_up(struct mmc_host *host)
        host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
        host->ios.chip_select = MMC_CS_DONTCARE;
        host->ios.power_mode = MMC_POWER_UP;
+       host->ios.bus_width = MMC_BUS_WIDTH_1;
        host->ops->set_ios(host, &host->ios);
 
        mmc_delay(1);
@@ -626,6 +708,7 @@ static void mmc_power_off(struct mmc_host *host)
        host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
        host->ios.chip_select = MMC_CS_DONTCARE;
        host->ios.power_mode = MMC_POWER_OFF;
+       host->ios.bus_width = MMC_BUS_WIDTH_1;
        host->ops->set_ios(host, &host->ios);
 }
 
@@ -738,10 +821,20 @@ static void mmc_discover_cards(struct mmc_host *host)
                        err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
                        if (err != MMC_ERR_NONE)
                                mmc_card_set_dead(card);
-                       else
+                       else {
                                card->rca = cmd.resp[0] >> 16;
-               }
-               else {
+
+                               if (!host->ops->get_ro) {
+                                       printk(KERN_WARNING "%s: host does not "
+                                               "support reading read-only "
+                                               "switch. assuming write-enable.\n",
+                                               mmc_hostname(host));
+                               } else {
+                                       if (host->ops->get_ro(host))
+                                               mmc_card_set_readonly(card);
+                               }
+                       }
+               } else {
                        cmd.opcode = MMC_SET_RELATIVE_ADDR;
                        cmd.arg = card->rca << 16;
                        cmd.flags = MMC_RSP_R1;
@@ -781,6 +874,79 @@ static void mmc_read_csds(struct mmc_host *host)
        }
 }
 
+static void mmc_read_scrs(struct mmc_host *host)
+{
+       int err;
+       struct mmc_card *card;
+
+       struct mmc_request mrq;
+       struct mmc_command cmd;
+       struct mmc_data data;
+
+       struct scatterlist sg;
+
+       list_for_each_entry(card, &host->cards, node) {
+               if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT))
+                       continue;
+               if (!mmc_card_sd(card))
+                       continue;
+
+               err = mmc_select_card(host, card);
+               if (err != MMC_ERR_NONE) {
+                       mmc_card_set_dead(card);
+                       continue;
+               }
+
+               memset(&cmd, 0, sizeof(struct mmc_command));
+
+               cmd.opcode = MMC_APP_CMD;
+               cmd.arg = card->rca << 16;
+               cmd.flags = MMC_RSP_R1;
+
+               err = mmc_wait_for_cmd(host, &cmd, 0);
+               if ((err != MMC_ERR_NONE) || !(cmd.resp[0] & R1_APP_CMD)) {
+                       mmc_card_set_dead(card);
+                       continue;
+               }
+
+               memset(&cmd, 0, sizeof(struct mmc_command));
+
+               cmd.opcode = SD_APP_SEND_SCR;
+               cmd.arg = 0;
+               cmd.flags = MMC_RSP_R1;
+
+               memset(&data, 0, sizeof(struct mmc_data));
+
+               data.timeout_ns = card->csd.tacc_ns * 10;
+               data.timeout_clks = card->csd.tacc_clks * 10;
+               data.blksz_bits = 3;
+               data.blocks = 1;
+               data.flags = MMC_DATA_READ;
+               data.sg = &sg;
+               data.sg_len = 1;
+
+               memset(&mrq, 0, sizeof(struct mmc_request));
+
+               mrq.cmd = &cmd;
+               mrq.data = &data;
+
+               sg_init_one(&sg, (u8*)card->raw_scr, 8);
+
+               err = mmc_wait_for_req(host, &mrq);
+               if (err != MMC_ERR_NONE) {
+                       mmc_card_set_dead(card);
+                       continue;
+               }
+
+               card->raw_scr[0] = ntohl(card->raw_scr[0]);
+               card->raw_scr[1] = ntohl(card->raw_scr[1]);
+
+               mmc_decode_scr(card);
+       }
+
+       mmc_deselect_cards(host);
+}
+
 static unsigned int mmc_calculate_clock(struct mmc_host *host)
 {
        struct mmc_card *card;
@@ -833,24 +999,23 @@ static void mmc_setup(struct mmc_host *host)
                int err;
                u32 ocr;
 
-               host->mode = MMC_MODE_MMC;
+               host->mode = MMC_MODE_SD;
 
                mmc_power_up(host);
                mmc_idle_cards(host);
 
-               err = mmc_send_op_cond(host, 0, &ocr);
+               err = mmc_send_app_op_cond(host, 0, &ocr);
 
                /*
-                * If we fail to detect any cards then try
-                * searching for SD cards.
+                * If we fail to detect any SD cards then try
+                * searching for MMC cards.
                 */
-               if (err != MMC_ERR_NONE)
-               {
-                       err = mmc_send_app_op_cond(host, 0, &ocr);
+               if (err != MMC_ERR_NONE) {
+                       host->mode = MMC_MODE_MMC;
+
+                       err = mmc_send_op_cond(host, 0, &ocr);
                        if (err != MMC_ERR_NONE)
                                return;
-
-                       host->mode = MMC_MODE_SD;
                }
 
                host->ocr = mmc_select_voltage(host, ocr);
@@ -905,19 +1070,26 @@ static void mmc_setup(struct mmc_host *host)
        host->ops->set_ios(host, &host->ios);
 
        mmc_read_csds(host);
+
+       if (host->mode == MMC_MODE_SD)
+               mmc_read_scrs(host);
 }
 
 
 /**
  *     mmc_detect_change - process change of state on a MMC socket
  *     @host: host which changed state.
+ *     @delay: optional delay to wait before detection (jiffies)
  *
  *     All we know is that card(s) have been inserted or removed
  *     from the socket(s).  We don't know which socket or cards.
  */
-void mmc_detect_change(struct mmc_host *host)
+void mmc_detect_change(struct mmc_host *host, unsigned long delay)
 {
-       schedule_work(&host->detect);
+       if (delay)
+               schedule_delayed_work(&host->detect, delay);
+       else
+               schedule_work(&host->detect);
 }
 
 EXPORT_SYMBOL(mmc_detect_change);
@@ -1021,7 +1193,7 @@ int mmc_add_host(struct mmc_host *host)
        ret = mmc_add_host_sysfs(host);
        if (ret == 0) {
                mmc_power_off(host);
-               mmc_detect_change(host);
+               mmc_detect_change(host, 0);
        }
 
        return ret;
@@ -1091,7 +1263,7 @@ EXPORT_SYMBOL(mmc_suspend_host);
  */
 int mmc_resume_host(struct mmc_host *host)
 {
-       mmc_detect_change(host);
+       mmc_rescan(host);
 
        return 0;
 }