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 <david.wu@rock-chips.com>
Change-Id: I529300a083dcd264cc5f25a2069b88601cade83e
This commit is contained in:
David Wu
2020-07-03 11:35:01 +08:00
committed by Tao Huang
parent 87bf929a47
commit 9be1cd8653

View File

@@ -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;