diff options
author | Pierre Ossman <drzeus@drzeus.cx> | 2007-07-06 13:35:01 +0200 |
---|---|---|
committer | Pierre Ossman <drzeus@drzeus.cx> | 2007-09-23 21:09:34 +0200 |
commit | 112c9db91ee6bf19eca7cbb6854be3127381c229 (patch) | |
tree | e2d45c7d18a4a218cc0716d7aef79aa04b73a498 /drivers/mmc/core/sdio_ops.c | |
parent | sdio: add /proc interface to sdio_uart driver (diff) | |
download | linux-112c9db91ee6bf19eca7cbb6854be3127381c229.tar.xz linux-112c9db91ee6bf19eca7cbb6854be3127381c229.zip |
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/core/sdio_ops.c')
-rw-r--r-- | drivers/mmc/core/sdio_ops.c | 57 |
1 files changed, 57 insertions, 0 deletions
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 @@ * your option) any later version. */ +#include <asm/scatterlist.h> +#include <linux/scatterlist.h> + #include <linux/mmc/host.h> #include <linux/mmc/card.h> #include <linux/mmc/mmc.h> @@ -84,3 +87,57 @@ int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, return 0; } +int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, + unsigned addr, int bang, u8 *buf, unsigned size) +{ + struct mmc_request mrq; + struct mmc_command cmd; + struct mmc_data data; + struct scatterlist sg; + + BUG_ON(!card); + BUG_ON(fn > 7); + BUG_ON(size > 512); + + memset(&mrq, 0, sizeof(struct mmc_request)); + memset(&cmd, 0, sizeof(struct mmc_command)); + memset(&data, 0, sizeof(struct mmc_data)); + + mrq.cmd = &cmd; + mrq.data = &data; + + cmd.opcode = SD_IO_RW_EXTENDED; + cmd.arg = write ? 0x80000000 : 0x00000000; + cmd.arg |= fn << 28; + cmd.arg |= bang ? 0x00000000 : 0x04000000; + cmd.arg |= addr << 9; + cmd.arg |= (size == 512) ? 0 : size; + cmd.flags = MMC_RSP_R5 | MMC_CMD_ADTC; + + data.blksz = size; + data.blocks = 1; + data.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ; + data.sg = &sg; + data.sg_len = 1; + + sg_init_one(&sg, buf, size); + + mmc_set_data_timeout(&data, card); + + mmc_wait_for_req(card->host, &mrq); + + if (cmd.error) + return cmd.error; + if (data.error) + return data.error; + + 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; + + return 0; +} + |