aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/iicbus/controller/rockchip/rk_i2c.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/iicbus/controller/rockchip/rk_i2c.c')
-rw-r--r--sys/dev/iicbus/controller/rockchip/rk_i2c.c44
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)