Skip to content

Commit

Permalink
twsi: fix support for a transfer where a write is followed by a write
Browse files Browse the repository at this point in the history
... and the first write has no-stop flag while the next write has no-start
flag.

In this case we do not need to send any stop or start or repeated start.
We can just keep writing bytes. Anything else confuses the target device.
Such a transfer can be created by i2c tool, e.g., for an EEPROM write at
specific offset:
    i2c -m tr -a 0x50 -d w -w 16 -o 0 -c 8 -v < /dev/random
    i2c -m tr -a 0x50 -d r -w 16 -o 0 -c 16 -v
  • Loading branch information
avg-I committed Sep 23, 2021
1 parent 1c6777d commit 35f3195
Showing 1 changed file with 15 additions and 2 deletions.
17 changes: 15 additions & 2 deletions sys/dev/iicbus/twsi/twsi.c
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,7 @@ twsi_intr(void *arg)
struct twsi_softc *sc;
uint32_t status;
int transfer_done = 0;
int send_byte = 0;

sc = arg;

Expand Down Expand Up @@ -601,25 +602,37 @@ twsi_intr(void *arg)
debugf(sc->dev, "Ack received after transmitting data\n");
if (sc->sent_bytes == sc->msgs[sc->msg_idx].len) {
debugf(sc->dev, "Done sending all the bytes for msg %d\n", sc->msg_idx);
send_byte = 0;

/* Send stop, no interrupts on stop */
if (!(sc->msgs[sc->msg_idx].flags & IIC_M_NOSTOP)) {
debugf(sc->dev, "Done TX data, send stop\n");
TWSI_WRITE(sc, sc->reg_control,
sc->control_val | TWSI_CONTROL_STOP);
} else {
debugf(sc->dev, "Done TX data with NO_STOP\n");
TWSI_WRITE(sc, sc->reg_control, sc->control_val | TWSI_CONTROL_START);
}
sc->msg_idx++;
if (sc->msg_idx == sc->nmsgs) {
debugf(sc->dev, "transfer_done=1\n");
transfer_done = 1;
sc->error = 0;
} else {
} else if (!(sc->msgs[sc->msg_idx].flags & IIC_M_NOSTART)) {
debugf(sc->dev, "Send repeated start\n");
TWSI_WRITE(sc, sc->reg_control, sc->control_val | TWSI_CONTROL_START);
} else {
/* Just keep sending data. */
KASSERT((sc->msgs[sc->msg_idx].flags & IIC_M_RD) == 0,
("read with nostart after write with nostop"));
debugf(sc->dev, "write followed by write\n");
sc->sent_bytes = 0;
send_byte = 1;
}
} else {
send_byte = 1;
}

if (send_byte) {
debugf(sc->dev, "Sending byte %d (of %d) = %x\n",
sc->sent_bytes,
sc->msgs[sc->msg_idx].len,
Expand Down

0 comments on commit 35f3195

Please sign in to comment.