git: 0deaf4be346f - main - rk_i2c: emulate repeated start
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Thu, 27 Jun 2024 10:33:17 UTC
The branch main has been updated by avg: URL: https://cgit.FreeBSD.org/src/commit/?id=0deaf4be346f7f343bd2cf771bbf5d172d1c0d2a commit 0deaf4be346f7f343bd2cf771bbf5d172d1c0d2a Author: Andriy Gapon <avg@FreeBSD.org> AuthorDate: 2024-06-27 07:40:22 +0000 Commit: Andriy Gapon <avg@FreeBSD.org> CommitDate: 2024-06-27 10:32:15 +0000 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 --- sys/dev/iicbus/controller/rockchip/rk_i2c.c | 34 +++++++++++++++++++---------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/sys/dev/iicbus/controller/rockchip/rk_i2c.c b/sys/dev/iicbus/controller/rockchip/rk_i2c.c index 4a431649de49..9f2a98bcea12 100644 --- a/sys/dev/iicbus/controller/rockchip/rk_i2c.c +++ b/sys/dev/iicbus/controller/rockchip/rk_i2c.c @@ -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);