aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/i2c/busses/i2c-intel-mid.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/i2c/busses/i2c-intel-mid.c')
-rw-r--r--drivers/i2c/busses/i2c-intel-mid.c95
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 0f61f33eaa7..83ddd8044fe 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 ||