فهرست منبع

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>
Pierre Ossman 18 سال پیش
والد
کامیت
112c9db91e
5فایلهای تغییر یافته به همراه275 افزوده شده و 0 حذف شده
  1. 184 0
      drivers/mmc/core/sdio_io.c
  2. 57 0
      drivers/mmc/core/sdio_ops.c
  3. 2 0
      drivers/mmc/core/sdio_ops.h
  4. 12 0
      include/linux/mmc/sdio.h
  5. 20 0
      include/linux/mmc/sdio_func.h

+ 184 - 0
drivers/mmc/core/sdio_io.c

@@ -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);
+

+ 57 - 0
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;
+}
+

+ 2 - 0
drivers/mmc/core/sdio_ops.h

@@ -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
 

+ 12 - 0
include/linux/mmc/sdio.h

@@ -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:
@@ -26,6 +27,17 @@
  *      [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

+ 20 - 0
include/linux/mmc/sdio_func.h

@@ -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