Index: src/sys/dev/ic/pcf8584.c =================================================================== RCS file: /cvsroot/src/sys/dev/ic/pcf8584.c,v retrieving revision 1.23 diff -u -r1.23 pcf8584.c --- src/sys/dev/ic/pcf8584.c 1 Feb 2026 10:50:23 -0000 1.23 +++ src/sys/dev/ic/pcf8584.c 22 Jul 2026 08:00:53 -0000 @@ -20,7 +20,9 @@ #include #include #include +#include #include +#include #include #include @@ -45,15 +47,16 @@ size_t, void *, size_t, int); int pcfiic_xmit(struct pcfiic_softc *, u_int8_t, const u_int8_t *, - size_t, const u_int8_t *, size_t, int); + size_t, const u_int8_t *, size_t, int, int); int pcfiic_recv(struct pcfiic_softc *, u_int8_t, u_int8_t *, - size_t, int); + size_t, int, int); u_int8_t pcfiic_read(struct pcfiic_softc *, bus_size_t); void pcfiic_write(struct pcfiic_softc *, bus_size_t, u_int8_t); void pcfiic_choose_bus(struct pcfiic_softc *, u_int8_t); int pcfiic_wait_BBN(struct pcfiic_softc *); -int pcfiic_wait_pin(struct pcfiic_softc *, volatile u_int8_t *); +int pcfiic_wait_pin(struct pcfiic_softc *, volatile u_int8_t *, + int); void pcfiic_init(struct pcfiic_softc *sc) @@ -99,13 +102,40 @@ sc->sc_i2c.ic_cookie = sc; sc->sc_i2c.ic_exec = pcfiic_i2c_exec; + if (sc->sc_poll == true) + printf(": polling"); + + mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_VM); + cv_init(&sc->sc_cv, "pcfiic"); + iicbus_attach(sc->sc_dev, &sc->sc_i2c); } int pcfiic_intr(void *arg) { - return (0); + struct pcfiic_softc *sc = arg; + u_int8_t s1; + + if (!sc->sc_running) + /* Not for us. */ + return (0); + + s1 = pcfiic_read(sc, PCF8584_S1); + if ((s1 & PCF8584_STATUS_PIN) != 0) { + /* Sometimes happens, so ignore it. + printf("%s: intr +PIN (0x%02x)\n", + device_xname(sc->sc_dev), s1); + */ + return (0); + } + + mutex_enter(&sc->sc_mutex); + sc->sc_intr_rcvd = 1; + cv_signal(&sc->sc_cv); + mutex_exit(&sc->sc_mutex); + + return (1); } int @@ -126,6 +156,8 @@ if (sc->sc_master) pcfiic_choose_bus(sc, addr >> 7); + sc->sc_running = 1; + /* * If we are writing, write address, cmdbuf, buf. * If we are reading, either: @@ -134,38 +166,50 @@ */ if (I2C_OP_WRITE_P(op)) { ret = pcfiic_xmit(sc, addr & 0x7f, cmdbuf, cmdlen, - buf, len, 0); + buf, len, 0, flags); } else { if(cmdlen > 0) { if (pcfiic_xmit(sc, addr & 0x7f, cmdbuf, cmdlen, - NULL, 0, REPEAT_START) != 0) + NULL, 0, REPEAT_START, flags) != 0) { + sc->sc_running = 0; return (1); + } ret = pcfiic_recv(sc, addr & 0x7f, buf, len, - REPEAT_START); + REPEAT_START, flags); } else ret = pcfiic_recv(sc, addr & 0x7f, buf, len, - 0); + 0, flags); } + sc->sc_running = 0; return (ret); } int pcfiic_xmit(struct pcfiic_softc *sc, u_int8_t addr, const u_int8_t *cmdbuf, - size_t cmdlen, const u_int8_t *buf, size_t len, int flags) + size_t cmdlen, const u_int8_t *buf, size_t len, int rs, int flags) { int i; + u_int8_t intr; volatile u_int8_t r; + if (flags & I2C_F_POLL) + intr = 0; + else + intr = PCF8584_CTRL_ENI; + if (pcfiic_wait_BBN(sc) != 0) { printf("%s: transmit failed (BBN)\n", device_xname(sc->sc_dev)); return (1); } + mutex_enter(&sc->sc_mutex); + sc->sc_intr_rcvd = 0; + mutex_exit(&sc->sc_mutex); pcfiic_write(sc, PCF8584_S0, addr << 1); - pcfiic_write(sc, PCF8584_S1, PCF8584_CMD_START); + pcfiic_write(sc, PCF8584_S1, PCF8584_CMD_START | intr); for (i = 0; i <= cmdlen + len; i++) { - if (pcfiic_wait_pin(sc, &r) != 0) { + if (pcfiic_wait_pin(sc, &r, flags) != 0) { pcfiic_write(sc, PCF8584_S1, PCF8584_CMD_STOP); printf("%s: transmit failed at %d (PIN)\n", device_xname(sc->sc_dev), i); @@ -177,38 +221,50 @@ return (1); } + mutex_enter(&sc->sc_mutex); + sc->sc_intr_rcvd = 0; + mutex_exit(&sc->sc_mutex); if (i < cmdlen) pcfiic_write(sc, PCF8584_S0, cmdbuf[i]); else if (i < cmdlen + len) pcfiic_write(sc, PCF8584_S0, buf[i - cmdlen]); } - if (flags != REPEAT_START) + if (rs != REPEAT_START) pcfiic_write(sc, PCF8584_S1, PCF8584_CMD_STOP); return (0); } int pcfiic_recv(struct pcfiic_softc *sc, u_int8_t addr, u_int8_t *buf, size_t len, - int flags) + int rs, int flags) { int i = 0, err = 0; + u_int8_t intr; volatile u_int8_t r; - if (flags != REPEAT_START) { + if (flags & I2C_F_POLL) + intr = 0; + else + intr = PCF8584_CTRL_ENI; + + mutex_enter(&sc->sc_mutex); + sc->sc_intr_rcvd = 0; + mutex_exit(&sc->sc_mutex); + if (rs != REPEAT_START) { if (pcfiic_wait_BBN(sc) != 0) { printf("%s: receive failed (BBN)\n", device_xname(sc->sc_dev)); return (1); } pcfiic_write(sc, PCF8584_S0, (addr << 1) | 0x01); - pcfiic_write(sc, PCF8584_S1, PCF8584_CMD_START); + pcfiic_write(sc, PCF8584_S1, PCF8584_CMD_START | intr); } else { - pcfiic_write(sc, PCF8584_S1, PCF8584_CMD_REPSTART); + pcfiic_write(sc, PCF8584_S1, PCF8584_CMD_REPSTART | intr); pcfiic_write(sc, PCF8584_S0, (addr << 1) | 0x01); } for (i = 0; i <= len; i++) { - if (pcfiic_wait_pin(sc, &r) != 0) { + if (pcfiic_wait_pin(sc, &r, flags) != 0) { pcfiic_write(sc, PCF8584_S1, PCF8584_CMD_STOP); printf("%s: receive failed at %d (PIN)\n", device_xname(sc->sc_dev), i); @@ -222,7 +278,10 @@ } if (i == len - 1) { - pcfiic_write(sc, PCF8584_S1, PCF8584_CMD_NAK); + mutex_enter(&sc->sc_mutex); + sc->sc_intr_rcvd = 0; + mutex_exit(&sc->sc_mutex); + pcfiic_write(sc, PCF8584_S1, PCF8584_CMD_NAK | intr); } else if (i == len) { pcfiic_write(sc, PCF8584_S1, PCF8584_CMD_STOP); } @@ -282,15 +341,37 @@ } int -pcfiic_wait_pin(struct pcfiic_softc *sc, volatile u_int8_t *r) +pcfiic_wait_pin(struct pcfiic_softc *sc, volatile u_int8_t *r, int flags) { int i; + unsigned deadline, rem; - for (i = 0; i < 1000; i++) { - *r = pcfiic_read(sc, PCF8584_S1); - if ((*r & PCF8584_STATUS_PIN) == 0) - return (0); - delay(1000); + if (flags & I2C_F_POLL) { + for (i = 0; i < 1000; i++) { + *r = pcfiic_read(sc, PCF8584_S1); + if ((*r & PCF8584_STATUS_PIN) == 0) + return (0); + delay(1000); + } + return (1); + } else { + deadline = getticks() + /*timeout*/ hz; + mutex_enter(&sc->sc_mutex); + while (((*r = pcfiic_read(sc, PCF8584_S1)) & PCF8584_STATUS_PIN) != 0) { + /* Interrupt arrived before we started to wait */ + if (sc->sc_intr_rcvd) { + mutex_exit(&sc->sc_mutex); + return (0); + } + if ((rem = deadline - getticks()) >= INT_MAX) + { + mutex_exit(&sc->sc_mutex); + return (1); + } + cv_timedwait(&sc->sc_cv, &sc->sc_mutex, rem); + } + /* PCF8584_STATUS_PIN == 0 */ + mutex_exit(&sc->sc_mutex); + return (0); } - return (1); } Index: src/sys/dev/ic/pcf8584var.h =================================================================== RCS file: /cvsroot/src/sys/dev/ic/pcf8584var.h,v retrieving revision 1.7 diff -u -r1.7 pcf8584var.h --- src/sys/dev/ic/pcf8584var.h 1 Feb 2026 10:50:23 -0000 1.7 +++ src/sys/dev/ic/pcf8584var.h 22 Jul 2026 08:00:53 -0000 @@ -21,17 +21,22 @@ device_t sc_dev; bus_space_tag_t sc_iot; - bus_space_handle_t sc_ioh; - bus_space_handle_t sc_ioh2; - int sc_master; - u_int8_t sc_addr; - u_int8_t sc_clock; + bus_space_handle_t sc_ioh; /* Handle for bus 1 */ + bus_space_handle_t sc_ioh2; /* Handle for bus 2 */ + int sc_master; /* We have 2 buses */ + u_int8_t sc_addr; /* Our address */ + u_int8_t sc_clock; /* Our clock settings */ u_int8_t sc_regmap[2]; - int sc_poll; - int sc_delay; + int sc_poll; /* Poll only (no intr) */ + int sc_delay; /* HW needs R, W delay */ + int sc_running; /* Exec is running */ struct i2c_controller sc_i2c; + + int sc_intr_rcvd; /* Interrupt received */ + kmutex_t sc_mutex; /* Interrupt mutex ... */ + kcondvar_t sc_cv; /* ... and condvar */ }; void pcfiic_attach(struct pcfiic_softc *, i2c_addr_t, u_int8_t, int);