Skip to content

Commit

Permalink
rk_i2c_fill_tx: fix a number of issues
Browse files Browse the repository at this point in the history
- maximum number of bytes that can be sent is 32, not 8;
- previous interface required callers to bump sc->msg->len in addition
  to setting sc->tx_slave_addr;
- because of the above there was an issue with writing one too many bytes
  because sc->cnt is not advanced when the slave address is written;
- the inetraction between outer and inner loops was confusing as the former
  was bounded on the number of bytes to write and the counter was
  incremented by one, but the inner loop advanced four bytes at a time;
- the return value was incorrect in the tx_slave_addr case; one call place
  had to use its own (and incorrect in some cases) notion of the write
  lenth.

All of the above issues should be fixed.
Some sanity asserts are added.
All callers use the return value to program RK_I2C_MTXCNT.
iic_msg::len no longer needs to be hacked.
A constant is added to reflect the maximum number of octets that can be
sent or received in one go (they are the same).

(cherry picked from commit c663545)
(cherry picked from commit b7bcd21)
  • Loading branch information
avg-I committed Dec 22, 2021
1 parent 94427ab commit f074373
Showing 1 changed file with 26 additions and 20 deletions.
46 changes: 26 additions & 20 deletions sys/arm64/rockchip/rk_i2c.c
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,9 @@ __FBSDID("$FreeBSD$");

#define RK_I2C_RXDATA_BASE 0x200

/* 8 data registers, 4 bytes each. */
#define RK_I2C_MAX_RXTX_LEN 32

enum rk_i2c_state {
STATE_IDLE = 0,
STATE_START,
Expand Down Expand Up @@ -214,36 +217,40 @@ rk_i2c_fill_tx(struct rk_i2c_softc *sc)
uint8_t buf;
int i, j, len;

if (sc->msg == NULL || sc->msg->len == sc->cnt)
return (0);

len = sc->msg->len - sc->cnt;
if (len > 8)
len = 8;
if (sc->tx_slave_addr) {
KASSERT(sc->cnt == 0, ("tx_slave_addr in the middle of data"));
len++;
}

for (i = 0; i < len; i++) {
if (len > RK_I2C_MAX_RXTX_LEN)
len = RK_I2C_MAX_RXTX_LEN;

for (i = 0; i < len; ) {
buf32 = 0;
for (j = 0; j < 4 ; j++) {
if (sc->cnt == sc->msg->len)
break;

/* Process next 4 bytes or whatever remains. */
for (j = 0; j < MIN(len - i, 4); j++) {
/* Fill the addr if needed */
if (sc->cnt == 0 && sc->tx_slave_addr) {
if (sc->tx_slave_addr) {
buf = sc->msg->slave;
sc->tx_slave_addr = false;
} else {
KASSERT(sc->cnt < sc->msg->len,
("%s: data buffer overrun", __func__));
buf = sc->msg->buf[sc->cnt];
sc->cnt++;
}
buf32 |= buf << (j * 8);
buf32 |= (uint32_t)buf << (j * 8);
}
RK_I2C_WRITE(sc, RK_I2C_TXDATA_BASE + 4 * i, buf32);

if (sc->cnt == sc->msg->len)
break;
KASSERT(i % 4 == 0, ("%s: misaligned write offset", __func__));
RK_I2C_WRITE(sc, RK_I2C_TXDATA_BASE + i, buf32);

i += j;
}

return (uint8_t)len;
return (len);
}

static void
Expand All @@ -260,8 +267,8 @@ rk_i2c_drain_rx(struct rk_i2c_softc *sc)
}

len = sc->msg->len - sc->cnt;
if (len > 32)
len = 32;
if (len > RK_I2C_MAX_RXTX_LEN)
len = RK_I2C_MAX_RXTX_LEN;

for (i = 0; i < len; i++) {
if (i % 4 == 0)
Expand Down Expand Up @@ -333,9 +340,8 @@ rk_i2c_intr_locked(struct rk_i2c_softc *sc)
RK_I2C_WRITE(sc, RK_I2C_IEN, RK_I2C_IEN_MBTFIEN |
RK_I2C_IEN_NAKRCVIEN);

sc->msg->len += 1;
rk_i2c_fill_tx(sc);
RK_I2C_WRITE(sc, RK_I2C_MTXCNT, sc->msg->len);
transfer_len = rk_i2c_fill_tx(sc);
RK_I2C_WRITE(sc, RK_I2C_MTXCNT, transfer_len);
}
break;
case STATE_READ:
Expand Down

0 comments on commit f074373

Please sign in to comment.