diff options
author | David Brownell <david-b@pacbell.net> | 2007-08-08 12:11:32 -0400 |
---|---|---|
committer | Pierre Ossman <drzeus@drzeus.cx> | 2007-09-23 15:51:30 -0400 |
commit | af51715079e7fb6b290e1881d63d815dc4de5011 (patch) | |
tree | 324e81b2346955f130dda8515f2ad4f4ce97c864 /drivers/mmc/core/mmc_ops.c | |
parent | 7213d175e3b6f6db60f843b72e88857a350e146a (diff) |
MMC core learns about SPI
Teach the MMC/SD/SDIO core about using SPI mode.
- Use mmc_host_is_spi() so enumeration works through SPI signaling
and protocols, not just the native versions.
- Provide the SPI response type flags with each request issued,
including requests from the new lock/unlock code.
- Understand that cmd->resp[0] and mmc_get_status() results for SPI
return different values than for "native" MMC/SD protocol; this
affects resetting, checking card lock status, and some others.
- Understand that some commands act a bit differently ... notably:
* OP_COND command doesn't return the OCR
* APP_CMD status doesn't have an R1_APP_CMD analogue
Those changes required some new and updated primitives:
- Provide utilities to access two SPI-only requests, and one
request that wasn't previously needed:
* mmc_spi_read_ocr() ... SPI only
* mmc_spi_set_crc() ... SPI only (override by module parm)
* mmc_send_cid() ... for use without broadcast mode
- Updated internal routines:
* Previous mmc_send_csd() modified into mmc_send_cxd_native();
it uses native "R2" responses, which include 16 bytes of data.
* Previous mmc_send_ext_csd() becomes new mmc_send_cxd_data()
helper for command-and-data access
* Bugfix to that mmc_send_cxd_data() code: dma-to-stack is
unsafe/nonportable, so kmalloc a bounce buffer instead.
- Modified mmc_send_ext_csd() now uses mmc_send_cxd_data() helper
- Modified mmc_send_csd(), and new mmc_spi_send_cid(), routines use
those helper routines based on whether they're native or SPI
The newest categories of cards supported by the MMC stack aren't expected
to work yet with SPI: MMC or SD cards with over 4GB data, and SDIO.
All those cards support SPI mode, so eventually they should work too.
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
Diffstat (limited to 'drivers/mmc/core/mmc_ops.c')
-rw-r--r-- | drivers/mmc/core/mmc_ops.c | 166 |
1 files changed, 135 insertions, 31 deletions
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index 39567f91a4b8..bf4bc6adcfef 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c | |||
@@ -63,23 +63,36 @@ int mmc_go_idle(struct mmc_host *host) | |||
63 | int err; | 63 | int err; |
64 | struct mmc_command cmd; | 64 | struct mmc_command cmd; |
65 | 65 | ||
66 | mmc_set_chip_select(host, MMC_CS_HIGH); | 66 | /* |
67 | 67 | * Non-SPI hosts need to prevent chipselect going active during | |
68 | mmc_delay(1); | 68 | * GO_IDLE; that would put chips into SPI mode. Remind them of |
69 | * that in case of hardware that won't pull up DAT3/nCS otherwise. | ||
70 | * | ||
71 | * SPI hosts ignore ios.chip_select; it's managed according to | ||
72 | * rules that must accomodate non-MMC slaves which this layer | ||
73 | * won't even know about. | ||
74 | */ | ||
75 | if (!mmc_host_is_spi(host)) { | ||
76 | mmc_set_chip_select(host, MMC_CS_HIGH); | ||
77 | mmc_delay(1); | ||
78 | } | ||
69 | 79 | ||
70 | memset(&cmd, 0, sizeof(struct mmc_command)); | 80 | memset(&cmd, 0, sizeof(struct mmc_command)); |
71 | 81 | ||
72 | cmd.opcode = MMC_GO_IDLE_STATE; | 82 | cmd.opcode = MMC_GO_IDLE_STATE; |
73 | cmd.arg = 0; | 83 | cmd.arg = 0; |
74 | cmd.flags = MMC_RSP_NONE | MMC_CMD_BC; | 84 | cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_NONE | MMC_CMD_BC; |
75 | 85 | ||
76 | err = mmc_wait_for_cmd(host, &cmd, 0); | 86 | err = mmc_wait_for_cmd(host, &cmd, 0); |
77 | 87 | ||
78 | mmc_delay(1); | 88 | mmc_delay(1); |
79 | 89 | ||
80 | mmc_set_chip_select(host, MMC_CS_DONTCARE); | 90 | if (!mmc_host_is_spi(host)) { |
91 | mmc_set_chip_select(host, MMC_CS_DONTCARE); | ||
92 | mmc_delay(1); | ||
93 | } | ||
81 | 94 | ||
82 | mmc_delay(1); | 95 | host->use_spi_crc = 0; |
83 | 96 | ||
84 | return err; | 97 | return err; |
85 | } | 98 | } |
@@ -94,23 +107,33 @@ int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) | |||
94 | memset(&cmd, 0, sizeof(struct mmc_command)); | 107 | memset(&cmd, 0, sizeof(struct mmc_command)); |
95 | 108 | ||
96 | cmd.opcode = MMC_SEND_OP_COND; | 109 | cmd.opcode = MMC_SEND_OP_COND; |
97 | cmd.arg = ocr; | 110 | cmd.arg = mmc_host_is_spi(host) ? 0 : ocr; |
98 | cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR; | 111 | cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR; |
99 | 112 | ||
100 | for (i = 100; i; i--) { | 113 | for (i = 100; i; i--) { |
101 | err = mmc_wait_for_cmd(host, &cmd, 0); | 114 | err = mmc_wait_for_cmd(host, &cmd, 0); |
102 | if (err) | 115 | if (err) |
103 | break; | 116 | break; |
104 | 117 | ||
105 | if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0) | 118 | /* if we're just probing, do a single pass */ |
119 | if (ocr == 0) | ||
106 | break; | 120 | break; |
107 | 121 | ||
122 | /* otherwise wait until reset completes */ | ||
123 | if (mmc_host_is_spi(host)) { | ||
124 | if (!(cmd.resp[0] & R1_SPI_IDLE)) | ||
125 | break; | ||
126 | } else { | ||
127 | if (cmd.resp[0] & MMC_CARD_BUSY) | ||
128 | break; | ||
129 | } | ||
130 | |||
108 | err = -ETIMEDOUT; | 131 | err = -ETIMEDOUT; |
109 | 132 | ||
110 | mmc_delay(10); | 133 | mmc_delay(10); |
111 | } | 134 | } |
112 | 135 | ||
113 | if (rocr) | 136 | if (rocr && !mmc_host_is_spi(host)) |
114 | *rocr = cmd.resp[0]; | 137 | *rocr = cmd.resp[0]; |
115 | 138 | ||
116 | return err; | 139 | return err; |
@@ -160,40 +183,46 @@ int mmc_set_relative_addr(struct mmc_card *card) | |||
160 | return 0; | 183 | return 0; |
161 | } | 184 | } |
162 | 185 | ||
163 | int mmc_send_csd(struct mmc_card *card, u32 *csd) | 186 | static int |
187 | mmc_send_cxd_native(struct mmc_host *host, u32 arg, u32 *cxd, int opcode) | ||
164 | { | 188 | { |
165 | int err; | 189 | int err; |
166 | struct mmc_command cmd; | 190 | struct mmc_command cmd; |
167 | 191 | ||
168 | BUG_ON(!card); | 192 | BUG_ON(!host); |
169 | BUG_ON(!card->host); | 193 | BUG_ON(!cxd); |
170 | BUG_ON(!csd); | ||
171 | 194 | ||
172 | memset(&cmd, 0, sizeof(struct mmc_command)); | 195 | memset(&cmd, 0, sizeof(struct mmc_command)); |
173 | 196 | ||
174 | cmd.opcode = MMC_SEND_CSD; | 197 | cmd.opcode = opcode; |
175 | cmd.arg = card->rca << 16; | 198 | cmd.arg = arg; |
176 | cmd.flags = MMC_RSP_R2 | MMC_CMD_AC; | 199 | cmd.flags = MMC_RSP_R2 | MMC_CMD_AC; |
177 | 200 | ||
178 | err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); | 201 | err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES); |
179 | if (err) | 202 | if (err) |
180 | return err; | 203 | return err; |
181 | 204 | ||
182 | memcpy(csd, cmd.resp, sizeof(u32) * 4); | 205 | memcpy(cxd, cmd.resp, sizeof(u32) * 4); |
183 | 206 | ||
184 | return 0; | 207 | return 0; |
185 | } | 208 | } |
186 | 209 | ||
187 | int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd) | 210 | static int |
211 | mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host, | ||
212 | u32 opcode, void *buf, unsigned len) | ||
188 | { | 213 | { |
189 | struct mmc_request mrq; | 214 | struct mmc_request mrq; |
190 | struct mmc_command cmd; | 215 | struct mmc_command cmd; |
191 | struct mmc_data data; | 216 | struct mmc_data data; |
192 | struct scatterlist sg; | 217 | struct scatterlist sg; |
218 | void *data_buf; | ||
193 | 219 | ||
194 | BUG_ON(!card); | 220 | /* dma onto stack is unsafe/nonportable, but callers to this |
195 | BUG_ON(!card->host); | 221 | * routine normally provide temporary on-stack buffers ... |
196 | BUG_ON(!ext_csd); | 222 | */ |
223 | data_buf = kmalloc(len, GFP_KERNEL); | ||
224 | if (data_buf == NULL) | ||
225 | return -ENOMEM; | ||
197 | 226 | ||
198 | memset(&mrq, 0, sizeof(struct mmc_request)); | 227 | memset(&mrq, 0, sizeof(struct mmc_request)); |
199 | memset(&cmd, 0, sizeof(struct mmc_command)); | 228 | memset(&cmd, 0, sizeof(struct mmc_command)); |
@@ -202,21 +231,31 @@ int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd) | |||
202 | mrq.cmd = &cmd; | 231 | mrq.cmd = &cmd; |
203 | mrq.data = &data; | 232 | mrq.data = &data; |
204 | 233 | ||
205 | cmd.opcode = MMC_SEND_EXT_CSD; | 234 | cmd.opcode = opcode; |
206 | cmd.arg = 0; | 235 | cmd.arg = 0; |
207 | cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; | ||
208 | 236 | ||
209 | data.blksz = 512; | 237 | /* NOTE HACK: the MMC_RSP_SPI_R1 is always correct here, but we |
238 | * rely on callers to never use this with "native" calls for reading | ||
239 | * CSD or CID. Native versions of those commands use the R2 type, | ||
240 | * not R1 plus a data block. | ||
241 | */ | ||
242 | cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; | ||
243 | |||
244 | data.blksz = len; | ||
210 | data.blocks = 1; | 245 | data.blocks = 1; |
211 | data.flags = MMC_DATA_READ; | 246 | data.flags = MMC_DATA_READ; |
212 | data.sg = &sg; | 247 | data.sg = &sg; |
213 | data.sg_len = 1; | 248 | data.sg_len = 1; |
214 | 249 | ||
215 | sg_init_one(&sg, ext_csd, 512); | 250 | sg_init_one(&sg, data_buf, len); |
216 | 251 | ||
217 | mmc_set_data_timeout(&data, card); | 252 | if (card) |
253 | mmc_set_data_timeout(&data, card); | ||
218 | 254 | ||
219 | mmc_wait_for_req(card->host, &mrq); | 255 | mmc_wait_for_req(host, &mrq); |
256 | |||
257 | memcpy(buf, data_buf, len); | ||
258 | kfree(data_buf); | ||
220 | 259 | ||
221 | if (cmd.error) | 260 | if (cmd.error) |
222 | return cmd.error; | 261 | return cmd.error; |
@@ -226,6 +265,67 @@ int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd) | |||
226 | return 0; | 265 | return 0; |
227 | } | 266 | } |
228 | 267 | ||
268 | int mmc_send_csd(struct mmc_card *card, u32 *csd) | ||
269 | { | ||
270 | if (!mmc_host_is_spi(card->host)) | ||
271 | return mmc_send_cxd_native(card->host, card->rca << 16, | ||
272 | csd, MMC_SEND_CSD); | ||
273 | |||
274 | return mmc_send_cxd_data(card, card->host, MMC_SEND_CSD, csd, 16); | ||
275 | } | ||
276 | |||
277 | int mmc_send_cid(struct mmc_host *host, u32 *cid) | ||
278 | { | ||
279 | if (!mmc_host_is_spi(host)) { | ||
280 | if (!host->card) | ||
281 | return -EINVAL; | ||
282 | return mmc_send_cxd_native(host, host->card->rca << 16, | ||
283 | cid, MMC_SEND_CID); | ||
284 | } | ||
285 | |||
286 | return mmc_send_cxd_data(NULL, host, MMC_SEND_CID, cid, 16); | ||
287 | } | ||
288 | |||
289 | int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd) | ||
290 | { | ||
291 | return mmc_send_cxd_data(card, card->host, MMC_SEND_EXT_CSD, | ||
292 | ext_csd, 512); | ||
293 | } | ||
294 | |||
295 | int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp) | ||
296 | { | ||
297 | struct mmc_command cmd; | ||
298 | int err; | ||
299 | |||
300 | memset(&cmd, 0, sizeof(struct mmc_command)); | ||
301 | |||
302 | cmd.opcode = MMC_SPI_READ_OCR; | ||
303 | cmd.arg = highcap ? (1 << 30) : 0; | ||
304 | cmd.flags = MMC_RSP_SPI_R3; | ||
305 | |||
306 | err = mmc_wait_for_cmd(host, &cmd, 0); | ||
307 | |||
308 | *ocrp = cmd.resp[1]; | ||
309 | return err; | ||
310 | } | ||
311 | |||
312 | int mmc_spi_set_crc(struct mmc_host *host, int use_crc) | ||
313 | { | ||
314 | struct mmc_command cmd; | ||
315 | int err; | ||
316 | |||
317 | memset(&cmd, 0, sizeof(struct mmc_command)); | ||
318 | |||
319 | cmd.opcode = MMC_SPI_CRC_ON_OFF; | ||
320 | cmd.flags = MMC_RSP_SPI_R1; | ||
321 | cmd.arg = use_crc; | ||
322 | |||
323 | err = mmc_wait_for_cmd(host, &cmd, 0); | ||
324 | if (!err) | ||
325 | host->use_spi_crc = use_crc; | ||
326 | return err; | ||
327 | } | ||
328 | |||
229 | int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value) | 329 | int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value) |
230 | { | 330 | { |
231 | int err; | 331 | int err; |
@@ -241,7 +341,7 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value) | |||
241 | (index << 16) | | 341 | (index << 16) | |
242 | (value << 8) | | 342 | (value << 8) | |
243 | set; | 343 | set; |
244 | cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; | 344 | cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC; |
245 | 345 | ||
246 | err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); | 346 | err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); |
247 | if (err) | 347 | if (err) |
@@ -261,13 +361,17 @@ int mmc_send_status(struct mmc_card *card, u32 *status) | |||
261 | memset(&cmd, 0, sizeof(struct mmc_command)); | 361 | memset(&cmd, 0, sizeof(struct mmc_command)); |
262 | 362 | ||
263 | cmd.opcode = MMC_SEND_STATUS; | 363 | cmd.opcode = MMC_SEND_STATUS; |
264 | cmd.arg = card->rca << 16; | 364 | if (!mmc_host_is_spi(card->host)) |
265 | cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; | 365 | cmd.arg = card->rca << 16; |
366 | cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC; | ||
266 | 367 | ||
267 | err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); | 368 | err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); |
268 | if (err) | 369 | if (err) |
269 | return err; | 370 | return err; |
270 | 371 | ||
372 | /* NOTE: callers are required to understand the difference | ||
373 | * between "native" and SPI format status words! | ||
374 | */ | ||
271 | if (status) | 375 | if (status) |
272 | *status = cmd.resp[0]; | 376 | *status = cmd.resp[0]; |
273 | 377 | ||