]>
Commit | Line | Data |
---|---|---|
da7fbe58 | 1 | /* |
70f10482 | 2 | * linux/drivers/mmc/core/mmc_ops.h |
da7fbe58 PO |
3 | * |
4 | * Copyright 2006-2007 Pierre Ossman | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License as published by | |
8 | * the Free Software Foundation; either version 2 of the License, or (at | |
9 | * your option) any later version. | |
10 | */ | |
11 | ||
12 | #include <linux/types.h> | |
13 | #include <asm/scatterlist.h> | |
14 | #include <linux/scatterlist.h> | |
15 | ||
16 | #include <linux/mmc/host.h> | |
17 | #include <linux/mmc/card.h> | |
18 | #include <linux/mmc/mmc.h> | |
19 | ||
20 | #include "core.h" | |
21 | #include "mmc_ops.h" | |
22 | ||
23 | static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card) | |
24 | { | |
25 | int err; | |
26 | struct mmc_command cmd; | |
27 | ||
28 | BUG_ON(!host); | |
29 | ||
30 | memset(&cmd, 0, sizeof(struct mmc_command)); | |
31 | ||
32 | cmd.opcode = MMC_SELECT_CARD; | |
33 | ||
34 | if (card) { | |
35 | cmd.arg = card->rca << 16; | |
36 | cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; | |
37 | } else { | |
38 | cmd.arg = 0; | |
39 | cmd.flags = MMC_RSP_NONE | MMC_CMD_AC; | |
40 | } | |
41 | ||
42 | err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES); | |
17b0429d | 43 | if (err) |
da7fbe58 PO |
44 | return err; |
45 | ||
17b0429d | 46 | return 0; |
da7fbe58 PO |
47 | } |
48 | ||
49 | int mmc_select_card(struct mmc_card *card) | |
50 | { | |
51 | BUG_ON(!card); | |
52 | ||
53 | return _mmc_select_card(card->host, card); | |
54 | } | |
55 | ||
56 | int mmc_deselect_cards(struct mmc_host *host) | |
57 | { | |
58 | return _mmc_select_card(host, NULL); | |
59 | } | |
60 | ||
61 | int mmc_go_idle(struct mmc_host *host) | |
62 | { | |
63 | int err; | |
64 | struct mmc_command cmd; | |
65 | ||
af517150 DB |
66 | /* |
67 | * Non-SPI hosts need to prevent chipselect going active during | |
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 | } | |
da7fbe58 PO |
79 | |
80 | memset(&cmd, 0, sizeof(struct mmc_command)); | |
81 | ||
82 | cmd.opcode = MMC_GO_IDLE_STATE; | |
83 | cmd.arg = 0; | |
af517150 | 84 | cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_NONE | MMC_CMD_BC; |
da7fbe58 PO |
85 | |
86 | err = mmc_wait_for_cmd(host, &cmd, 0); | |
87 | ||
88 | mmc_delay(1); | |
89 | ||
af517150 DB |
90 | if (!mmc_host_is_spi(host)) { |
91 | mmc_set_chip_select(host, MMC_CS_DONTCARE); | |
92 | mmc_delay(1); | |
93 | } | |
da7fbe58 | 94 | |
af517150 | 95 | host->use_spi_crc = 0; |
da7fbe58 PO |
96 | |
97 | return err; | |
98 | } | |
99 | ||
100 | int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) | |
101 | { | |
102 | struct mmc_command cmd; | |
103 | int i, err = 0; | |
104 | ||
105 | BUG_ON(!host); | |
106 | ||
107 | memset(&cmd, 0, sizeof(struct mmc_command)); | |
108 | ||
109 | cmd.opcode = MMC_SEND_OP_COND; | |
af517150 DB |
110 | cmd.arg = mmc_host_is_spi(host) ? 0 : ocr; |
111 | cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR; | |
da7fbe58 PO |
112 | |
113 | for (i = 100; i; i--) { | |
114 | err = mmc_wait_for_cmd(host, &cmd, 0); | |
17b0429d | 115 | if (err) |
da7fbe58 PO |
116 | break; |
117 | ||
af517150 DB |
118 | /* if we're just probing, do a single pass */ |
119 | if (ocr == 0) | |
da7fbe58 PO |
120 | break; |
121 | ||
af517150 DB |
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 | ||
17b0429d | 131 | err = -ETIMEDOUT; |
da7fbe58 PO |
132 | |
133 | mmc_delay(10); | |
134 | } | |
135 | ||
af517150 | 136 | if (rocr && !mmc_host_is_spi(host)) |
da7fbe58 PO |
137 | *rocr = cmd.resp[0]; |
138 | ||
139 | return err; | |
140 | } | |
141 | ||
142 | int mmc_all_send_cid(struct mmc_host *host, u32 *cid) | |
143 | { | |
144 | int err; | |
145 | struct mmc_command cmd; | |
146 | ||
147 | BUG_ON(!host); | |
148 | BUG_ON(!cid); | |
149 | ||
150 | memset(&cmd, 0, sizeof(struct mmc_command)); | |
151 | ||
152 | cmd.opcode = MMC_ALL_SEND_CID; | |
153 | cmd.arg = 0; | |
154 | cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR; | |
155 | ||
156 | err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES); | |
17b0429d | 157 | if (err) |
da7fbe58 PO |
158 | return err; |
159 | ||
160 | memcpy(cid, cmd.resp, sizeof(u32) * 4); | |
161 | ||
17b0429d | 162 | return 0; |
da7fbe58 PO |
163 | } |
164 | ||
165 | int mmc_set_relative_addr(struct mmc_card *card) | |
166 | { | |
167 | int err; | |
168 | struct mmc_command cmd; | |
169 | ||
170 | BUG_ON(!card); | |
171 | BUG_ON(!card->host); | |
172 | ||
173 | memset(&cmd, 0, sizeof(struct mmc_command)); | |
174 | ||
175 | cmd.opcode = MMC_SET_RELATIVE_ADDR; | |
176 | cmd.arg = card->rca << 16; | |
177 | cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; | |
178 | ||
179 | err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); | |
17b0429d | 180 | if (err) |
da7fbe58 PO |
181 | return err; |
182 | ||
17b0429d | 183 | return 0; |
da7fbe58 PO |
184 | } |
185 | ||
af517150 DB |
186 | static int |
187 | mmc_send_cxd_native(struct mmc_host *host, u32 arg, u32 *cxd, int opcode) | |
da7fbe58 PO |
188 | { |
189 | int err; | |
190 | struct mmc_command cmd; | |
191 | ||
af517150 DB |
192 | BUG_ON(!host); |
193 | BUG_ON(!cxd); | |
da7fbe58 PO |
194 | |
195 | memset(&cmd, 0, sizeof(struct mmc_command)); | |
196 | ||
af517150 DB |
197 | cmd.opcode = opcode; |
198 | cmd.arg = arg; | |
da7fbe58 PO |
199 | cmd.flags = MMC_RSP_R2 | MMC_CMD_AC; |
200 | ||
af517150 | 201 | err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES); |
17b0429d | 202 | if (err) |
da7fbe58 PO |
203 | return err; |
204 | ||
af517150 | 205 | memcpy(cxd, cmd.resp, sizeof(u32) * 4); |
da7fbe58 | 206 | |
17b0429d | 207 | return 0; |
da7fbe58 PO |
208 | } |
209 | ||
af517150 DB |
210 | static int |
211 | mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host, | |
212 | u32 opcode, void *buf, unsigned len) | |
da7fbe58 PO |
213 | { |
214 | struct mmc_request mrq; | |
215 | struct mmc_command cmd; | |
216 | struct mmc_data data; | |
217 | struct scatterlist sg; | |
af517150 | 218 | void *data_buf; |
da7fbe58 | 219 | |
af517150 DB |
220 | /* dma onto stack is unsafe/nonportable, but callers to this |
221 | * routine normally provide temporary on-stack buffers ... | |
222 | */ | |
223 | data_buf = kmalloc(len, GFP_KERNEL); | |
224 | if (data_buf == NULL) | |
225 | return -ENOMEM; | |
da7fbe58 PO |
226 | |
227 | memset(&mrq, 0, sizeof(struct mmc_request)); | |
228 | memset(&cmd, 0, sizeof(struct mmc_command)); | |
229 | memset(&data, 0, sizeof(struct mmc_data)); | |
230 | ||
231 | mrq.cmd = &cmd; | |
232 | mrq.data = &data; | |
233 | ||
af517150 | 234 | cmd.opcode = opcode; |
da7fbe58 | 235 | cmd.arg = 0; |
da7fbe58 | 236 | |
af517150 DB |
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; | |
da7fbe58 PO |
245 | data.blocks = 1; |
246 | data.flags = MMC_DATA_READ; | |
247 | data.sg = &sg; | |
248 | data.sg_len = 1; | |
249 | ||
af517150 | 250 | sg_init_one(&sg, data_buf, len); |
da7fbe58 | 251 | |
af517150 DB |
252 | if (card) |
253 | mmc_set_data_timeout(&data, card); | |
da7fbe58 | 254 | |
af517150 DB |
255 | mmc_wait_for_req(host, &mrq); |
256 | ||
257 | memcpy(buf, data_buf, len); | |
258 | kfree(data_buf); | |
da7fbe58 | 259 | |
17b0429d | 260 | if (cmd.error) |
da7fbe58 | 261 | return cmd.error; |
17b0429d | 262 | if (data.error) |
da7fbe58 PO |
263 | return data.error; |
264 | ||
17b0429d | 265 | return 0; |
da7fbe58 PO |
266 | } |
267 | ||
af517150 DB |
268 | int mmc_send_csd(struct mmc_card *card, u32 *csd) |
269 | { | |
78e48073 PO |
270 | int ret, i; |
271 | ||
af517150 DB |
272 | if (!mmc_host_is_spi(card->host)) |
273 | return mmc_send_cxd_native(card->host, card->rca << 16, | |
274 | csd, MMC_SEND_CSD); | |
275 | ||
78e48073 PO |
276 | ret = mmc_send_cxd_data(card, card->host, MMC_SEND_CSD, csd, 16); |
277 | if (ret) | |
278 | return ret; | |
279 | ||
280 | for (i = 0;i < 4;i++) | |
281 | csd[i] = be32_to_cpu(csd[i]); | |
282 | ||
283 | return 0; | |
af517150 DB |
284 | } |
285 | ||
286 | int mmc_send_cid(struct mmc_host *host, u32 *cid) | |
287 | { | |
78e48073 PO |
288 | int ret, i; |
289 | ||
af517150 DB |
290 | if (!mmc_host_is_spi(host)) { |
291 | if (!host->card) | |
292 | return -EINVAL; | |
293 | return mmc_send_cxd_native(host, host->card->rca << 16, | |
294 | cid, MMC_SEND_CID); | |
295 | } | |
296 | ||
78e48073 PO |
297 | ret = mmc_send_cxd_data(NULL, host, MMC_SEND_CID, cid, 16); |
298 | if (ret) | |
299 | return ret; | |
300 | ||
301 | for (i = 0;i < 4;i++) | |
302 | cid[i] = be32_to_cpu(cid[i]); | |
303 | ||
304 | return 0; | |
af517150 DB |
305 | } |
306 | ||
307 | int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd) | |
308 | { | |
309 | return mmc_send_cxd_data(card, card->host, MMC_SEND_EXT_CSD, | |
310 | ext_csd, 512); | |
311 | } | |
312 | ||
313 | int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp) | |
314 | { | |
315 | struct mmc_command cmd; | |
316 | int err; | |
317 | ||
318 | memset(&cmd, 0, sizeof(struct mmc_command)); | |
319 | ||
320 | cmd.opcode = MMC_SPI_READ_OCR; | |
321 | cmd.arg = highcap ? (1 << 30) : 0; | |
322 | cmd.flags = MMC_RSP_SPI_R3; | |
323 | ||
324 | err = mmc_wait_for_cmd(host, &cmd, 0); | |
325 | ||
326 | *ocrp = cmd.resp[1]; | |
327 | return err; | |
328 | } | |
329 | ||
330 | int mmc_spi_set_crc(struct mmc_host *host, int use_crc) | |
331 | { | |
332 | struct mmc_command cmd; | |
333 | int err; | |
334 | ||
335 | memset(&cmd, 0, sizeof(struct mmc_command)); | |
336 | ||
337 | cmd.opcode = MMC_SPI_CRC_ON_OFF; | |
338 | cmd.flags = MMC_RSP_SPI_R1; | |
339 | cmd.arg = use_crc; | |
340 | ||
341 | err = mmc_wait_for_cmd(host, &cmd, 0); | |
342 | if (!err) | |
343 | host->use_spi_crc = use_crc; | |
344 | return err; | |
345 | } | |
346 | ||
da7fbe58 PO |
347 | int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value) |
348 | { | |
349 | int err; | |
350 | struct mmc_command cmd; | |
351 | ||
352 | BUG_ON(!card); | |
353 | BUG_ON(!card->host); | |
354 | ||
355 | memset(&cmd, 0, sizeof(struct mmc_command)); | |
356 | ||
357 | cmd.opcode = MMC_SWITCH; | |
358 | cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | | |
359 | (index << 16) | | |
360 | (value << 8) | | |
361 | set; | |
af517150 | 362 | cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC; |
da7fbe58 PO |
363 | |
364 | err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); | |
17b0429d | 365 | if (err) |
da7fbe58 PO |
366 | return err; |
367 | ||
17b0429d | 368 | return 0; |
da7fbe58 PO |
369 | } |
370 | ||
371 | int mmc_send_status(struct mmc_card *card, u32 *status) | |
372 | { | |
373 | int err; | |
374 | struct mmc_command cmd; | |
375 | ||
376 | BUG_ON(!card); | |
377 | BUG_ON(!card->host); | |
378 | ||
379 | memset(&cmd, 0, sizeof(struct mmc_command)); | |
380 | ||
381 | cmd.opcode = MMC_SEND_STATUS; | |
af517150 DB |
382 | if (!mmc_host_is_spi(card->host)) |
383 | cmd.arg = card->rca << 16; | |
384 | cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC; | |
da7fbe58 PO |
385 | |
386 | err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); | |
17b0429d | 387 | if (err) |
da7fbe58 PO |
388 | return err; |
389 | ||
af517150 DB |
390 | /* NOTE: callers are required to understand the difference |
391 | * between "native" and SPI format status words! | |
392 | */ | |
da7fbe58 PO |
393 | if (status) |
394 | *status = cmd.resp[0]; | |
395 | ||
17b0429d | 396 | return 0; |
da7fbe58 PO |
397 | } |
398 |