From: Major Lee <major_...@wistron.com>

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_...@wistron.com>
Signed-off-by: Alan Cox <a...@linux.intel.com>
---

 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 majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to