[PATCH] i2c-intel-mid: I2C FIFO buffer size setting and fragmentation

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Major Lee <major_lee@xxxxxxxxxxx>

The FIFO buffer size is different with different CPU stepping.
Define it as 32-byte; it is safe for all CPU stepping.

There is a problem when xfer size is greater then FIFO buffer size.
Implement software fragmentation in host bus driver so that the
IÂC slave device drivers need not to be modified or to know about the
limits.

Signed-off-by: Major Lee <major_lee@xxxxxxxxxxx>
Signed-off-by: Alan Cox <alan@xxxxxxxxxxxxxxx>
---

 drivers/i2c/busses/i2c-intel-mid.c |   95 +++++++++++++++++-------------------
 1 files changed, 46 insertions(+), 49 deletions(-)


diff --git a/drivers/i2c/busses/i2c-intel-mid.c b/drivers/i2c/busses/i2c-intel-mid.c
index 3975736..da4bbdd 100644
--- a/drivers/i2c/busses/i2c-intel-mid.c
+++ b/drivers/i2c/busses/i2c-intel-mid.c
@@ -54,6 +54,10 @@ enum mid_i2c_status {
 	STATUS_STANDBY
 };
 
+/* The FIFO buffer size is different with different CPU stepping */
+/* Define it as 32-byte; it is safe for all CPU stepping */
+#define I2C_FIFO_SIZE	32
+
 /**
  * struct intel_mid_i2c_private	- per device IÂC context
  * @adap: core i2c layer adapter information
@@ -62,7 +66,6 @@ enum mid_i2c_status {
  * @speed: speed mode for this port
  * @complete: completion object for transaction wait
  * @abort: reason for last abort
- * @rx_buf: pointer into working receive buffer
  * @rx_buf_len: receive buffer length
  * @status: adapter state machine
  * @msg: the message we are currently processing
@@ -79,7 +82,6 @@ struct intel_mid_i2c_private {
 	int speed;
 	struct completion complete;
 	u32 abort;
-	u8 *rx_buf;
 	int rx_buf_len;
 	enum mid_i2c_status status;
 	struct i2c_msg *msg;
@@ -560,17 +562,15 @@ static int xfer_read(struct i2c_adapter *adap, unsigned char *buf, int length)
 	int i = length;
 	int err;
 
-	if (length >= 256) {
-		dev_err(&adap->dev,
-			"I2C FIFO cannot support larger than 256 bytes\n");
-		return -EMSGSIZE;
-	}
-
 	INIT_COMPLETION(i2c->complete);
 
 	readl(i2c->base + IC_CLR_INTR);
 	writel(0x0044, i2c->base + IC_INTR_MASK);
 
+	i2c->rx_buf_len = length;
+	/* set receive FIFO threshold */
+	writel((uint16_t)(length - 1), i2c->base + IC_RX_TL);
+
 	i2c->status = STATUS_READ_START;
 
 	while (i--)
@@ -614,12 +614,6 @@ static int xfer_write(struct i2c_adapter *adap,
 	struct intel_mid_i2c_private *i2c = i2c_get_adapdata(adap);
 	int i, err;
 
-	if (length >= 256) {
-		dev_err(&adap->dev,
-			"I2C FIFO cannot support larger than 256 bytes\n");
-		return -EMSGSIZE;
-	}
-
 	INIT_COMPLETION(i2c->complete);
 
 	readl(i2c->base + IC_CLR_INTR);
@@ -748,6 +742,9 @@ static int intel_mid_i2c_xfer(struct i2c_adapter *adap,
 {
 	struct intel_mid_i2c_private *i2c = i2c_get_adapdata(adap);
 	int i, err = 0;
+	u16 len;
+	u8 *buf;
+	u16 xfer_len;
 
 	/* if number of messages equal 0*/
 	if (num == 0)
@@ -785,13 +782,35 @@ static int intel_mid_i2c_xfer(struct i2c_adapter *adap,
 	for (i = 0; i < num; i++) {
 		i2c->msg = pmsg;
 		i2c->status = STATUS_IDLE;
-		/* Read or Write */
-		if (pmsg->flags & I2C_M_RD) {
-			dev_dbg(&adap->dev, "I2C_M_RD\n");
-			err = xfer_read(adap, pmsg->buf, pmsg->len);
-		} else {
-			dev_dbg(&adap->dev, "I2C_M_WR\n");
-			err = xfer_write(adap, pmsg->buf, pmsg->len);
+
+		if (pmsg->len && pmsg->buf) {
+			len = pmsg->len;
+			buf = pmsg->buf;
+			xfer_len = 0;
+
+			while (len && buf) {
+				/* Fragment xfer data */
+				if (len >= I2C_FIFO_SIZE)
+					xfer_len = I2C_FIFO_SIZE;
+				else
+					xfer_len = len;
+				/* Read or Write */
+				if (pmsg->flags & I2C_M_RD) {
+					dev_dbg(&adap->dev, "I2C_M_RD\n");
+					err = xfer_read(adap, buf, xfer_len);
+				} else {
+					dev_dbg(&adap->dev, "I2C_M_WR\n");
+					err = xfer_write(adap, buf, xfer_len);
+				}
+				if (err < 0)
+					break;
+
+				len -= xfer_len;
+				if (len)
+					buf += xfer_len;
+				else /* len == 0 */
+					break;
+			}
 		}
 		if (err < 0)
 			break;
@@ -875,32 +894,12 @@ static int mrst_i2c_runtime_idle(struct device *dev)
 static void i2c_isr_read(struct intel_mid_i2c_private *i2c)
 {
 	struct i2c_msg *msg = i2c->msg;
-	int rx_num;
-	u32 len;
-	u8 *buf;
-
-	if (!(msg->flags & I2C_M_RD))
-		return;
+	u32 len = i2c->rx_buf_len;
+	u8 *buf = msg->buf;
 
-	if (i2c->status != STATUS_READ_IN_PROGRESS) {
-		len = msg->len;
-		buf = msg->buf;
-	} else {
-		len = i2c->rx_buf_len;
-		buf = i2c->rx_buf;
-	}
-
-	rx_num = readl(i2c->base + IC_RXFLR);
-
-	for (; len > 0 && rx_num > 0; len--, rx_num--)
+	while (len--)
 		*buf++ = readl(i2c->base + IC_DATA_CMD);
-
-	if (len > 0) {
-		i2c->status = STATUS_READ_IN_PROGRESS;
-		i2c->rx_buf_len = len;
-		i2c->rx_buf = buf;
-	} else
-		i2c->status = STATUS_READ_SUCCESS;
+	i2c->status = STATUS_READ_SUCCESS;
 
 	return;
 }
@@ -936,10 +935,8 @@ static irqreturn_t intel_mid_i2c_isr(int this_irq, void *dev)
 		goto exit;
 	}
 
-	if (stat & TX_EMPTY) {
-		if (readl(i2c->base + IC_STATUS) & 0x4)
-			i2c->status = STATUS_WRITE_SUCCESS;
-	}
+	if (stat & TX_EMPTY)
+		i2c->status = STATUS_WRITE_SUCCESS;
 
 exit:
 	if (i2c->status == STATUS_READ_SUCCESS ||

--
To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux GPIO]     [Linux SPI]     [Linux Hardward Monitoring]     [LM Sensors]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux