From 9be1cd865392bba1095ce22dbc1928f8c6e9f59e Mon Sep 17 00:00:00 2001 From: David Wu Date: Fri, 3 Jul 2020 11:35:01 +0800 Subject: [PATCH] i2c: rk3x: Remove start state and irq Let configuration start and count be performed at the same time as much as possible, which can reduce the interval between the start signal and the data signal, and can also reduce a start irq. Signed-off-by: David Wu Change-Id: I529300a083dcd264cc5f25a2069b88601cade83e --- drivers/i2c/busses/i2c-rk3x.c | 66 +++++++++++++++-------------------- 1 file changed, 29 insertions(+), 37 deletions(-) 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;