diff options
author | Pierre Ossman <drzeus@drzeus.cx> | 2007-07-06 07:35:01 -0400 |
---|---|---|
committer | Pierre Ossman <drzeus@drzeus.cx> | 2007-09-23 15:09:34 -0400 |
commit | 112c9db91ee6bf19eca7cbb6854be3127381c229 (patch) | |
tree | e2d45c7d18a4a218cc0716d7aef79aa04b73a498 /drivers/mmc | |
parent | 5ed334a1f8caaae98806d572f78c5802975ea20f (diff) |
sdio: support IO_RW_EXTENDED
Support the multi-byte transfer operation, including handlers for
common operations like writel()/readl().
Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/core/sdio_io.c | 184 | ||||
-rw-r--r-- | drivers/mmc/core/sdio_ops.c | 57 | ||||
-rw-r--r-- | drivers/mmc/core/sdio_ops.h | 2 |
3 files changed, 243 insertions, 0 deletions
diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c index eb6c20935cef..ecdb77242e98 100644 --- a/drivers/mmc/core/sdio_io.c +++ b/drivers/mmc/core/sdio_io.c | |||
@@ -196,3 +196,187 @@ void sdio_writeb(struct sdio_func *func, unsigned char b, unsigned int addr, | |||
196 | } | 196 | } |
197 | EXPORT_SYMBOL_GPL(sdio_writeb); | 197 | EXPORT_SYMBOL_GPL(sdio_writeb); |
198 | 198 | ||
199 | /** | ||
200 | * sdio_memcpy_fromio - read a chunk of memory from a SDIO function | ||
201 | * @func: SDIO function to access | ||
202 | * @dst: buffer to store the data | ||
203 | * @addr: address to begin reading from | ||
204 | * @count: number of bytes to read | ||
205 | * | ||
206 | * Reads up to 512 bytes from the address space of a given SDIO | ||
207 | * function. Return value indicates if the transfer succeeded or | ||
208 | * not. | ||
209 | */ | ||
210 | int sdio_memcpy_fromio(struct sdio_func *func, void *dst, | ||
211 | unsigned int addr, int count) | ||
212 | { | ||
213 | return mmc_io_rw_extended(func->card, 0, func->num, addr, 0, dst, | ||
214 | count); | ||
215 | } | ||
216 | EXPORT_SYMBOL_GPL(sdio_memcpy_fromio); | ||
217 | |||
218 | /** | ||
219 | * sdio_memcpy_toio - write a chunk of memory to a SDIO function | ||
220 | * @func: SDIO function to access | ||
221 | * @addr: address to start writing to | ||
222 | * @src: buffer that contains the data to write | ||
223 | * @count: number of bytes to write | ||
224 | * | ||
225 | * Writes up to 512 bytes to the address space of a given SDIO | ||
226 | * function. Return value indicates if the transfer succeeded or | ||
227 | * not. | ||
228 | */ | ||
229 | int sdio_memcpy_toio(struct sdio_func *func, unsigned int addr, | ||
230 | void *src, int count) | ||
231 | { | ||
232 | return mmc_io_rw_extended(func->card, 1, func->num, addr, 0, src, | ||
233 | count); | ||
234 | } | ||
235 | EXPORT_SYMBOL_GPL(sdio_memcpy_toio); | ||
236 | |||
237 | /** | ||
238 | * sdio_readsb - read from a FIFO on a SDIO function | ||
239 | * @func: SDIO function to access | ||
240 | * @dst: buffer to store the data | ||
241 | * @addr: address of (single byte) FIFO | ||
242 | * @count: number of bytes to read | ||
243 | * | ||
244 | * Reads up to 512 bytes from the specified FIFO of a given SDIO | ||
245 | * function. Return value indicates if the transfer succeeded or | ||
246 | * not. | ||
247 | */ | ||
248 | int sdio_readsb(struct sdio_func *func, void *dst, unsigned int addr, | ||
249 | int count) | ||
250 | { | ||
251 | return mmc_io_rw_extended(func->card, 0, func->num, addr, 1, dst, | ||
252 | count); | ||
253 | } | ||
254 | |||
255 | EXPORT_SYMBOL_GPL(sdio_readsb); | ||
256 | |||
257 | /** | ||
258 | * sdio_writesb - write to a FIFO of a SDIO function | ||
259 | * @func: SDIO function to access | ||
260 | * @addr: address of (single byte) FIFO | ||
261 | * @src: buffer that contains the data to write | ||
262 | * @count: number of bytes to write | ||
263 | * | ||
264 | * Writes up to 512 bytes to the specified FIFO of a given SDIO | ||
265 | * function. Return value indicates if the transfer succeeded or | ||
266 | * not. | ||
267 | */ | ||
268 | int sdio_writesb(struct sdio_func *func, unsigned int addr, void *src, | ||
269 | int count) | ||
270 | { | ||
271 | return mmc_io_rw_extended(func->card, 1, func->num, addr, 1, src, | ||
272 | count); | ||
273 | } | ||
274 | EXPORT_SYMBOL_GPL(sdio_writesb); | ||
275 | |||
276 | /** | ||
277 | * sdio_readw - read a 16 bit integer from a SDIO function | ||
278 | * @func: SDIO function to access | ||
279 | * @addr: address to read | ||
280 | * @err_ret: optional status value from transfer | ||
281 | * | ||
282 | * Reads a 16 bit integer from the address space of a given SDIO | ||
283 | * function. If there is a problem reading the address, 0xffff | ||
284 | * is returned and @err_ret will contain the error code. | ||
285 | */ | ||
286 | unsigned short sdio_readw(struct sdio_func *func, unsigned int addr, | ||
287 | int *err_ret) | ||
288 | { | ||
289 | int ret; | ||
290 | |||
291 | if (err_ret) | ||
292 | *err_ret = 0; | ||
293 | |||
294 | ret = sdio_memcpy_fromio(func, func->tmpbuf, addr, 2); | ||
295 | if (ret) { | ||
296 | if (err_ret) | ||
297 | *err_ret = ret; | ||
298 | return 0xFFFF; | ||
299 | } | ||
300 | |||
301 | return le16_to_cpu(*(u16*)func->tmpbuf); | ||
302 | } | ||
303 | EXPORT_SYMBOL_GPL(sdio_readw); | ||
304 | |||
305 | /** | ||
306 | * sdio_writew - write a 16 bit integer to a SDIO function | ||
307 | * @func: SDIO function to access | ||
308 | * @b: integer to write | ||
309 | * @addr: address to write to | ||
310 | * @err_ret: optional status value from transfer | ||
311 | * | ||
312 | * Writes a 16 bit integer to the address space of a given SDIO | ||
313 | * function. @err_ret will contain the status of the actual | ||
314 | * transfer. | ||
315 | */ | ||
316 | void sdio_writew(struct sdio_func *func, unsigned short b, unsigned int addr, | ||
317 | int *err_ret) | ||
318 | { | ||
319 | int ret; | ||
320 | |||
321 | *(u16*)func->tmpbuf = cpu_to_le16(b); | ||
322 | |||
323 | ret = sdio_memcpy_toio(func, addr, func->tmpbuf, 2); | ||
324 | if (err_ret) | ||
325 | *err_ret = ret; | ||
326 | } | ||
327 | EXPORT_SYMBOL_GPL(sdio_writew); | ||
328 | |||
329 | /** | ||
330 | * sdio_readl - read a 32 bit integer from a SDIO function | ||
331 | * @func: SDIO function to access | ||
332 | * @addr: address to read | ||
333 | * @err_ret: optional status value from transfer | ||
334 | * | ||
335 | * Reads a 32 bit integer from the address space of a given SDIO | ||
336 | * function. If there is a problem reading the address, | ||
337 | * 0xffffffff is returned and @err_ret will contain the error | ||
338 | * code. | ||
339 | */ | ||
340 | unsigned long sdio_readl(struct sdio_func *func, unsigned int addr, | ||
341 | int *err_ret) | ||
342 | { | ||
343 | int ret; | ||
344 | |||
345 | if (err_ret) | ||
346 | *err_ret = 0; | ||
347 | |||
348 | ret = sdio_memcpy_fromio(func, func->tmpbuf, addr, 4); | ||
349 | if (ret) { | ||
350 | if (err_ret) | ||
351 | *err_ret = ret; | ||
352 | return 0xFFFFFFFF; | ||
353 | } | ||
354 | |||
355 | return le32_to_cpu(*(u32*)func->tmpbuf); | ||
356 | } | ||
357 | EXPORT_SYMBOL_GPL(sdio_readl); | ||
358 | |||
359 | /** | ||
360 | * sdio_writel - write a 32 bit integer to a SDIO function | ||
361 | * @func: SDIO function to access | ||
362 | * @b: integer to write | ||
363 | * @addr: address to write to | ||
364 | * @err_ret: optional status value from transfer | ||
365 | * | ||
366 | * Writes a 32 bit integer to the address space of a given SDIO | ||
367 | * function. @err_ret will contain the status of the actual | ||
368 | * transfer. | ||
369 | */ | ||
370 | void sdio_writel(struct sdio_func *func, unsigned long b, unsigned int addr, | ||
371 | int *err_ret) | ||
372 | { | ||
373 | int ret; | ||
374 | |||
375 | *(u32*)func->tmpbuf = cpu_to_le32(b); | ||
376 | |||
377 | ret = sdio_memcpy_toio(func, addr, func->tmpbuf, 4); | ||
378 | if (err_ret) | ||
379 | *err_ret = ret; | ||
380 | } | ||
381 | EXPORT_SYMBOL_GPL(sdio_writel); | ||
382 | |||
diff --git a/drivers/mmc/core/sdio_ops.c b/drivers/mmc/core/sdio_ops.c index 31233f7b55cd..4f2c77139477 100644 --- a/drivers/mmc/core/sdio_ops.c +++ b/drivers/mmc/core/sdio_ops.c | |||
@@ -9,6 +9,9 @@ | |||
9 | * your option) any later version. | 9 | * your option) any later version. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <asm/scatterlist.h> | ||
13 | #include <linux/scatterlist.h> | ||
14 | |||
12 | #include <linux/mmc/host.h> | 15 | #include <linux/mmc/host.h> |
13 | #include <linux/mmc/card.h> | 16 | #include <linux/mmc/card.h> |
14 | #include <linux/mmc/mmc.h> | 17 | #include <linux/mmc/mmc.h> |
@@ -84,3 +87,57 @@ int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, | |||
84 | return 0; | 87 | return 0; |
85 | } | 88 | } |
86 | 89 | ||
90 | int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, | ||
91 | unsigned addr, int bang, u8 *buf, unsigned size) | ||
92 | { | ||
93 | struct mmc_request mrq; | ||
94 | struct mmc_command cmd; | ||
95 | struct mmc_data data; | ||
96 | struct scatterlist sg; | ||
97 | |||
98 | BUG_ON(!card); | ||
99 | BUG_ON(fn > 7); | ||
100 | BUG_ON(size > 512); | ||
101 | |||
102 | memset(&mrq, 0, sizeof(struct mmc_request)); | ||
103 | memset(&cmd, 0, sizeof(struct mmc_command)); | ||
104 | memset(&data, 0, sizeof(struct mmc_data)); | ||
105 | |||
106 | mrq.cmd = &cmd; | ||
107 | mrq.data = &data; | ||
108 | |||
109 | cmd.opcode = SD_IO_RW_EXTENDED; | ||
110 | cmd.arg = write ? 0x80000000 : 0x00000000; | ||
111 | cmd.arg |= fn << 28; | ||
112 | cmd.arg |= bang ? 0x00000000 : 0x04000000; | ||
113 | cmd.arg |= addr << 9; | ||
114 | cmd.arg |= (size == 512) ? 0 : size; | ||
115 | cmd.flags = MMC_RSP_R5 | MMC_CMD_ADTC; | ||
116 | |||
117 | data.blksz = size; | ||
118 | data.blocks = 1; | ||
119 | data.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ; | ||
120 | data.sg = &sg; | ||
121 | data.sg_len = 1; | ||
122 | |||
123 | sg_init_one(&sg, buf, size); | ||
124 | |||
125 | mmc_set_data_timeout(&data, card); | ||
126 | |||
127 | mmc_wait_for_req(card->host, &mrq); | ||
128 | |||
129 | if (cmd.error) | ||
130 | return cmd.error; | ||
131 | if (data.error) | ||
132 | return data.error; | ||
133 | |||
134 | if (cmd.resp[0] & R5_ERROR) | ||
135 | return -EIO; | ||
136 | if (cmd.resp[0] & R5_FUNCTION_NUMBER) | ||
137 | return -EINVAL; | ||
138 | if (cmd.resp[0] & R5_OUT_OF_RANGE) | ||
139 | return -ERANGE; | ||
140 | |||
141 | return 0; | ||
142 | } | ||
143 | |||
diff --git a/drivers/mmc/core/sdio_ops.h b/drivers/mmc/core/sdio_ops.h index f0e9d69e5ce8..1d42e4f366aa 100644 --- a/drivers/mmc/core/sdio_ops.h +++ b/drivers/mmc/core/sdio_ops.h | |||
@@ -15,6 +15,8 @@ | |||
15 | int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr); | 15 | int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr); |
16 | int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, | 16 | 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, | ||
19 | unsigned addr, int bang, u8 *data, unsigned size); | ||
18 | 20 | ||
19 | #endif | 21 | #endif |
20 | 22 | ||