diff options
author | Albert Herranz <albert_herranz@yahoo.es> | 2010-03-10 18:20:37 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-03-12 18:52:28 -0500 |
commit | 516a82422209e078345d0ca54b16793d7bfd4782 (patch) | |
tree | c0f44619451e3ae5d40f6cacd953a5ad209412e3 /drivers | |
parent | d0ab4a4d5094e5d17b103dc5073529a04f00a469 (diff) |
sdio: recognize io card without powercycle
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: Albert Herranz <albert_herranz@yahoo.es>
Cc: <linux-mmc@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/mmc/core/core.c | 1 | ||||
-rw-r--r-- | drivers/mmc/core/sdio_ops.c | 36 | ||||
-rw-r--r-- | drivers/mmc/core/sdio_ops.h | 1 |
3 files changed, 32 insertions, 6 deletions
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index f4b97d3c3d0f..3168ebd616b2 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c | |||
@@ -1089,6 +1089,7 @@ void mmc_rescan(struct work_struct *work) | |||
1089 | mmc_claim_host(host); | 1089 | mmc_claim_host(host); |
1090 | 1090 | ||
1091 | mmc_power_up(host); | 1091 | mmc_power_up(host); |
1092 | sdio_reset(host); | ||
1092 | mmc_go_idle(host); | 1093 | mmc_go_idle(host); |
1093 | 1094 | ||
1094 | mmc_send_if_cond(host, host->ocr_avail); | 1095 | 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..dea36d9c22e6 100644 --- a/drivers/mmc/core/sdio_ops.c +++ b/drivers/mmc/core/sdio_ops.c | |||
@@ -67,13 +67,13 @@ int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) | |||
67 | return err; | 67 | return err; |
68 | } | 68 | } |
69 | 69 | ||
70 | int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, | 70 | static int mmc_io_rw_direct_host(struct mmc_host *host, int write, unsigned fn, |
71 | unsigned addr, u8 in, u8* out) | 71 | unsigned addr, u8 in, u8 *out) |
72 | { | 72 | { |
73 | struct mmc_command cmd; | 73 | struct mmc_command cmd; |
74 | int err; | 74 | int err; |
75 | 75 | ||
76 | BUG_ON(!card); | 76 | BUG_ON(!host); |
77 | BUG_ON(fn > 7); | 77 | BUG_ON(fn > 7); |
78 | 78 | ||
79 | /* sanity check */ | 79 | /* sanity check */ |
@@ -90,11 +90,11 @@ int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, | |||
90 | cmd.arg |= in; | 90 | cmd.arg |= in; |
91 | cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC; | 91 | cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC; |
92 | 92 | ||
93 | err = mmc_wait_for_cmd(card->host, &cmd, 0); | 93 | err = mmc_wait_for_cmd(host, &cmd, 0); |
94 | if (err) | 94 | if (err) |
95 | return err; | 95 | return err; |
96 | 96 | ||
97 | if (mmc_host_is_spi(card->host)) { | 97 | if (mmc_host_is_spi(host)) { |
98 | /* host driver already reported errors */ | 98 | /* host driver already reported errors */ |
99 | } else { | 99 | } else { |
100 | if (cmd.resp[0] & R5_ERROR) | 100 | if (cmd.resp[0] & R5_ERROR) |
@@ -106,7 +106,7 @@ int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, | |||
106 | } | 106 | } |
107 | 107 | ||
108 | if (out) { | 108 | if (out) { |
109 | if (mmc_host_is_spi(card->host)) | 109 | if (mmc_host_is_spi(host)) |
110 | *out = (cmd.resp[0] >> 8) & 0xFF; | 110 | *out = (cmd.resp[0] >> 8) & 0xFF; |
111 | else | 111 | else |
112 | *out = cmd.resp[0] & 0xFF; | 112 | *out = cmd.resp[0] & 0xFF; |
@@ -115,6 +115,13 @@ int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, | |||
115 | return 0; | 115 | return 0; |
116 | } | 116 | } |
117 | 117 | ||
118 | int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, | ||
119 | unsigned addr, u8 in, u8 *out) | ||
120 | { | ||
121 | BUG_ON(!card); | ||
122 | return mmc_io_rw_direct_host(card->host, write, fn, addr, in, out); | ||
123 | } | ||
124 | |||
118 | int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, | 125 | int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, |
119 | unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz) | 126 | unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz) |
120 | { | 127 | { |
@@ -182,3 +189,20 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, | |||
182 | return 0; | 189 | return 0; |
183 | } | 190 | } |
184 | 191 | ||
192 | int sdio_reset(struct mmc_host *host) | ||
193 | { | ||
194 | int ret; | ||
195 | u8 abort; | ||
196 | |||
197 | /* SDIO Simplified Specification V2.0, 4.4 Reset for SDIO */ | ||
198 | |||
199 | ret = mmc_io_rw_direct_host(host, 0, 0, SDIO_CCCR_ABORT, 0, &abort); | ||
200 | if (ret) | ||
201 | abort = 0x08; | ||
202 | else | ||
203 | abort |= 0x08; | ||
204 | |||
205 | ret = mmc_io_rw_direct_host(host, 1, 0, SDIO_CCCR_ABORT, abort, NULL); | ||
206 | return ret; | ||
207 | } | ||
208 | |||
diff --git a/drivers/mmc/core/sdio_ops.h b/drivers/mmc/core/sdio_ops.h index e2e74b0d17d8..12a4d3ab174c 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, | |||
17 | unsigned addr, u8 in, u8* out); | 17 | unsigned addr, u8 in, u8* out); |
18 | int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, | 18 | int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, |
19 | unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz); | 19 | unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz); |
20 | int sdio_reset(struct mmc_host *host); | ||
20 | 21 | ||
21 | #endif | 22 | #endif |
22 | 23 | ||