rk_i2c: emulate repeated start

rk_i2c_send_stop is modified so that it sends a stop condition, like it
always did, if there is no IIC_M_NOSTOP flag.
But if the flag is set then the function completely resets the control
register and sets the driver state to transfer completed.
Something like this was previously done for a write with IIC_M_NOSTOP.
Now it is done for a read with IIC_M_NOSTOP as well.

Linux code says that the hardware does not support the repeated start
condition and the documentation, indeed, does not mention it.
But according to the Linux driver clearing the control register and then
sending a start condition acts as if it were a repeated start.

While here, add braces around a single-line 'if' branch to balance it
with a multi-line 'else' branch.

Tested with max44009(4).

MFC after:	2 weeks
This commit is contained in:
Andriy Gapon 2024-06-27 10:40:22 +03:00
parent cde6642431
commit 0deaf4be34

View file

@ -281,13 +281,26 @@ rk_i2c_send_stop(struct rk_i2c_softc *sc)
{
uint32_t reg;
RK_I2C_WRITE(sc, RK_I2C_IEN, RK_I2C_IEN_STOPIEN);
if (!(sc->msg->flags & IIC_M_NOSTOP)) {
RK_I2C_WRITE(sc, RK_I2C_IEN, RK_I2C_IEN_STOPIEN);
sc->state = STATE_STOP;
sc->state = STATE_STOP;
reg = RK_I2C_READ(sc, RK_I2C_CON);
reg |= RK_I2C_CON_STOP;
RK_I2C_WRITE(sc, RK_I2C_CON, reg);
reg = RK_I2C_READ(sc, RK_I2C_CON);
reg |= RK_I2C_CON_STOP;
RK_I2C_WRITE(sc, RK_I2C_CON, reg);
} else {
/*
* Do not actually set stop bit, set up conditions to
* emulate repeated start by clearing all state.
*/
sc->state = STATE_IDLE;
sc->transfer_done = 1;
reg = RK_I2C_READ(sc, RK_I2C_CON);
reg &= ~RK_I2C_CON_CTRL_MASK;
RK_I2C_WRITE(sc, RK_I2C_CON, reg);
}
}
static void
@ -350,9 +363,9 @@ rk_i2c_intr_locked(struct rk_i2c_softc *sc)
case STATE_READ:
rk_i2c_drain_rx(sc);
if (sc->cnt == sc->msg->len)
if (sc->cnt == sc->msg->len) {
rk_i2c_send_stop(sc);
else {
} else {
sc->mode = RK_I2C_CON_MODE_RX;
reg = RK_I2C_READ(sc, RK_I2C_CON) & \
~RK_I2C_CON_CTRL_MASK;
@ -369,7 +382,6 @@ rk_i2c_intr_locked(struct rk_i2c_softc *sc)
RK_I2C_WRITE(sc, RK_I2C_CON, reg);
RK_I2C_WRITE(sc, RK_I2C_MRXCNT, transfer_len);
}
break;
case STATE_WRITE:
if (sc->cnt < sc->msg->len) {
@ -378,12 +390,10 @@ rk_i2c_intr_locked(struct rk_i2c_softc *sc)
RK_I2C_IEN_NAKRCVIEN);
transfer_len = rk_i2c_fill_tx(sc);
RK_I2C_WRITE(sc, RK_I2C_MTXCNT, transfer_len);
break;
} else if (!(sc->msg->flags & IIC_M_NOSTOP)) {
} else {
rk_i2c_send_stop(sc);
break;
}
/* passthru */
break;
case STATE_STOP:
/* Disable stop bit */
reg = RK_I2C_READ(sc, RK_I2C_CON);