Changeset View
Changeset View
Standalone View
Standalone View
sys/arm64/rockchip/rk_i2c.c
Show First 20 Lines • Show All 285 Lines • ▼ Show 20 Lines | rk_i2c_send_stop(struct rk_i2c_softc *sc) | ||||
reg |= RK_I2C_CON_STOP; | reg |= RK_I2C_CON_STOP; | ||||
RK_I2C_WRITE(sc, RK_I2C_CON, reg); | RK_I2C_WRITE(sc, RK_I2C_CON, reg); | ||||
} | } | ||||
static void | static void | ||||
rk_i2c_intr_locked(struct rk_i2c_softc *sc) | rk_i2c_intr_locked(struct rk_i2c_softc *sc) | ||||
{ | { | ||||
uint32_t reg; | uint32_t reg; | ||||
int transfer_len; | |||||
sc->ipd = RK_I2C_READ(sc, RK_I2C_IPD); | sc->ipd = RK_I2C_READ(sc, RK_I2C_IPD); | ||||
/* Something to handle? */ | /* Something to handle? */ | ||||
if ((sc->ipd & RK_I2C_IPD_ALL) == 0) | if ((sc->ipd & RK_I2C_IPD_ALL) == 0) | ||||
return; | return; | ||||
RK_I2C_WRITE(sc, RK_I2C_IPD, sc->ipd); | RK_I2C_WRITE(sc, RK_I2C_IPD, sc->ipd); | ||||
Show All 17 Lines | case STATE_START: | ||||
RK_I2C_WRITE(sc, RK_I2C_CON, reg); | RK_I2C_WRITE(sc, RK_I2C_CON, reg); | ||||
if (sc->mode == RK_I2C_CON_MODE_RRX || | if (sc->mode == RK_I2C_CON_MODE_RRX || | ||||
sc->mode == RK_I2C_CON_MODE_RX) { | sc->mode == RK_I2C_CON_MODE_RX) { | ||||
sc->state = STATE_READ; | sc->state = STATE_READ; | ||||
RK_I2C_WRITE(sc, RK_I2C_IEN, RK_I2C_IEN_MBRFIEN | | RK_I2C_WRITE(sc, RK_I2C_IEN, RK_I2C_IEN_MBRFIEN | | ||||
RK_I2C_IEN_NAKRCVIEN); | RK_I2C_IEN_NAKRCVIEN); | ||||
if ((sc->msg->len - sc->cnt) > 32) | |||||
transfer_len = 32; | |||||
else { | |||||
transfer_len = sc->msg->len - sc->cnt; | |||||
reg = RK_I2C_READ(sc, RK_I2C_CON); | reg = RK_I2C_READ(sc, RK_I2C_CON); | ||||
reg |= RK_I2C_CON_LASTACK; | reg |= RK_I2C_CON_LASTACK; | ||||
RK_I2C_WRITE(sc, RK_I2C_CON, reg); | RK_I2C_WRITE(sc, RK_I2C_CON, reg); | ||||
} | |||||
RK_I2C_WRITE(sc, RK_I2C_MRXCNT, sc->msg->len); | RK_I2C_WRITE(sc, RK_I2C_MRXCNT, transfer_len); | ||||
} else { | } else { | ||||
sc->state = STATE_WRITE; | sc->state = STATE_WRITE; | ||||
RK_I2C_WRITE(sc, RK_I2C_IEN, RK_I2C_IEN_MBTFIEN | | RK_I2C_WRITE(sc, RK_I2C_IEN, RK_I2C_IEN_MBTFIEN | | ||||
RK_I2C_IEN_NAKRCVIEN); | RK_I2C_IEN_NAKRCVIEN); | ||||
sc->msg->len += 1; | sc->msg->len += 1; | ||||
rk_i2c_fill_tx(sc); | rk_i2c_fill_tx(sc); | ||||
RK_I2C_WRITE(sc, RK_I2C_MTXCNT, sc->msg->len); | RK_I2C_WRITE(sc, RK_I2C_MTXCNT, sc->msg->len); | ||||
} | } | ||||
break; | break; | ||||
case STATE_READ: | case STATE_READ: | ||||
rk_i2c_drain_rx(sc); | rk_i2c_drain_rx(sc); | ||||
if (sc->cnt == sc->msg->len) | if (sc->cnt == sc->msg->len) | ||||
rk_i2c_send_stop(sc); | rk_i2c_send_stop(sc); | ||||
else { | |||||
sc->mode = RK_I2C_CON_MODE_RX; | |||||
reg = RK_I2C_READ(sc, RK_I2C_CON) & \ | |||||
~RK_I2C_CON_CTRL_MASK; | |||||
reg |= sc->mode << RK_I2C_CON_MODE_SHIFT; | |||||
reg |= RK_I2C_CON_EN; | |||||
if ((sc->msg->len - sc->cnt) > 32) | |||||
transfer_len = 32; | |||||
else { | |||||
transfer_len = sc->msg->len - sc->cnt; | |||||
manu: That will not work if the transfer is not for a multiple of 32. | |||||
Done Inline Actionswhy? br: why? | |||||
Not Done Inline ActionsIf I understand correctly if you try to do a transfer with a len of 48 bytes the first 32 bytes will be transmitted first (as it's the max length that this controller can support) but on the second transfer instead of setting TXCOUNT to 16 we will set it to 32 as you check sc->msg->len and not taking into account what have been transmitted already. manu: If I understand correctly if you try to do a transfer with a len of 48 bytes the first 32 bytes… | |||||
Done Inline ActionsYou are right, thanks! br: You are right, thanks!
I think driver works for me just fine now | |||||
reg |= RK_I2C_CON_LASTACK; | |||||
} | |||||
RK_I2C_WRITE(sc, RK_I2C_CON, reg); | |||||
RK_I2C_WRITE(sc, RK_I2C_MRXCNT, transfer_len); | |||||
} | |||||
break; | break; | ||||
case STATE_WRITE: | case STATE_WRITE: | ||||
if (sc->cnt == sc->msg->len && | if (sc->cnt == sc->msg->len && | ||||
!(sc->msg->flags & IIC_M_NOSTOP)) { | !(sc->msg->flags & IIC_M_NOSTOP)) { | ||||
rk_i2c_send_stop(sc); | rk_i2c_send_stop(sc); | ||||
break; | break; | ||||
} | } | ||||
/* passthru */ | /* passthru */ | ||||
▲ Show 20 Lines • Show All 94 Lines • ▼ Show 20 Lines | rk_i2c_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs) | ||||
/* Disable the module and interrupts */ | /* Disable the module and interrupts */ | ||||
RK_I2C_WRITE(sc, RK_I2C_CON, 0); | RK_I2C_WRITE(sc, RK_I2C_CON, 0); | ||||
RK_I2C_WRITE(sc, RK_I2C_IEN, 0); | RK_I2C_WRITE(sc, RK_I2C_IEN, 0); | ||||
/* Clean stale interrupts */ | /* Clean stale interrupts */ | ||||
RK_I2C_WRITE(sc, RK_I2C_IPD, RK_I2C_IPD_ALL); | RK_I2C_WRITE(sc, RK_I2C_IPD, RK_I2C_IPD_ALL); | ||||
err = 0; | |||||
for (i = 0; i < nmsgs; i++) { | for (i = 0; i < nmsgs; i++) { | ||||
err = 0; | |||||
/* Validate parameters. */ | /* Validate parameters. */ | ||||
if (msgs == NULL || msgs[i].buf == NULL || | if (msgs == NULL || msgs[i].buf == NULL || | ||||
msgs[i].len == 0) { | msgs[i].len == 0) { | ||||
err = EINVAL; | err = EINVAL; | ||||
break; | break; | ||||
} | } | ||||
/* | /* | ||||
* If next message have NOSTART flag, then they both | * If next message have NOSTART flag, then they both | ||||
Show All 36 Lines | if (nmsgs - i >= 2 && msgs[i].len < 4 && | ||||
i++; | i++; | ||||
} else { | } else { | ||||
if (msgs[i].flags & IIC_M_RD) { | if (msgs[i].flags & IIC_M_RD) { | ||||
if (msgs[i].flags & IIC_M_NOSTART) { | if (msgs[i].flags & IIC_M_NOSTART) { | ||||
sc->mode = RK_I2C_CON_MODE_RX; | sc->mode = RK_I2C_CON_MODE_RX; | ||||
} else { | } else { | ||||
sc->mode = RK_I2C_CON_MODE_RRX; | sc->mode = RK_I2C_CON_MODE_RRX; | ||||
reg = msgs[i].slave & LSB; | reg = msgs[i].slave & ~LSB; | ||||
Not Done Inline ActionsMhm, that should be | LSB I think. manu: Mhm, that should be | LSB I think. | |||||
Done Inline Actionsyes, but does not matter, since controller sets this bit internally depending on mode br: yes, but does not matter, since controller sets this bit internally depending on mode | |||||
reg |= RK_I2C_MRXADDR_VALID(0); | reg |= RK_I2C_MRXADDR_VALID(0); | ||||
RK_I2C_WRITE(sc, RK_I2C_MRXADDR, reg); | RK_I2C_WRITE(sc, RK_I2C_MRXADDR, reg); | ||||
RK_I2C_WRITE(sc, RK_I2C_MRXRADDR, 0); | RK_I2C_WRITE(sc, RK_I2C_MRXRADDR, 0); | ||||
} | } | ||||
} else { | } else { | ||||
sc->mode = RK_I2C_CON_MODE_TX; | sc->mode = RK_I2C_CON_MODE_TX; | ||||
} | } | ||||
} | } | ||||
▲ Show 20 Lines • Show All 180 Lines • Show Last 20 Lines |
That will not work if the transfer is not for a multiple of 32.