aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndriy Gapon <avg@FreeBSD.org>2021-11-26 07:44:30 +0000
committerAndriy Gapon <avg@FreeBSD.org>2021-12-10 12:30:58 +0000
commit3507728e59ab64f109e7495311f38549b007706b (patch)
treeb7fcc7f158f4426b32f9ce29ba3d2ee85899b524
parent035813ba15545b7d77429427823d2fb603d83a23 (diff)
twsi: unify error handling, explicitly handle more conditions
twsi_error() is a new function that stops the current transfer and sets up softc when an error condition is detected. TWSI_STATUS_DATA_WR_NACK, TWSI_STATUS_BUS_ERROR and TWSI_STATUS_ARBITRATION_LOST are now handled explicitly rather than via the catch-all unknown status. Also, twsi_intr() now calls wakeup() in a single place when the transfer is finished. (cherry picked from commit a4fe8922085dfc1e5e6a6bac73ccc738e373165f)
-rw-r--r--sys/dev/iicbus/twsi/twsi.c46
1 files changed, 32 insertions, 14 deletions
diff --git a/sys/dev/iicbus/twsi/twsi.c b/sys/dev/iicbus/twsi/twsi.c
index 384e19e120b9..ecadfade04d9 100644
--- a/sys/dev/iicbus/twsi/twsi.c
+++ b/sys/dev/iicbus/twsi/twsi.c
@@ -544,6 +544,19 @@ twsi_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs)
}
static void
+twsi_error(struct twsi_softc *sc, int err)
+{
+ /*
+ * Must send stop condition to abort the current transfer.
+ */
+ debugf(sc, "Sending STOP condition for error %d\n", err);
+ sc->transfer = 0;
+ sc->error = err;
+ sc->control_val = 0;
+ TWSI_WRITE(sc, sc->reg_control, sc->control_val | TWSI_CONTROL_STOP);
+}
+
+static void
twsi_intr(void *arg)
{
struct twsi_softc *sc;
@@ -604,13 +617,13 @@ twsi_intr(void *arg)
case TWSI_STATUS_ADDR_W_NACK:
case TWSI_STATUS_ADDR_R_NACK:
- debugf(sc, "No ack received after transmitting the address\n");
- sc->transfer = 0;
- sc->error = IIC_ENOACK;
- sc->control_val = 0;
- wakeup(sc);
+ debugf(sc, "Address NACK-ed\n");
+ twsi_error(sc, IIC_ENOACK);
+ break;
+ case TWSI_STATUS_DATA_WR_NACK:
+ debugf(sc, "Data byte NACK-ed\n");
+ twsi_error(sc, IIC_ENOACK);
break;
-
case TWSI_STATUS_DATA_WR_ACK:
debugf(sc, "Ack received after transmitting data\n");
if (sc->sent_bytes == sc->msgs[sc->msg_idx].len) {
@@ -684,12 +697,17 @@ twsi_intr(void *arg)
sc->error = 0;
break;
+ case TWSI_STATUS_BUS_ERROR:
+ debugf(sc, "Bus error\n");
+ twsi_error(sc, IIC_EBUSERR);
+ break;
+ case TWSI_STATUS_ARBITRATION_LOST:
+ debugf(sc, "Arbitration lost\n");
+ twsi_error(sc, IIC_EBUSBSY);
+ break;
default:
- debugf(sc, "status=%x hot handled\n", status);
- sc->transfer = 0;
- sc->error = IIC_EBUSERR;
- sc->control_val = 0;
- wakeup(sc);
+ debugf(sc, "unexpected status 0x%x\n", status);
+ twsi_error(sc, IIC_ESTATUS);
break;
}
debugf(sc, "Refresh reg_control\n");
@@ -701,11 +719,11 @@ end:
TWSI_WRITE(sc, sc->reg_control, sc->control_val |
(sc->iflag_w1c ? TWSI_CONTROL_IFLG : 0));
- debugf(sc, "Done with interrupts\n\n");
- if (transfer_done == 1) {
+ if (transfer_done == 1)
sc->transfer = 0;
+ debugf(sc, "Done with interrupt, transfer = %d\n", sc->transfer);
+ if (sc->transfer == 0)
wakeup(sc);
- }
mtx_unlock(&sc->mutex);
}