diff options
Diffstat (limited to 'sys/dev/iicbus/controller/rockchip/rk_i2c.c')
-rw-r--r-- | sys/dev/iicbus/controller/rockchip/rk_i2c.c | 44 |
1 files changed, 25 insertions, 19 deletions
diff --git a/sys/dev/iicbus/controller/rockchip/rk_i2c.c b/sys/dev/iicbus/controller/rockchip/rk_i2c.c index 4a431649de49..9317adbcfd98 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); @@ -515,7 +525,7 @@ rk_i2c_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs) if (nmsgs - i >= 2 && msgs[i].len < 4 && msgs[i].flags == (IIC_M_WR | IIC_M_NOSTOP) && - msgs[i + 1].flags == IIC_M_RD && + (msgs[i + 1].flags & IIC_M_RD) == IIC_M_RD && (msgs[i].slave & ~LSB) == (msgs[i + 1].slave & ~LSB)) { sc->mode = RK_I2C_CON_MODE_RRX; @@ -648,14 +658,14 @@ rk_i2c_attach(device_t dev) } } - sc->iicbus = device_add_child(dev, "iicbus", -1); + sc->iicbus = device_add_child(dev, "iicbus", DEVICE_UNIT_ANY); if (sc->iicbus == NULL) { device_printf(dev, "cannot add iicbus child device\n"); error = ENXIO; goto fail; } - bus_generic_attach(dev); + bus_attach_children(dev); return (0); @@ -676,10 +686,6 @@ rk_i2c_detach(device_t dev) if ((error = bus_generic_detach(dev)) != 0) return (error); - if (sc->iicbus != NULL) - if ((error = device_delete_child(dev, sc->iicbus)) != 0) - return (error); - if (sc->sclk != NULL) clk_release(sc->sclk); if (sc->pclk != NULL) |