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 <sys/param.h>
 #include <sys/systm.h>
 #include <sys/device.h>
+#include <sys/intr.h>
 #include <sys/kernel.h>
+#include <sys/mutex.h>
 #include <sys/proc.h>
 #include <sys/bus.h>
 
@@ -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);
