sdio: support IO_RW_EXTENDED
authorPierre Ossman <drzeus@drzeus.cx>
Fri, 6 Jul 2007 11:35:01 +0000 (13:35 +0200)
committerPierre Ossman <drzeus@drzeus.cx>
Sun, 23 Sep 2007 19:09:34 +0000 (21:09 +0200)
Support the multi-byte transfer operation, including handlers for
common operations like writel()/readl().

Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
drivers/mmc/core/sdio_io.c
drivers/mmc/core/sdio_ops.c
drivers/mmc/core/sdio_ops.h
include/linux/mmc/sdio.h
include/linux/mmc/sdio_func.h

index eb6c20935cef18e121fb1442169277eceed3f200..ecdb77242e98f9033156435d90e57bc2258d2b03 100644 (file)
@@ -196,3 +196,187 @@ void sdio_writeb(struct sdio_func *func, unsigned char b, unsigned int addr,
 }
 EXPORT_SYMBOL_GPL(sdio_writeb);
 
+/**
+ *     sdio_memcpy_fromio - read a chunk of memory from a SDIO function
+ *     @func: SDIO function to access
+ *     @dst: buffer to store the data
+ *     @addr: address to begin reading from
+ *     @count: number of bytes to read
+ *
+ *     Reads up to 512 bytes from the address space of a given SDIO
+ *     function. Return value indicates if the transfer succeeded or
+ *     not.
+ */
+int sdio_memcpy_fromio(struct sdio_func *func, void *dst,
+       unsigned int addr, int count)
+{
+       return mmc_io_rw_extended(func->card, 0, func->num, addr, 0, dst,
+               count);
+}
+EXPORT_SYMBOL_GPL(sdio_memcpy_fromio);
+
+/**
+ *     sdio_memcpy_toio - write a chunk of memory to a SDIO function
+ *     @func: SDIO function to access
+ *     @addr: address to start writing to
+ *     @src: buffer that contains the data to write
+ *     @count: number of bytes to write
+ *
+ *     Writes up to 512 bytes to the address space of a given SDIO
+ *     function. Return value indicates if the transfer succeeded or
+ *     not.
+ */
+int sdio_memcpy_toio(struct sdio_func *func, unsigned int addr,
+       void *src, int count)
+{
+       return mmc_io_rw_extended(func->card, 1, func->num, addr, 0, src,
+               count);
+}
+EXPORT_SYMBOL_GPL(sdio_memcpy_toio);
+
+/**
+ *     sdio_readsb - read from a FIFO on a SDIO function
+ *     @func: SDIO function to access
+ *     @dst: buffer to store the data
+ *     @addr: address of (single byte) FIFO
+ *     @count: number of bytes to read
+ *
+ *     Reads up to 512 bytes from the specified FIFO of a given SDIO
+ *     function. Return value indicates if the transfer succeeded or
+ *     not.
+ */
+int sdio_readsb(struct sdio_func *func, void *dst, unsigned int addr,
+       int count)
+{
+       return mmc_io_rw_extended(func->card, 0, func->num, addr, 1, dst,
+               count);
+}
+
+EXPORT_SYMBOL_GPL(sdio_readsb);
+
+/**
+ *     sdio_writesb - write to a FIFO of a SDIO function
+ *     @func: SDIO function to access
+ *     @addr: address of (single byte) FIFO
+ *     @src: buffer that contains the data to write
+ *     @count: number of bytes to write
+ *
+ *     Writes up to 512 bytes to the specified FIFO of a given SDIO
+ *     function. Return value indicates if the transfer succeeded or
+ *     not.
+ */
+int sdio_writesb(struct sdio_func *func, unsigned int addr, void *src,
+       int count)
+{
+       return mmc_io_rw_extended(func->card, 1, func->num, addr, 1, src,
+               count);
+}
+EXPORT_SYMBOL_GPL(sdio_writesb);
+
+/**
+ *     sdio_readw - read a 16 bit integer from a SDIO function
+ *     @func: SDIO function to access
+ *     @addr: address to read
+ *     @err_ret: optional status value from transfer
+ *
+ *     Reads a 16 bit integer from the address space of a given SDIO
+ *     function. If there is a problem reading the address, 0xffff
+ *     is returned and @err_ret will contain the error code.
+ */
+unsigned short sdio_readw(struct sdio_func *func, unsigned int addr,
+       int *err_ret)
+{
+       int ret;
+
+       if (err_ret)
+               *err_ret = 0;
+
+       ret = sdio_memcpy_fromio(func, func->tmpbuf, addr, 2);
+       if (ret) {
+               if (err_ret)
+                       *err_ret = ret;
+               return 0xFFFF;
+       }
+
+       return le16_to_cpu(*(u16*)func->tmpbuf);
+}
+EXPORT_SYMBOL_GPL(sdio_readw);
+
+/**
+ *     sdio_writew - write a 16 bit integer to a SDIO function
+ *     @func: SDIO function to access
+ *     @b: integer to write
+ *     @addr: address to write to
+ *     @err_ret: optional status value from transfer
+ *
+ *     Writes a 16 bit integer to the address space of a given SDIO
+ *     function. @err_ret will contain the status of the actual
+ *     transfer.
+ */
+void sdio_writew(struct sdio_func *func, unsigned short b, unsigned int addr,
+       int *err_ret)
+{
+       int ret;
+
+       *(u16*)func->tmpbuf = cpu_to_le16(b);
+
+       ret = sdio_memcpy_toio(func, addr, func->tmpbuf, 2);
+       if (err_ret)
+               *err_ret = ret;
+}
+EXPORT_SYMBOL_GPL(sdio_writew);
+
+/**
+ *     sdio_readl - read a 32 bit integer from a SDIO function
+ *     @func: SDIO function to access
+ *     @addr: address to read
+ *     @err_ret: optional status value from transfer
+ *
+ *     Reads a 32 bit integer from the address space of a given SDIO
+ *     function. If there is a problem reading the address,
+ *     0xffffffff is returned and @err_ret will contain the error
+ *     code.
+ */
+unsigned long sdio_readl(struct sdio_func *func, unsigned int addr,
+       int *err_ret)
+{
+       int ret;
+
+       if (err_ret)
+               *err_ret = 0;
+
+       ret = sdio_memcpy_fromio(func, func->tmpbuf, addr, 4);
+       if (ret) {
+               if (err_ret)
+                       *err_ret = ret;
+               return 0xFFFFFFFF;
+       }
+
+       return le32_to_cpu(*(u32*)func->tmpbuf);
+}
+EXPORT_SYMBOL_GPL(sdio_readl);
+
+/**
+ *     sdio_writel - write a 32 bit integer to a SDIO function
+ *     @func: SDIO function to access
+ *     @b: integer to write
+ *     @addr: address to write to
+ *     @err_ret: optional status value from transfer
+ *
+ *     Writes a 32 bit integer to the address space of a given SDIO
+ *     function. @err_ret will contain the status of the actual
+ *     transfer.
+ */
+void sdio_writel(struct sdio_func *func, unsigned long b, unsigned int addr,
+       int *err_ret)
+{
+       int ret;
+
+       *(u32*)func->tmpbuf = cpu_to_le32(b);
+
+       ret = sdio_memcpy_toio(func, addr, func->tmpbuf, 4);
+       if (err_ret)
+               *err_ret = ret;
+}
+EXPORT_SYMBOL_GPL(sdio_writel);
+
index 31233f7b55cdb67e2a789bb2d583f0f6a96e4945..4f2c771394777365f90ba395305b40e6eee61f49 100644 (file)
@@ -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;
+}
+
index f0e9d69e5ce84239839b0d2c2db7b9041c104605..1d42e4f366aad2a5f16fc6a4bdb7f13bbc3f39e3 100644 (file)
@@ -15,6 +15,8 @@
 int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr);
 int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn,
        unsigned addr, u8 in, u8* out);
+int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
+       unsigned addr, int bang, u8 *data, unsigned size);
 
 #endif
 
index 56239f4aab042f8b02a4f50c53f01a77259b9e41..9b1ec76cac379fa088a7f2424a19af64ff045301 100644 (file)
@@ -15,6 +15,7 @@
 /* SDIO commands                         type  argument     response */
 #define SD_IO_SEND_OP_COND          5 /* bcr  [23:0] OCR         R4  */
 #define SD_IO_RW_DIRECT            52 /* ac   [31:0] See below   R5  */
+#define SD_IO_RW_EXTENDED          53 /* adtc [31:0] See below   R5  */
 
 /*
  * SD_IO_RW_DIRECT argument format:
  *      [7:0] Data
  */
 
+/*
+ * SD_IO_RW_EXTENDED argument format:
+ *
+ *      [31] R/W flag
+ *      [30:28] Function number
+ *      [27] Block mode
+ *      [26] Increment address
+ *      [25:9] Register address
+ *      [8:0] Byte/block count
+ */
+
 /*
   SDIO status in R5
   Type
index a8d268c9c27610a27d261e75b72f9536f4b66c96..af813fffc4acd560ac35c81ba5e481718f674e68 100644 (file)
@@ -48,6 +48,8 @@ struct sdio_func {
        unsigned int            state;          /* function state */
 #define SDIO_STATE_PRESENT     (1<<0)          /* present in sysfs */
 
+       u8                      tmpbuf[4];      /* DMA:able scratch buffer */
+
        struct sdio_func_tuple *tuples;
 };
 
@@ -114,9 +116,27 @@ extern int sdio_release_irq(struct sdio_func *func);
 
 extern unsigned char sdio_readb(struct sdio_func *func,
        unsigned int addr, int *err_ret);
+extern unsigned short sdio_readw(struct sdio_func *func,
+       unsigned int addr, int *err_ret);
+extern unsigned long sdio_readl(struct sdio_func *func,
+       unsigned int addr, int *err_ret);
+
+extern int sdio_memcpy_fromio(struct sdio_func *func, void *dst,
+       unsigned int addr, int count);
+extern int sdio_readsb(struct sdio_func *func, void *dst,
+       unsigned int addr, int count);
 
 extern void sdio_writeb(struct sdio_func *func, unsigned char b,
        unsigned int addr, int *err_ret);
+extern void sdio_writew(struct sdio_func *func, unsigned short b,
+       unsigned int addr, int *err_ret);
+extern void sdio_writel(struct sdio_func *func, unsigned long b,
+       unsigned int addr, int *err_ret);
+
+extern int sdio_memcpy_toio(struct sdio_func *func, unsigned int addr,
+       void *src, int count);
+extern int sdio_writesb(struct sdio_func *func, unsigned int addr,
+       void *src, int count);
 
 #endif