summaryrefslogtreecommitdiff
path: root/drivers/mmc
diff options
context:
space:
mode:
authorPedro Perez de Heredia <pedro.perez@digi.com>2010-02-23 10:50:29 +0100
committerPedro Perez de Heredia <pedro.perez@digi.com>2010-02-23 10:50:29 +0100
commitf64e954031af2ea2224213fd4c000ba93e158b2b (patch)
tree3786861624d9d3da87d2a74a6bab4e9ceaa16b81 /drivers/mmc
parent158aeade15595f75d6484ddb1346a8e7efd8050c (diff)
sdio: recognize io card without powercycle
PPH: temporal patch from Albert Herranz (no included in mainline) but necessary for the redpine wireless module. Original patch comments: SDIO Simplified Specification V2.00 states that it is strongly recommended that the host executes either a power reset or issues a CMD52 (I/O Reset) to re-initialize an I/O only card or the I/O portion of a combo card. Additionally, the CMD52 must be issued first because it cannot be issued after a CMD0. With this patch the Nintendo Wii SDIO-based WLAN card is detected after a system reset, without requiring a complete system powercycle. Signed-off-by: Pedro Perez de Heredia <pedro.perez@digi.com>
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/core/core.c2
-rw-r--r--drivers/mmc/core/sdio_ops.c119
-rw-r--r--drivers/mmc/core/sdio_ops.h1
3 files changed, 74 insertions, 48 deletions
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index d84c880fac84..50b208253440 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -890,6 +890,8 @@ void mmc_rescan(struct work_struct *work)
mmc_claim_host(host);
mmc_power_up(host);
+ sdio_go_idle(host);
+
mmc_go_idle(host);
mmc_send_if_cond(host, host->ocr_avail);
diff --git a/drivers/mmc/core/sdio_ops.c b/drivers/mmc/core/sdio_ops.c
index 4eb7825fd1a7..208beeb23ed6 100644
--- a/drivers/mmc/core/sdio_ops.c
+++ b/drivers/mmc/core/sdio_ops.c
@@ -67,54 +67,6 @@ int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
return err;
}
-int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn,
- unsigned addr, u8 in, u8* out)
-{
- struct mmc_command cmd;
- int err;
-
- BUG_ON(!card);
- BUG_ON(fn > 7);
-
- /* sanity check */
- if (addr & ~0x1FFFF)
- return -EINVAL;
-
- memset(&cmd, 0, sizeof(struct mmc_command));
-
- cmd.opcode = SD_IO_RW_DIRECT;
- cmd.arg = write ? 0x80000000 : 0x00000000;
- cmd.arg |= fn << 28;
- cmd.arg |= (write && out) ? 0x08000000 : 0x00000000;
- cmd.arg |= addr << 9;
- cmd.arg |= in;
- cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC;
-
- err = mmc_wait_for_cmd(card->host, &cmd, 0);
- if (err)
- return err;
-
- if (mmc_host_is_spi(card->host)) {
- /* host driver already reported errors */
- } else {
- if (cmd.resp[0] & R5_ERROR)
- return -EIO;
- if (cmd.resp[0] & R5_FUNCTION_NUMBER)
- return -EINVAL;
- if (cmd.resp[0] & R5_OUT_OF_RANGE)
- return -ERANGE;
- }
-
- if (out) {
- if (mmc_host_is_spi(card->host))
- *out = (cmd.resp[0] >> 8) & 0xFF;
- else
- *out = cmd.resp[0] & 0xFF;
- }
-
- return 0;
-}
-
int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz)
{
@@ -182,3 +134,74 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
return 0;
}
+static int mmc_io_rw_direct_host(struct mmc_host *host, int write, unsigned fn,
+ unsigned addr, u8 in, u8 *out)
+{
+ struct mmc_command cmd;
+ int err;
+
+ BUG_ON(!host);
+ BUG_ON(fn > 7);
+
+ /* sanity check */
+ if (addr & ~0x1FFFF)
+ return -EINVAL;
+
+ memset(&cmd, 0, sizeof(struct mmc_command));
+
+ cmd.opcode = SD_IO_RW_DIRECT;
+ cmd.arg = write ? 0x80000000 : 0x00000000;
+ cmd.arg |= fn << 28;
+ cmd.arg |= (write && out) ? 0x08000000 : 0x00000000;
+ cmd.arg |= addr << 9;
+ cmd.arg |= in;
+ cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC;
+
+ err = mmc_wait_for_cmd(host, &cmd, 0);
+ if (err)
+ return err;
+
+ if (mmc_host_is_spi(host)) {
+ /* host driver already reported errors */
+ } else {
+ if (cmd.resp[0] & R5_ERROR)
+ return -EIO;
+ if (cmd.resp[0] & R5_FUNCTION_NUMBER)
+ return -EINVAL;
+ if (cmd.resp[0] & R5_OUT_OF_RANGE)
+ return -ERANGE;
+ }
+
+ if (out) {
+ if (mmc_host_is_spi(host))
+ *out = (cmd.resp[0] >> 8) & 0xFF;
+ else
+ *out = cmd.resp[0] & 0xFF;
+ }
+
+ return 0;
+}
+
+int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn,
+ unsigned addr, u8 in, u8 *out)
+{
+ BUG_ON(!card);
+ return mmc_io_rw_direct_host(card->host, write, fn, addr, in, out);
+}
+
+int sdio_go_idle(struct mmc_host *host)
+{
+ int ret;
+ u8 abort;
+
+ /* SDIO Simplified Specification V2.0, 4.4 Reset for SDIO */
+
+ ret = mmc_io_rw_direct_host(host, 0, 0, SDIO_CCCR_ABORT, 0, &abort);
+ if (ret)
+ abort = 0x08;
+ else
+ abort |= 0x08;
+
+ ret = mmc_io_rw_direct_host(host, 1, 0, SDIO_CCCR_ABORT, abort, NULL);
+ return ret;
+}
diff --git a/drivers/mmc/core/sdio_ops.h b/drivers/mmc/core/sdio_ops.h
index e2e74b0d17d8..9b546c71eb5e 100644
--- a/drivers/mmc/core/sdio_ops.h
+++ b/drivers/mmc/core/sdio_ops.h
@@ -17,6 +17,7 @@ int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn,
unsigned addr, u8 in, u8* out);
int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz);
+int sdio_go_idle(struct mmc_host *host);
#endif