diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c index 9fcb2d81ea49..c7c8d2f0abe7 100644 --- a/drivers/i2c/busses/i2c-rk3x.c +++ b/drivers/i2c/busses/i2c-rk3x.c @@ -157,7 +157,6 @@ struct rk3x_i2c_calced_timings { enum rk3x_i2c_state { STATE_IDLE, - STATE_START, STATE_READ, STATE_WRITE, STATE_STOP @@ -232,6 +231,9 @@ struct rk3x_i2c { bool system_restarting; }; +static void rk3x_i2c_prepare_read(struct rk3x_i2c *i2c); +static int rk3x_i2c_fill_transmit_buf(struct rk3x_i2c *i2c, bool sended); + static inline void rk3x_i2c_wake_up(struct rk3x_i2c *i2c) { if (!i2c->system_restarting) @@ -273,8 +275,18 @@ static inline void rk3x_i2c_disable(struct rk3x_i2c *i2c) static void rk3x_i2c_start(struct rk3x_i2c *i2c) { u32 val = i2c_readl(i2c, REG_CON) & REG_CON_TUNING_MASK; + int length = 0; - i2c_writel(i2c, REG_INT_START, REG_IEN); + /* enable appropriate interrupts */ + if (i2c->mode == REG_CON_MOD_TX) { + i2c_writel(i2c, REG_INT_MBTF | REG_INT_NAKRCV, REG_IEN); + i2c->state = STATE_WRITE; + length = rk3x_i2c_fill_transmit_buf(i2c, false); + } else { + /* in any other case, we are going to be reading. */ + i2c_writel(i2c, REG_INT_MBRF | REG_INT_NAKRCV, REG_IEN); + i2c->state = STATE_READ; + } /* enable adapter with correct mode, send START condition */ val |= REG_CON_EN | REG_CON_MOD(i2c->mode) | REG_CON_START; @@ -284,6 +296,12 @@ static void rk3x_i2c_start(struct rk3x_i2c *i2c) val |= REG_CON_ACTACK; i2c_writel(i2c, val, REG_CON); + + /* enable transition */ + if (i2c->mode == REG_CON_MOD_TX) + i2c_writel(i2c, length, REG_MTXCNT); + else + rk3x_i2c_prepare_read(i2c); } /** @@ -307,6 +325,7 @@ static void rk3x_i2c_stop(struct rk3x_i2c *i2c, int error) ctrl = i2c_readl(i2c, REG_CON); ctrl |= REG_CON_STOP; + ctrl &= ~REG_CON_START; i2c_writel(i2c, ctrl, REG_CON); } else { /* Signal rk3x_i2c_xfer to start the next message. */ @@ -351,6 +370,8 @@ static void rk3x_i2c_prepare_read(struct rk3x_i2c *i2c) if (i2c->processed != 0) { con &= ~REG_CON_MOD_MASK; con |= REG_CON_MOD(REG_CON_MOD_RX); + if (con & REG_CON_START) + con &= ~REG_CON_START; } i2c_writel(i2c, con, REG_CON); @@ -360,7 +381,7 @@ static void rk3x_i2c_prepare_read(struct rk3x_i2c *i2c) /** * Fill the transmit buffer with data from i2c->msg */ -static void rk3x_i2c_fill_transmit_buf(struct rk3x_i2c *i2c) +static int rk3x_i2c_fill_transmit_buf(struct rk3x_i2c *i2c, bool sendend) { unsigned int i, j; u32 cnt = 0; @@ -388,40 +409,15 @@ static void rk3x_i2c_fill_transmit_buf(struct rk3x_i2c *i2c) break; } - i2c_writel(i2c, cnt, REG_MTXCNT); + if (sendend) + i2c_writel(i2c, cnt, REG_MTXCNT); + + return cnt; } /* IRQ handlers for individual states */ -static void rk3x_i2c_handle_start(struct rk3x_i2c *i2c, unsigned int ipd) -{ - if (!(ipd & REG_INT_START)) { - rk3x_i2c_stop(i2c, -EIO); - dev_warn(i2c->dev, "unexpected irq in START: 0x%x\n", ipd); - rk3x_i2c_clean_ipd(i2c); - return; - } - - /* ack interrupt */ - i2c_writel(i2c, REG_INT_START, REG_IPD); - - /* disable start bit */ - i2c_writel(i2c, i2c_readl(i2c, REG_CON) & ~REG_CON_START, REG_CON); - - /* enable appropriate interrupts and transition */ - if (i2c->mode == REG_CON_MOD_TX) { - i2c_writel(i2c, REG_INT_MBTF | REG_INT_NAKRCV, REG_IEN); - i2c->state = STATE_WRITE; - rk3x_i2c_fill_transmit_buf(i2c); - } else { - /* in any other case, we are going to be reading. */ - i2c_writel(i2c, REG_INT_MBRF | REG_INT_NAKRCV, REG_IEN); - i2c->state = STATE_READ; - rk3x_i2c_prepare_read(i2c); - } -} - static void rk3x_i2c_handle_write(struct rk3x_i2c *i2c, unsigned int ipd) { if (!(ipd & REG_INT_MBTF)) { @@ -438,7 +434,7 @@ static void rk3x_i2c_handle_write(struct rk3x_i2c *i2c, unsigned int ipd) if (i2c->processed == i2c->msg->len) rk3x_i2c_stop(i2c, i2c->error); else - rk3x_i2c_fill_transmit_buf(i2c); + rk3x_i2c_fill_transmit_buf(i2c, true); } static void rk3x_i2c_handle_read(struct rk3x_i2c *i2c, unsigned int ipd) @@ -543,9 +539,6 @@ static irqreturn_t rk3x_i2c_irq(int irqno, void *dev_id) goto out; switch (i2c->state) { - case STATE_START: - rk3x_i2c_handle_start(i2c, ipd); - break; case STATE_WRITE: rk3x_i2c_handle_write(i2c, ipd); break; @@ -1065,7 +1058,6 @@ static int rk3x_i2c_setup(struct rk3x_i2c *i2c, struct i2c_msg *msgs, int num) i2c->addr = msgs[0].addr; i2c->busy = true; - i2c->state = STATE_START; i2c->processed = 0; i2c->error = 0;