aboutsummaryrefslogtreecommitdiff
path: root/drivers/i2c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/busses/i2c-xiic.c53
1 files changed, 53 insertions, 0 deletions
diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c
index 839564054501..86da622e060c 100644
--- a/drivers/i2c/busses/i2c-xiic.c
+++ b/drivers/i2c/busses/i2c-xiic.c
@@ -61,6 +61,7 @@ enum xiic_endian {
* @state: See STATE_
* @singlemaster: Indicates bus is single master
* @dynamic: Mode of controller
+ * @prev_msg_tx: Previous message is Tx
*/
struct xiic_i2c {
struct device *dev;
@@ -78,6 +79,7 @@ struct xiic_i2c {
enum xilinx_i2c_state state;
bool singlemaster;
bool dynamic;
+ bool prev_msg_tx;
};
#define XIIC_MSB_OFFSET 0
@@ -280,6 +282,24 @@ static int xiic_clear_rx_fifo(struct xiic_i2c *i2c)
return 0;
}
+static int xiic_wait_tx_empty(struct xiic_i2c *i2c)
+{
+ u8 isr;
+ unsigned long timeout;
+
+ timeout = jiffies + XIIC_I2C_TIMEOUT;
+ for (isr = xiic_getreg32(i2c, XIIC_IISR_OFFSET);
+ !(isr & XIIC_INTR_TX_EMPTY_MASK);
+ isr = xiic_getreg32(i2c, XIIC_IISR_OFFSET)) {
+ if (time_after(jiffies, timeout)) {
+ dev_err(i2c->dev, "Timeout waiting at Tx empty\n");
+ return -ETIMEDOUT;
+ }
+ }
+
+ return 0;
+}
+
static int xiic_reinit(struct xiic_i2c *i2c)
{
int ret;
@@ -685,6 +705,20 @@ static void xiic_start_recv(struct xiic_i2c *i2c)
local_irq_restore(flags);
} else {
+ /*
+ * If previous message is Tx, make sure that Tx FIFO is empty
+ * before starting a new transfer as the repeated start in
+ * standard mode can corrupt the transaction if there are
+ * still bytes to be transmitted in FIFO
+ */
+ if (i2c->prev_msg_tx) {
+ int status;
+
+ status = xiic_wait_tx_empty(i2c);
+ if (status)
+ return;
+ }
+
cr = xiic_getreg8(i2c, XIIC_CR_REG_OFFSET);
/* Set Receive fifo depth */
@@ -739,6 +773,8 @@ static void xiic_start_recv(struct xiic_i2c *i2c)
/* Enable interrupts */
xiic_setreg32(i2c, XIIC_DGIER_OFFSET, XIIC_GINTR_ENABLE_MASK);
+
+ i2c->prev_msg_tx = false;
}
static void xiic_start_send(struct xiic_i2c *i2c)
@@ -773,6 +809,19 @@ static void xiic_start_send(struct xiic_i2c *i2c)
xiic_fill_tx_fifo(i2c);
} else {
+ /*
+ * If previous message is Tx, make sure that Tx FIFO is empty
+ * before starting a new transfer as the repeated start in
+ * standard mode can corrupt the transaction if there are
+ * still bytes to be transmitted in FIFO
+ */
+ if (i2c->prev_msg_tx) {
+ int status;
+
+ status = xiic_wait_tx_empty(i2c);
+ if (status)
+ return;
+ }
/* Check if RSTA should be set */
cr = xiic_getreg8(i2c, XIIC_CR_REG_OFFSET);
if (cr & XIIC_CR_MSMS_MASK) {
@@ -803,6 +852,7 @@ static void xiic_start_send(struct xiic_i2c *i2c)
XIIC_INTR_TX_ERROR_MASK |
XIIC_INTR_BNB_MASK);
}
+ i2c->prev_msg_tx = true;
}
static void __xiic_start_xfer(struct xiic_i2c *i2c)
@@ -866,6 +916,9 @@ static int xiic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
/* Decide standard mode or Dynamic mode */
i2c->dynamic = true;
+ /* Initialize prev message type */
+ i2c->prev_msg_tx = false;
+
/*
* If number of messages is 1 and read length is > 255 bytes,
* enter standard mode