tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[PATCH] i2c bus acquire / release cleanup, forbid i2c access in hard interrupt context



The i2c subsystem has a mechanism by which drivers for i2c-connected devices "acquire" and "release" the i2c bus for their own exclusive access while performing a set of operations.  Historically, it has been the responsibility of the back-end controller drivers to implement this mechanism, which generally speaking, has been implemented as a simple mutex.

This has worked out fine, for the most part, but but one of the features of the i2c subsystem is that a driver that's using it can request that the operation run in a "polled" mode, which has historically meant "don't sleep, busy wait for completions, don't use interrupts".

Unfortunately, the way this "polled" mode was implemented in some back-end drivers' acquire / release functions was wildly inconsistent, and in some cases, just plain broken.  During my audit, I found instances where drivers just didn't bother with the mutex at all... some would "trylock" ... some would busy-loop around a "trylock".

In sort, it was kind of a hot mess.

In one case (the "ihid" hid-over-i2c driver), a driver used "polled" mode in order to perform i2c bus access from a hard interrupt context.  When combined with some of the mistakes noted above, you've got recipe for deadlocks.

My solution to this is two-fold:

1- Fix the hid-over-i2c driver to not perform i2c access in hard interrupt context.  That required some additional capabilities from the ACPI interrupt API, which is chronicled here (note there are still some messages on that thread that are not on the web archive yet at the time I write this email, but they should land soon):

	http://mail-index.netbsd.org/port-i386/2019/08/08/msg003804.html
	(cross-posted to port-amd64 and port-i386)

2- Centralize the logic for bus acquire / release.  This is now all performed in iic_acquire_bus() and iic_release_bus().  The I2C_F_POLL case is handled with a "trylock" operation, and EBUSY is returned if that fails.  The rationale is that basically NO ONE should be using polled mode.  It is used automatically by the i2c subsystem when the system is "cold", and honestly, I doubt anyone will be able to convince me that any other use of I2C_F_POLL is legitimate.  The acquire / release hooks for the back-end drivers remain in case they need to power on the controller or something like that, but the hook is now entirely optional just for those cases.

Access to i2c bus in hard interrupt context is now forbidden.  Allowing it makes synchronization much harder and more expensive, and it's not something that can safely be done with all i2c controller back-ends (e.g. the type that might share registers with another type of device on the system).

The end result -- there is a bunch of redundant (and incorrect) code that simply gets deleted.  And every driver has consistent behavior.

Patch attached.  I've *at least* compile-tested these changes just about everywhere, and I have done pretty thorough testing of the MI i2c portions on a Raspberry Pi (where I also took the opportunity to rewrite the driver for the bcm2835 i2c controller to work as an interrupt-driven state machine rather than busy-waiting everywhere, which improved system responsiveness when transferring lots of data over i2c on a single-cpu Pi).  I also found some bugs in the Exynos and Tegra i2c controller drivers, but I don't have the hardware to test my fixes for those.

diff --git a/sys/arch/alpha/pci/tsciic.c b/sys/arch/alpha/pci/tsciic.c
index 37110949d564..29507daa8c95 100644
--- a/sys/arch/alpha/pci/tsciic.c
+++ b/sys/arch/alpha/pci/tsciic.c
@@ -45,8 +45,6 @@ __KERNEL_RCSID(0, "$NetBSD: tsciic.c,v 1.1 2014/02/21 12:23:30 jdc Exp $");
 #include <dev/i2c/ddcvar.h>
 
 /* I2C glue */
-static int tsciic_acquire_bus(void *, int);
-static void tsciic_release_bus(void *, int);
 static int tsciic_send_start(void *, int);
 static int tsciic_send_stop(void *, int);
 static int tsciic_initiate_xfer(void *, i2c_addr_t, int);
@@ -77,17 +75,13 @@ tsciic_init(device_t self) {
 	struct tsciic_softc *sc = device_private(self);
 	struct i2cbus_attach_args iba;
 
-	mutex_init(&sc->sc_buslock, MUTEX_DEFAULT, IPL_NONE);
-
+	iic_tag_init(&sc->sc_i2c);
 	sc->sc_i2c.ic_cookie = sc;
-	sc->sc_i2c.ic_acquire_bus = tsciic_acquire_bus;
-	sc->sc_i2c.ic_release_bus = tsciic_release_bus;
 	sc->sc_i2c.ic_send_start = tsciic_send_start;
 	sc->sc_i2c.ic_send_stop = tsciic_send_stop;
 	sc->sc_i2c.ic_initiate_xfer = tsciic_initiate_xfer;
 	sc->sc_i2c.ic_read_byte = tsciic_read_byte;
 	sc->sc_i2c.ic_write_byte = tsciic_write_byte;
-	sc->sc_i2c.ic_exec = NULL;
 
 	memset(&iba, 0, sizeof(iba));
 	iba.iba_tag = &sc->sc_i2c;
@@ -128,23 +122,6 @@ tsciicbb_read(void *cookie)
 }
 
 /* higher level I2C stuff */
-static int
-tsciic_acquire_bus(void *cookie, int flags)
-{
-	struct tsciic_softc *sc = cookie;
-
-	mutex_enter(&sc->sc_buslock);
-	return 0;
-}
-
-static void
-tsciic_release_bus(void *cookie, int flags)
-{
-	struct tsciic_softc *sc = cookie;
-
-	mutex_exit(&sc->sc_buslock);
-}
-
 static int
 tsciic_send_start(void *cookie, int flags)
 {
diff --git a/sys/arch/alpha/pci/tsvar.h b/sys/arch/alpha/pci/tsvar.h
index 641e62d83d2f..9cd92c128009 100644
--- a/sys/arch/alpha/pci/tsvar.h
+++ b/sys/arch/alpha/pci/tsvar.h
@@ -72,7 +72,6 @@ struct tsp_attach_args {
 struct tsciic_softc {
 	device_t	sc_dev;
 	struct		i2c_controller sc_i2c;
-	kmutex_t	sc_buslock;
 };
 
 struct tsciic_attach_args {
diff --git a/sys/arch/arm/at91/at91twi.c b/sys/arch/arm/at91/at91twi.c
index 79b27b2dac2b..82400a70bc2a 100644
--- a/sys/arch/arm/at91/at91twi.c
+++ b/sys/arch/arm/at91/at91twi.c
@@ -58,8 +58,6 @@ int at91twi_read(struct at91twi_softc *, int, void *, int, int);
 int at91twi_write(struct at91twi_softc *, int, void *, int, int);
 
 /* I2C glue */
-static int at91twi_i2c_acquire_bus(void *, int);
-static void at91twi_i2c_release_bus(void *, int);
 static int at91twi_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t,
 		    void *, size_t, int);
 
@@ -119,19 +117,12 @@ found_ckdiv:
 //#endif
 
 	/* initialize rest */
-	mutex_init(&sc->sc_buslock, MUTEX_DEFAULT, IPL_NONE);
 	sc->sc_ih = at91_intr_establish(sc->sc_pid, IPL_SERIAL, INTR_HIGH_LEVEL,
 					at91twi_intr, sc);
 
 	/* fill in the i2c tag */
+	iic_tag_init(&sc->sc_i2c);
 	sc->sc_i2c.ic_cookie = sc;
-	sc->sc_i2c.ic_acquire_bus = at91twi_i2c_acquire_bus;
-	sc->sc_i2c.ic_release_bus = at91twi_i2c_release_bus;
-	sc->sc_i2c.ic_send_start = NULL;
-	sc->sc_i2c.ic_send_stop = NULL;
-	sc->sc_i2c.ic_initiate_xfer = NULL;
-	sc->sc_i2c.ic_read_byte = NULL;
-	sc->sc_i2c.ic_write_byte = NULL;
 	sc->sc_i2c.ic_exec = at91twi_i2c_exec;
 
 	memset(&iba, 0, sizeof(iba));
@@ -294,29 +285,6 @@ at91twi_write(struct at91twi_softc *sc, int addr, void *data, int len, int flags
 	return at91twi_start(sc, addr, data, len, flags);
 }
 
-static int
-at91twi_i2c_acquire_bus(void *cookie, int flags)
-{
-	struct at91twi_softc *sc = cookie;
-
-	if (flags & I2C_F_POLL)
-		return 0;
-
-	mutex_enter(&sc->sc_buslock);
-	return 0;
-}
-
-static void
-at91twi_i2c_release_bus(void *cookie, int flags)
-{
-	struct at91twi_softc *sc = cookie;
-
-	if (flags & I2C_F_POLL)
-		return;
-
-	mutex_exit(&sc->sc_buslock);
-}
-
 int
 at91twi_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *vcmd,
     size_t cmdlen, void *vbuf, size_t buflen, int flags)
diff --git a/sys/arch/arm/at91/at91twivar.h b/sys/arch/arm/at91/at91twivar.h
index 2d68635c29ea..ce32204189a4 100644
--- a/sys/arch/arm/at91/at91twivar.h
+++ b/sys/arch/arm/at91/at91twivar.h
@@ -40,7 +40,6 @@ struct at91twi_softc {
 
 	int			sc_pid;		/* peripheral id	*/
 	struct i2c_controller	sc_i2c;		/* I2C device desc	*/
-	kmutex_t		sc_buslock;	/* bus lock		*/
 
 	void			*sc_ih;		/* interrupt handle	*/
 
diff --git a/sys/arch/arm/broadcom/bcm2835_bsc.c b/sys/arch/arm/broadcom/bcm2835_bsc.c
index 491766967969..f27eb4491a26 100644
--- a/sys/arch/arm/broadcom/bcm2835_bsc.c
+++ b/sys/arch/arm/broadcom/bcm2835_bsc.c
@@ -1,6 +1,7 @@
 /*	$NetBSD: bcm2835_bsc.c,v 1.13 2018/07/01 21:23:16 jmcneill Exp $	*/
 
 /*
+ * Copyright (c) 2019 Jason R. Thorpe
  * Copyright (c) 2012 Jonathan A. Kollasch
  * All rights reserved.
  *
@@ -29,17 +30,12 @@
 #include <sys/cdefs.h>
 __KERNEL_RCSID(0, "$NetBSD: bcm2835_bsc.c,v 1.13 2018/07/01 21:23:16 jmcneill Exp $");
 
-#if defined(_KERNEL_OPT)
-#include "opt_kernhist.h"
-#endif
-
 #include <sys/param.h>
 #include <sys/bus.h>
 #include <sys/device.h>
 #include <sys/kernhist.h>
 #include <sys/intr.h>
 #include <sys/mutex.h>
-#include <sys/once.h>
 #include <sys/systm.h>
 
 #include <dev/i2c/i2cvar.h>
@@ -49,42 +45,118 @@ __KERNEL_RCSID(0, "$NetBSD: bcm2835_bsc.c,v 1.13 2018/07/01 21:23:16 jmcneill Ex
 
 #include <dev/fdt/fdtvar.h>
 
-KERNHIST_DEFINE(bsciichist);
+typedef enum {
+	BSC_EXEC_STATE_IDLE		= 0,
+	BSC_EXEC_STATE_SEND_ADDR	= 1,
+	BSC_EXEC_STATE_SEND_CMD		= 2,
+	BSC_EXEC_STATE_SEND_DATA	= 3,
+	BSC_EXEC_STATE_RECV_DATA	= 4,
+	BSC_EXEC_STATE_DONE		= 5,
+	BSC_EXEC_STATE_ERROR		= 6,
+} bsc_exec_state_t;
+
+#define	BSC_EXEC_STATE_SENDING(sc)	\
+	((sc)->sc_exec_state >= BSC_EXEC_STATE_SEND_ADDR && \
+	 (sc)->sc_exec_state <= BSC_EXEC_STATE_SEND_DATA)
+
+#define	BSC_EXEC_STATE_RECEIVING(sc)	\
+	((sc)->sc_exec_state == BSC_EXEC_STATE_RECV_DATA)
 
 struct bsciic_softc {
 	device_t sc_dev;
 	bus_space_tag_t sc_iot;
 	bus_space_handle_t sc_ioh;
 	struct i2c_controller sc_i2c;
-	kmutex_t sc_buslock;
 	void *sc_inth;
 
 	struct clk *sc_clk;
 	u_int sc_frequency;
 	u_int sc_clkrate;
+
+	kmutex_t sc_intr_lock;
+	kcondvar_t sc_intr_wait;
+
+	struct {
+		i2c_op_t op;
+		i2c_addr_t addr;
+		const void *cmdbuf;
+		size_t cmdlen;
+		void *databuf;
+		size_t datalen;
+		int flags;
+	} sc_exec;
+
+	/*
+	 * Everything below here protected by the i2c controller lock
+	 * /and/ sc_intr_lock (if we're using interrupts).
+	 */
+
+	bsc_exec_state_t sc_exec_state;
+
+	uint8_t *sc_buf;
+	size_t sc_bufpos;
+	size_t sc_buflen;
+
+	uint32_t sc_c_bits;
+	bool sc_expecting_interrupt;
+};
+
+static void	bsciic_exec_func_idle(struct bsciic_softc * const);
+static void	bsciic_exec_func_send_addr(struct bsciic_softc * const);
+static void	bsciic_exec_func_send_cmd(struct bsciic_softc * const);
+static void	bsciic_exec_func_send_data(struct bsciic_softc * const);
+static void	bsciic_exec_func_recv_data(struct bsciic_softc * const);
+static void	bsciic_exec_func_done(struct bsciic_softc * const);
+static void	bsciic_exec_func_error(struct bsciic_softc * const);
+
+const struct {
+	void			(*func)(struct bsciic_softc * const);
+	uint32_t		c_bits;
+	uint32_t		s_bits;
+} bsciic_exec_state_data[] = {
+	[BSC_EXEC_STATE_IDLE] = {
+		.func = bsciic_exec_func_idle,
+	},
+	[BSC_EXEC_STATE_SEND_ADDR] = {
+		.func = bsciic_exec_func_send_addr,
+	},
+	[BSC_EXEC_STATE_SEND_CMD] = {
+		.func = bsciic_exec_func_send_cmd,
+		.c_bits = BSC_C_INTT,
+		.s_bits = BSC_S_TXW,
+	},
+	[BSC_EXEC_STATE_SEND_DATA] = {
+		.func = bsciic_exec_func_send_data,
+		.c_bits = BSC_C_INTT,
+		.s_bits = BSC_S_TXW,
+	},
+	[BSC_EXEC_STATE_RECV_DATA] = {
+		.func = bsciic_exec_func_recv_data,
+		.c_bits = BSC_C_READ | BSC_C_INTR,
+		.s_bits = BSC_S_RXR,
+	},
+	[BSC_EXEC_STATE_DONE] = {
+		.func = bsciic_exec_func_done,
+	},
+	[BSC_EXEC_STATE_ERROR] = {
+		.func = bsciic_exec_func_error,
+	},
 };
 
 static int bsciic_match(device_t, cfdata_t, void *);
 static void bsciic_attach(device_t, device_t, void *);
 
-void bsciic_dump_regs(struct bsciic_softc * const);
-
 static int  bsciic_acquire_bus(void *, int);
 static void bsciic_release_bus(void *, int);
 static int  bsciic_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t,
-    void *, size_t, int);
-
-CFATTACH_DECL_NEW(bsciic, sizeof(struct bsciic_softc),
-    bsciic_match, bsciic_attach, NULL, NULL);
+			void *, size_t, int);
 
-static int
-bsciic_init(void)
-{
+static int bsciic_intr(void *);
 
-	KERNHIST_INIT(bsciichist, 512);
+int	bsciic_debug = 0;
 
-	return 0;
-}
+CFATTACH_DECL_NEW(bsciic, sizeof(struct bsciic_softc),
+    bsciic_match, bsciic_attach, NULL, NULL);
 
 static int
 bsciic_match(device_t parent, cfdata_t match, void *aux)
@@ -104,9 +176,6 @@ bsciic_attach(device_t parent, device_t self, void *aux)
 	prop_dictionary_t prop = device_properties(self);
 	bool disable = false;
 
-	static ONCE_DECL(control);
-	RUN_ONCE(&control, bsciic_init);
-
 	bus_addr_t addr;
 	bus_size_t size;
 
@@ -146,24 +215,41 @@ bsciic_attach(device_t parent, device_t self, void *aux)
 	}
 
 	if (bus_space_map(sc->sc_iot, addr, size, 0, &sc->sc_ioh)) {
-		aprint_error_dev(sc->sc_dev, "unable to map device\n");
+		aprint_error(": unable to map device\n");
 		return;
 	}
 
 	aprint_naive("\n");
 	aprint_normal(": Broadcom Serial Controller\n");
 
-	mutex_init(&sc->sc_buslock, MUTEX_DEFAULT, IPL_NONE);
-
 	/* clear FIFO, disable controller */
 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_C, BSC_C_CLEAR_CLEAR);
 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_S, BSC_S_CLKT |
 	    BSC_S_ERR | BSC_S_DONE);
+	bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_DLEN, 0);
 
 	u_int divider = howmany(sc->sc_frequency, sc->sc_clkrate);
 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_DIV,
 	   __SHIFTIN(divider, BSC_DIV_CDIV));
 
+	mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_VM);
+	cv_init(&sc->sc_intr_wait, device_xname(self));
+
+	char intrstr[128];
+	if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) {
+		aprint_error_dev(sc->sc_dev, "failed to decode interrupt\n");
+		return;
+	}
+	sc->sc_inth = fdtbus_intr_establish(phandle, 0, IPL_VM,
+	    FDT_INTR_MPSAFE, bsciic_intr, sc);
+	if (sc->sc_inth == NULL) {
+		aprint_error_dev(sc->sc_dev,
+		    "failed to establish interrupt %s\n", intrstr);
+		return;
+	}
+	aprint_normal_dev(sc->sc_dev, "interrupting on %s\n", intrstr);
+
+	iic_tag_init(&sc->sc_i2c);
 	sc->sc_i2c.ic_cookie = sc;
 	sc->sc_i2c.ic_acquire_bus = bsciic_acquire_bus;
 	sc->sc_i2c.ic_release_bus = bsciic_release_bus;
@@ -172,28 +258,12 @@ bsciic_attach(device_t parent, device_t self, void *aux)
 	fdtbus_attach_i2cbus(self, phandle, &sc->sc_i2c, iicbus_print);
 }
 
-void
-bsciic_dump_regs(struct bsciic_softc * const sc)
-{
-	KERNHIST_FUNC(__func__);
-	KERNHIST_CALLED(bsciichist);
-
-	KERNHIST_LOG(bsciichist, "C %08jx S %08jx D %08jx A %08jx",
-	    bus_space_read_4(sc->sc_iot, sc->sc_ioh, BSC_C),
-	    bus_space_read_4(sc->sc_iot, sc->sc_ioh, BSC_S),
-	    bus_space_read_4(sc->sc_iot, sc->sc_ioh, BSC_DLEN),
-	    bus_space_read_4(sc->sc_iot, sc->sc_ioh, BSC_A)
-	    );
-}
-
 static int
 bsciic_acquire_bus(void *v, int flags)
 {
 	struct bsciic_softc * const sc = v;
 	uint32_t s __diagused;
 
-	mutex_enter(&sc->sc_buslock);
-
 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_S, BSC_S_CLKT |
 	    BSC_S_ERR | BSC_S_DONE);
 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_C, BSC_C_I2CEN |
@@ -210,203 +280,365 @@ bsciic_release_bus(void *v, int flags)
 	struct bsciic_softc * const sc = v;
 
 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_C, BSC_C_CLEAR_CLEAR);
+}
 
-	mutex_exit(&sc->sc_buslock);
+static void
+bsciic_exec_lock(struct bsciic_softc * const sc)
+{
+	if ((sc->sc_exec.flags & I2C_F_POLL) == 0) {
+		mutex_enter(&sc->sc_intr_lock);
+	}
+}
+
+static void
+bsciic_exec_unlock(struct bsciic_softc * const sc)
+{
+	if ((sc->sc_exec.flags & I2C_F_POLL) == 0) {
+		mutex_exit(&sc->sc_intr_lock);
+	}
+}
+
+static void
+bsciic_txfill(struct bsciic_softc * const sc)
+{
+	uint32_t s;
+
+	while (sc->sc_bufpos != sc->sc_buflen) {
+		s = bus_space_read_4(sc->sc_iot, sc->sc_ioh, BSC_S);
+		if ((s & BSC_S_TXD) == 0)
+			break;
+		bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_FIFO,
+		    sc->sc_buf[sc->sc_bufpos++]);
+	}
+}
+
+static void
+bsciic_rxdrain(struct bsciic_softc * const sc)
+{
+	uint32_t s;
+
+	while (sc->sc_bufpos != sc->sc_buflen) {
+		s = bus_space_read_4(sc->sc_iot, sc->sc_ioh, BSC_S);
+		if ((s & BSC_S_RXD) == 0)
+			break;
+		sc->sc_buf[sc->sc_bufpos++] =
+		    (uint8_t)bus_space_read_4(sc->sc_iot, sc->sc_ioh, BSC_FIFO);
+	}
+}
+
+static bsc_exec_state_t
+bsciic_next_state(struct bsciic_softc * const sc)
+{
+	switch (sc->sc_exec_state) {
+	case BSC_EXEC_STATE_IDLE:
+		if (sc->sc_exec.addr > 0x7f) {
+			return BSC_EXEC_STATE_SEND_ADDR;
+		}
+		/* FALLTHROUGH */
+
+	case BSC_EXEC_STATE_SEND_ADDR:
+		if (sc->sc_exec.cmdlen) {
+			return BSC_EXEC_STATE_SEND_CMD;
+		}
+		/* FALLTHROUGH */
+
+	case BSC_EXEC_STATE_SEND_CMD:
+		if (sc->sc_exec.datalen == 0) {
+			return BSC_EXEC_STATE_DONE;
+		}
+
+		if (I2C_OP_READ_P(sc->sc_exec.op)) {
+			return BSC_EXEC_STATE_RECV_DATA;
+		}
+
+		return BSC_EXEC_STATE_SEND_DATA;
+
+	case BSC_EXEC_STATE_SEND_DATA:
+	case BSC_EXEC_STATE_RECV_DATA:
+		return BSC_EXEC_STATE_DONE;
+	
+	case BSC_EXEC_STATE_DONE:
+	case BSC_EXEC_STATE_ERROR:
+		return sc->sc_exec_state;
+	}
+
+	panic("bsciic_next_state: invalid state: %d", sc->sc_exec_state);
+}
+
+#define	BSC_EXEC_PHASE_COMPLETE(sc)				\
+	((sc)->sc_exec_state == BSC_EXEC_STATE_ERROR ||		\
+	 (sc)->sc_bufpos == (sc)->sc_buflen)
+
+static void
+bsciic_signal(struct bsciic_softc * const sc)
+{
+	if ((sc->sc_exec.flags & I2C_F_POLL) == 0) {
+		cv_signal(&sc->sc_intr_wait);
+	}
+}
+
+static void
+bsciic_phase_done(struct bsciic_softc * const sc)
+{
+	sc->sc_exec_state = bsciic_next_state(sc);
+	(*bsciic_exec_state_data[sc->sc_exec_state].func)(sc);
+}
+
+static void
+bsciic_abort(struct bsciic_softc * const sc)
+{
+	sc->sc_exec_state = BSC_EXEC_STATE_ERROR;
+	bsciic_phase_done(sc);
 }
 
 static int
-bsciic_exec(void *v, i2c_op_t op, i2c_addr_t addr, const void *cmdbuf,
-    size_t cmdlen, void *databuf, size_t datalen, int flags)
+bsciic_intr(void *v)
 {
-	KERNHIST_FUNC(__func__); KERNHIST_CALLED(bsciichist);
 	struct bsciic_softc * const sc = v;
-	uint32_t c, s, dlen, a;
-	uint32_t j;
-	uint8_t *buf;
-	size_t len;
-	size_t pos;
-	int error = 0;
-	int whichbuf = 0;
-	const bool isread = I2C_OP_READ_P(op);
+	uint32_t s;
 
-	/*
-	 * XXX We don't do 10-bit addressing correctly yet.
-	 */
-	if (addr > 0x7f)
-		return (ENOTSUP);
+	bsciic_exec_lock(sc);
 
-	flags |= I2C_F_POLL;
+	if ((sc->sc_exec.flags & I2C_F_POLL) == 0 &&
+	    sc->sc_expecting_interrupt == false) {
+		bsciic_exec_unlock(sc);
+		return 0;
+	}
 
-#if 0
-	device_printf(sc->sc_dev, "exec: op %d, addr 0x%x, cmdbuf %p, "
-	    "cmdlen %zu, databuf %p, datalen %zu, flags 0x%x\n",
-	    op, addr, cmdbuf, cmdlen, databuf, datalen, flags);
-#endif
+	s = bus_space_read_4(sc->sc_iot, sc->sc_ioh, BSC_S);
+	bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_S,
+	    BSC_S_CLKT | BSC_S_ERR | BSC_S_DONE);
+
+	if (s & (BSC_S_CLKT | BSC_S_ERR)) {
+		/*
+		 * ERR might be a normal "probing for device" sort
+		 * of thing, so don't complain about that one.
+		 * Do complain about CLKT, though.
+		 */
+		if ((s & BSC_S_CLKT) ||
+		    (bsciic_debug && (s & BSC_S_ERR))) {
+			device_printf(sc->sc_dev,
+			    "error s=0x%08x, aborting transfer\n", s);
+		}
+		bsciic_abort(sc);
+		goto out;
+	}
 
-	a = __SHIFTIN(addr, BSC_A_ADDR);
-	c = BSC_C_I2CEN | BSC_C_CLEAR_CLEAR;
-#if notyet
-	c |= BSC_C_INTR | BSC_C_INTT | BSC_C_INTD;
-#endif
+	if (BSC_EXEC_STATE_SENDING(sc)) {
+		/*
+		 * When transmitting, we need to wait for one final
+		 * interrupt after pushing out the last of our data.
+		 * Catch that case here and go to the next state.
+		 */
+		if (BSC_EXEC_PHASE_COMPLETE(sc)) {
+			bsciic_phase_done(sc);
+		} else {
+			bsciic_txfill(sc);
+		}
+	} else if (BSC_EXEC_STATE_RECEIVING(sc)) {
+		bsciic_rxdrain(sc);
+		/*
+		 * If we've received all of the data, go to the next
+		 * state now; we might not get another interrupt.
+		 */
+		if (BSC_EXEC_PHASE_COMPLETE(sc)) {
+			bsciic_phase_done(sc);
+		}
+	} else {
+		device_printf(sc->sc_dev,
+		    "unexpected interrupt: state=%d s=0x%08x\n",
+		    sc->sc_exec_state, s);
+		bsciic_abort(sc);
+	}
 
-	if (isread && cmdlen == 0)
-		goto only_read;
+ out:
+	bsciic_exec_unlock(sc);
+	return (1);
+}
 
-	buf = __UNCONST(cmdbuf);
-	len = cmdlen;
+static void
+bsciic_wait(struct bsciic_softc * const sc, const uint32_t events)
+{
+	if ((sc->sc_exec.flags & I2C_F_POLL) == 0) {
+		return;
+	}
 
-	if (isread)
-		dlen = cmdlen;
-	else
-		dlen = cmdlen + datalen;
-	dlen = __SHIFTIN(dlen, BSC_DLEN_DLEN);
+	const uint32_t s_bits =
+	    events | BSC_S_CLKT | BSC_S_ERR | BSC_S_DONE;
+	uint32_t s;
 
-	s = bus_space_read_4(sc->sc_iot, sc->sc_ioh, BSC_S);
-	if ((s & BSC_S_TA) != 0)
-		bsciic_dump_regs(sc);
-	KASSERT((s & BSC_S_TA) == 0);
-	bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_DLEN, dlen);
-	bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_A, a);
-	bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_C, c | BSC_C_ST);
+	/* sc_intr_lock is not held in this case. */
 
-	do {
-		s = bus_space_read_4(sc->sc_iot, sc->sc_ioh, BSC_S);
-	} while ((s & BSC_S_TA) == 0);
-
-flood_again:
-	KERNHIST_LOG(bsciichist, "flood top %#jx %ju",
-	    (uintptr_t)buf, len, 0, 0);
-	j = 10000000;
-	for (pos = 0; pos < len; ) {
-		if (--j == 0)
-			return -1;
+	for (;;) {
 		s = bus_space_read_4(sc->sc_iot, sc->sc_ioh, BSC_S);
-		KERNHIST_LOG(bsciichist, "w s %08jx", s, 0, 0, 0);
-		if ((s & BSC_S_CLKT) != 0) {
-			error = EIO;
-			goto done;
+		if (s & s_bits) {
+			(void) bsciic_intr(sc);
 		}
-		if ((s & BSC_S_ERR) != 0) {
-			error = EIO;
-			goto done;
+		if (BSC_EXEC_PHASE_COMPLETE(sc)) {
+			bsciic_phase_done(sc);
 		}
-		if ((s & BSC_S_DONE) != 0)
-			break;
-		if ((s & BSC_S_TXD) == 0)
-			continue;
-		bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_FIFO, buf[pos]);
-		KERNHIST_LOG(bsciichist, "w %#jx %#jx %02jx",
-		    (uintptr_t)buf, (uintptr_t)&buf[pos],
-		    buf[pos], 0);
-		pos++;
+		if (sc->sc_exec_state >= BSC_EXEC_STATE_DONE) {
+			return;
+		}
+		delay(1);
 	}
-	KERNHIST_LOG(bsciichist, "flood bot %#jx %ju",
-	    (uintptr_t)buf, len, 0, 0);
-
-	if (whichbuf == 0 && !isread) {
-		KASSERT(buf == cmdbuf);
-		whichbuf++;
-		buf = databuf;
-		len = datalen;
-		if (len)
-			goto flood_again;
+}
+
+static void
+bsciic_start(struct bsciic_softc * const sc)
+{
+
+	sc->sc_c_bits = BSC_C_I2CEN | BSC_C_INTD |
+	    bsciic_exec_state_data[sc->sc_exec_state].c_bits;
+
+	/* Clear the interrupt-enable bits if we're polling. */
+	if (sc->sc_exec.flags & I2C_F_POLL) {
+		sc->sc_c_bits &= ~(BSC_C_INTD | BSC_C_INTT | BSC_C_INTR);
 	}
 
-	do {
-		s = bus_space_read_4(sc->sc_iot, sc->sc_ioh, BSC_S);
-	} while ((s & BSC_S_TA) != 0);
+	sc->sc_expecting_interrupt =
+	    (sc->sc_c_bits & (BSC_C_INTD | BSC_C_INTT | BSC_C_INTR)) ? true
+								     : false;
 
-	s = bus_space_read_4(sc->sc_iot, sc->sc_ioh, BSC_S);
-	s &= BSC_S_CLKT|BSC_S_ERR|BSC_S_DONE;
-	KASSERT((s & BSC_S_DONE) != 0);
-	if (s != 0)
-		bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_S, s);
+	bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_C,
+	    sc->sc_c_bits | BSC_C_ST);
+	bsciic_wait(sc, bsciic_exec_state_data[sc->sc_exec_state].s_bits);
+}
 
-	if (error == 0 && (s & (BSC_S_CLKT|BSC_S_ERR)) != 0)
-		error = EIO;
+static void
+bsciic_exec_func_idle(struct bsciic_softc * const sc)
+{
+	/* We kick off a transfer by setting the slave address register. */
+	bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_A, sc->sc_exec.addr);
 
-	if (!isread)
-		goto done;
+	/* Immediately transition to the next state. */
+	bsciic_phase_done(sc);
+}
 
-only_read:
-	c |= BSC_C_READ;
+static void
+bsciic_exec_func_send_addr(struct bsciic_softc * const sc)
+{
+	/* XXX For 10-bit addressing; not implemented yet. */
+	panic("bsciic_exec_func_send_addr is not supposed to be called");
+}
 
-	buf = databuf;
-	len = datalen;
-	dlen = datalen;
+static void
+bsciic_exec_func_send_cmd(struct bsciic_softc * const sc)
+{
+	sc->sc_buf = __UNCONST(sc->sc_exec.cmdbuf);
+	sc->sc_bufpos = 0;
+	sc->sc_buflen = sc->sc_exec.cmdlen;
 
-	dlen = __SHIFTIN(dlen, BSC_DLEN_DLEN);
-#if 0
-	KASSERT(dlen >= 1);
-#endif
+	uint32_t dlen = sc->sc_exec.cmdlen;
+	if (! I2C_OP_READ_P(sc->sc_exec.op)) {
+		dlen += sc->sc_exec.datalen;
+	}
 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_DLEN, dlen);
-	bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_A, a);
-	bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_C, c | BSC_C_ST);
 
-	do {
-		s = bus_space_read_4(sc->sc_iot, sc->sc_ioh, BSC_S);
-	} while ((s & BSC_S_TA) == 0);
-
-	KERNHIST_LOG(bsciichist, "drain top %#jx %ju",
-	    (uintptr_t)buf, len, 0, 0);
-	j = 10000000;
-	for (pos = 0; pos < len; ) {
-		if (--j == 0)
-			return -1;
-		s = bus_space_read_4(sc->sc_iot, sc->sc_ioh, BSC_S);
-		KERNHIST_LOG(bsciichist, "r s %08jx", s, 0, 0, 0);
-		if ((s & BSC_S_CLKT) != 0) {
-			error = EIO;
-			goto done;
-		}
-		if ((s & BSC_S_ERR) != 0) {
-			error = EIO;
-			goto done;
-		}
-		if ((s & BSC_S_DONE) != 0)
-			break;
-		if ((s & BSC_S_RXD) == 0)
-			continue;
-		j = 10000000;
-		buf[pos] = bus_space_read_4(sc->sc_iot, sc->sc_ioh, BSC_FIFO);
-		KERNHIST_LOG(bsciichist, "r %#jx %#jx %02jx",
-		    (uintptr_t)buf, (uintptr_t)&buf[pos],
-		    buf[pos], 0);
-		pos++;
-	}
-	KERNHIST_LOG(bsciichist, "drain bot %#jx %ju", (uintptr_t)buf, len,
-	    0, 0);
+	bsciic_start(sc);
+}
 
-	do {
-		s = bus_space_read_4(sc->sc_iot, sc->sc_ioh, BSC_S);
-	} while ((s & BSC_S_TA) != 0);
+static void
+bsciic_exec_func_send_data(struct bsciic_softc * const sc)
+{
+	sc->sc_buf = sc->sc_exec.databuf;
+	sc->sc_bufpos = 0;
+	sc->sc_buflen = sc->sc_exec.datalen;
+
+	if (sc->sc_exec.cmdlen) {
+		/*
+		 * Output has already been started in this case; we just
+		 * needed to switch buffers.
+		 */
+		bsciic_wait(sc, BSC_S_TXW);
+	} else {
+		uint32_t dlen = sc->sc_exec.datalen;
+		bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_DLEN, dlen);
+		bsciic_start(sc);
+	}
+}
 
-	s = bus_space_read_4(sc->sc_iot, sc->sc_ioh, BSC_S);
-	s &= BSC_S_CLKT|BSC_S_ERR|BSC_S_DONE;
-	KASSERT((s & BSC_S_DONE) != 0);
-	if (s != 0)
-		bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_S, s);
+static void
+bsciic_exec_func_recv_data(struct bsciic_softc * const sc)
+{
+	sc->sc_buf = sc->sc_exec.databuf;
+	sc->sc_bufpos = 0;
+	sc->sc_buflen = sc->sc_exec.datalen;
 
-done:
-	bsciic_dump_regs(sc);
+	uint32_t dlen = sc->sc_exec.datalen;
+	bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_DLEN, dlen);
 
-	bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_DLEN, 0);
+	bsciic_start(sc);
+}
 
-	do {
-		s = bus_space_read_4(sc->sc_iot, sc->sc_ioh, BSC_S);
-	} while ((s & BSC_S_TA) != 0);
+static void
+bsciic_exec_func_done(struct bsciic_softc * const sc)
+{
+	/* We're done!  Disable interrupts. */
+	bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_C, BSC_C_I2CEN);
+	sc->sc_expecting_interrupt = false;
+	bsciic_signal(sc);
+}
 
-	bsciic_dump_regs(sc);
+static void
+bsciic_exec_func_error(struct bsciic_softc * const sc)
+{
+	/* Clear the FIFO and disable interrupts. */
+	bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_C,
+	    BSC_C_I2CEN | BSC_C_CLEAR_CLEAR);
+	sc->sc_expecting_interrupt = false;
+	bsciic_signal(sc);
+}
 
-	s = bus_space_read_4(sc->sc_iot, sc->sc_ioh, BSC_S);
-	s &= BSC_S_CLKT|BSC_S_ERR|BSC_S_DONE;
-	if (s != 0)
-		bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_S, s);
+static int
+bsciic_exec(void *v, i2c_op_t op, i2c_addr_t addr, const void *cmdbuf,
+    size_t cmdlen, void *databuf, size_t datalen, int flags)
+{
+	struct bsciic_softc * const sc = v;
 
-	bsciic_dump_regs(sc);
+	/* XXX We don't do 10-bit addressing correctly yet. */
+	if (addr > 0x7f)
+		return (ENOTSUP);
 
-	if (error == 0 && (s & (BSC_S_CLKT|BSC_S_ERR)) != 0)
+	/*
+	 * The I2C middle layer has ensured that the client device has
+	 * exclusive access to the controller.  Copy the parameters
+	 * and start the state machine that runs through the necessary
+	 * phases of the request.
+	 */
+	KASSERT(sc->sc_exec_state == BSC_EXEC_STATE_IDLE);
+	sc->sc_exec.op = op;
+	sc->sc_exec.addr = addr;
+	sc->sc_exec.cmdbuf = cmdbuf;
+	sc->sc_exec.cmdlen = cmdlen;
+	sc->sc_exec.databuf = databuf;
+	sc->sc_exec.datalen = datalen;
+	sc->sc_exec.flags = flags;
+
+	bsciic_exec_lock(sc);
+	(*bsciic_exec_state_data[sc->sc_exec_state].func)(sc);
+	while (sc->sc_exec_state < BSC_EXEC_STATE_DONE) {
+		KASSERT((flags & I2C_F_POLL) == 0);
+		cv_wait(&sc->sc_intr_wait, &sc->sc_intr_lock);
+	}
+	int error = sc->sc_exec_state == BSC_EXEC_STATE_ERROR ? EIO : 0;
+	uint32_t s;
+	do {
+		s = bus_space_read_4(sc->sc_iot, sc->sc_ioh, BSC_S);
+	} while ((s & BSC_S_TA) != 0);
+	if (s & (BSC_S_CLKT | BSC_S_ERR)) {
 		error = EIO;
+	}
+	bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_C,
+	    BSC_C_I2CEN | BSC_C_CLEAR_CLEAR);
+	bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_S,
+	    BSC_S_CLKT | BSC_S_ERR | BSC_S_DONE);
+	bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_DLEN, 0);
+	bsciic_exec_unlock(sc);
+
+	sc->sc_exec.flags = 0;
+	sc->sc_exec_state = BSC_EXEC_STATE_IDLE;
+	memset(&sc->sc_exec, 0, sizeof(sc->sc_exec));
 
 	return error;
 }
diff --git a/sys/arch/arm/iomd/iomdiic.c b/sys/arch/arm/iomd/iomdiic.c
index 0d3fc9f3dc8a..5c1446ee6e62 100644
--- a/sys/arch/arm/iomd/iomdiic.c
+++ b/sys/arch/arm/iomd/iomdiic.c
@@ -57,7 +57,6 @@ struct iomdiic_softc {
 	bus_space_handle_t sc_sh;
 
 	struct i2c_controller sc_i2c;
-	kmutex_t sc_buslock;
 
 	/*
 	 * The SDA pin is open-drain, so we make it an input by
@@ -66,9 +65,6 @@ struct iomdiic_softc {
 	uint8_t sc_iomd_iocr;
 };
 
-static int	iomdiic_acquire_bus(void *, int);
-static void	iomdiic_release_bus(void *, int);
-
 static int	iomdiic_send_start(void *, int);
 static int	iomdiic_send_stop(void *, int);
 static int	iomdiic_initiate_xfer(void *, i2c_addr_t, int);
@@ -136,11 +132,8 @@ iomdiic_attach(device_t parent, device_t self, void *aux)
 
 	sc->sc_dev = self;
 
-	mutex_init(&sc->sc_buslock, MUTEX_DEFAULT, IPL_NONE);
-
+	iic_tag_init(&sc->sc_i2c);
 	sc->sc_i2c.ic_cookie = sc;
-	sc->sc_i2c.ic_acquire_bus = iomdiic_acquire_bus;
-	sc->sc_i2c.ic_release_bus = iomdiic_release_bus;
 	sc->sc_i2c.ic_send_start = iomdiic_send_start;
 	sc->sc_i2c.ic_send_stop = iomdiic_send_stop;
 	sc->sc_i2c.ic_initiate_xfer = iomdiic_initiate_xfer;
@@ -165,9 +158,9 @@ iomdiic_bootstrap_cookie(void)
 	strcpy(dev.dv_xname, "iomdiicboot");
 
 	sc.sc_dev = &dev;
+
+	iic_tag_init(&sc.sc_i2c);
 	sc.sc_i2c.ic_cookie = &sc;
-	sc.sc_i2c.ic_acquire_bus = iomdiic_acquire_bus;
-	sc.sc_i2c.ic_release_bus = iomdiic_release_bus;
 	sc.sc_i2c.ic_send_start = iomdiic_send_start;
 	sc.sc_i2c.ic_send_stop = iomdiic_send_stop;
 	sc.sc_i2c.ic_initiate_xfer = iomdiic_initiate_xfer;
@@ -177,31 +170,6 @@ iomdiic_bootstrap_cookie(void)
 	return ((void *) &sc.sc_i2c);
 }
 
-static int
-iomdiic_acquire_bus(void *cookie, int flags)
-{
-	struct iomdiic_softc *sc = cookie;
-
-	/* XXX What should we do for the polling case? */
-	if (flags & I2C_F_POLL)
-		return (0);
-
-	mutex_enter(&sc->sc_buslock);
-	return (0);
-}
-
-static void
-iomdiic_release_bus(void *cookie, int flags)
-{
-	struct iomdiic_softc *sc = cookie;
-
-	/* XXX See above. */
-	if (flags & I2C_F_POLL)
-		return;
-
-	mutex_exit(&sc->sc_buslock);
-}
-
 static int
 iomdiic_send_start(void *cookie, int flags)
 {
diff --git a/sys/arch/arm/nvidia/tegra_i2c.c b/sys/arch/arm/nvidia/tegra_i2c.c
index 9d837c457a2f..60a227eec249 100644
--- a/sys/arch/arm/nvidia/tegra_i2c.c
+++ b/sys/arch/arm/nvidia/tegra_i2c.c
@@ -70,8 +70,6 @@ struct tegra_i2c_softc {
 static void	tegra_i2c_init(struct tegra_i2c_softc *);
 static int	tegra_i2c_intr(void *);
 
-static int	tegra_i2c_acquire_bus(void *, int);
-static void	tegra_i2c_release_bus(void *, int);
 static int	tegra_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *,
 			       size_t, void *, size_t, int);
 
@@ -177,11 +175,12 @@ tegra_i2c_attach(device_t parent, device_t self, void *aux)
 	}
 	fdtbus_reset_deassert(sc->sc_rst);
 
+	mutex_enter(&sc->sc_lock);
 	tegra_i2c_init(sc);
+	mutex_exit(&sc->sc_lock);
 
+	iic_tag_init(&sc->sc_ic);
 	sc->sc_ic.ic_cookie = sc;
-	sc->sc_ic.ic_acquire_bus = tegra_i2c_acquire_bus;
-	sc->sc_ic.ic_release_bus = tegra_i2c_release_bus;
 	sc->sc_ic.ic_exec = tegra_i2c_exec;
 
 	fdtbus_register_i2c_controller(self, phandle, &tegra_i2c_funcs);
@@ -243,24 +242,6 @@ tegra_i2c_intr(void *priv)
 	return 1;
 }
 
-static int
-tegra_i2c_acquire_bus(void *priv, int flags)
-{
-	struct tegra_i2c_softc * const sc = priv;
-
-	mutex_enter(&sc->sc_lock);
-
-	return 0;
-}
-
-static void
-tegra_i2c_release_bus(void *priv, int flags)
-{
-	struct tegra_i2c_softc * const sc = priv;
-
-	mutex_exit(&sc->sc_lock);
-}
-
 static int
 tegra_i2c_exec(void *priv, i2c_op_t op, i2c_addr_t addr, const void *cmdbuf,
     size_t cmdlen, void *buf, size_t buflen, int flags)
@@ -268,16 +249,19 @@ tegra_i2c_exec(void *priv, i2c_op_t op, i2c_addr_t addr, const void *cmdbuf,
 	struct tegra_i2c_softc * const sc = priv;
 	int retry, error;
 
-#if notyet
-	if (cold)
-#endif
-		flags |= I2C_F_POLL;
-
-	KASSERT(mutex_owned(&sc->sc_lock));
+	/*
+	 * XXXJRT This is probably no longer necessary?  Before these
+	 * changes, sc_lock was held by iic_acquire_bus(), and there
+	 * would be a deadlock when the interrupt handler tried to
+	 * acquire it again.
+	 */
+	flags |= I2C_F_POLL;
 
 	if (buflen == 0 && cmdlen == 0)
 		return EINVAL;
 
+	mutex_enter(&sc->sc_lock);
+
 	if ((flags & I2C_F_POLL) == 0) {
 		I2C_WRITE(sc, I2C_INTERRUPT_MASK_REG,
 		    I2C_INTERRUPT_MASK_NOACK | I2C_INTERRUPT_MASK_ARB_LOST |
@@ -296,6 +280,7 @@ tegra_i2c_exec(void *priv, i2c_op_t op, i2c_addr_t addr, const void *cmdbuf,
 		delay(1);
 	}
 	if (retry == 0) {
+		mutex_exit(&sc->sc_lock);
 		device_printf(sc->sc_dev, "timeout flushing FIFO\n");
 		return EIO;
 	}
@@ -325,6 +310,8 @@ done:
 		tegra_i2c_init(sc);
 	}
 
+	mutex_exit(&sc->sc_lock);
+
 	return error;
 }
 
diff --git a/sys/arch/arm/omap/omap3_i2c.c b/sys/arch/arm/omap/omap3_i2c.c
index 719e1dd901cb..31732dddd639 100644
--- a/sys/arch/arm/omap/omap3_i2c.c
+++ b/sys/arch/arm/omap/omap3_i2c.c
@@ -53,7 +53,6 @@ __KERNEL_RCSID(0, "$NetBSD: omap3_i2c.c,v 1.3 2013/03/13 03:08:17 khorben Exp $"
 struct omap3_i2c_softc {
 	device_t		sc_dev;
 	struct i2c_controller	sc_ic;
-	kmutex_t		sc_lock;
 	device_t		sc_i2cdev;
 
 	bus_space_tag_t		sc_iot;
@@ -74,8 +73,6 @@ static void	omap3_i2c_attach(device_t, device_t, void *);
 static int	omap3_i2c_rescan(device_t, const char *, const int *);
 static void	omap3_i2c_childdet(device_t, device_t);
 
-static int	omap3_i2c_acquire_bus(void *, int);
-static void	omap3_i2c_release_bus(void *, int);
 static int	omap3_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *,
 			       size_t, void *, size_t, int);
 
@@ -120,10 +117,9 @@ omap3_i2c_attach(device_t parent, device_t self, void *opaque)
 
 	sc->sc_dev = self;
 	sc->sc_iot = obio->obio_iot;
-	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
+
+	iic_tag_init(&sc->sc_ic);
 	sc->sc_ic.ic_cookie = sc;
-	sc->sc_ic.ic_acquire_bus = omap3_i2c_acquire_bus;
-	sc->sc_ic.ic_release_bus = omap3_i2c_release_bus;
 	sc->sc_ic.ic_exec = omap3_i2c_exec;
 
 	if (bus_space_map(obio->obio_iot, obio->obio_addr, obio->obio_size,
@@ -168,29 +164,6 @@ omap3_i2c_childdet(device_t self, device_t child)
 		sc->sc_i2cdev = NULL;
 }
 
-static int
-omap3_i2c_acquire_bus(void *opaque, int flags)
-{
-	struct omap3_i2c_softc *sc = opaque;
-
-	if (flags & I2C_F_POLL) {
-		if (!mutex_tryenter(&sc->sc_lock))
-			return EBUSY;
-	} else {
-		mutex_enter(&sc->sc_lock);
-	}
-
-	return 0;
-}
-
-static void
-omap3_i2c_release_bus(void *opaque, int flags)
-{
-	struct omap3_i2c_softc *sc = opaque;
-
-	mutex_exit(&sc->sc_lock);
-}
-
 static int
 omap3_i2c_exec(void *opaque, i2c_op_t op, i2c_addr_t addr,
     const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
diff --git a/sys/arch/arm/omap/ti_iic.c b/sys/arch/arm/omap/ti_iic.c
index b094e078b7fe..e3e73d33e2b0 100644
--- a/sys/arch/arm/omap/ti_iic.c
+++ b/sys/arch/arm/omap/ti_iic.c
@@ -102,7 +102,6 @@ typedef enum {
 struct ti_iic_softc {
 	device_t		sc_dev;
 	struct i2c_controller	sc_ic;
-	kmutex_t		sc_lock;
 	device_t		sc_i2cdev;
 
 	bus_space_tag_t		sc_iot;
@@ -136,8 +135,6 @@ static void	ti_iic_childdet(device_t, device_t);
 
 static int	ti_iic_intr(void *);
 
-static int	ti_iic_acquire_bus(void *, int);
-static void	ti_iic_release_bus(void *, int);
 static int	ti_iic_exec(void *, i2c_op_t, i2c_addr_t, const void *,
 			       size_t, void *, size_t, int);
 
@@ -214,9 +211,10 @@ ti_iic_attach(device_t parent, device_t self, void *opaque)
 
 	sc->sc_dev = self;
 	sc->sc_iot = obio->obio_iot;
-	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
 	mutex_init(&sc->sc_mtx, MUTEX_DEFAULT, IPL_NET);
 	cv_init(&sc->sc_cv, "tiiic");
+
+	iic_tag_init(&sc->sc_ic);
 	sc->sc_ic.ic_cookie = sc;
 	sc->sc_ic.ic_acquire_bus = ti_iic_acquire_bus;
 	sc->sc_ic.ic_release_bus = ti_iic_release_bus;
@@ -336,29 +334,6 @@ ti_iic_intr(void *arg)
 	return 1;
 }
 
-static int
-ti_iic_acquire_bus(void *opaque, int flags)
-{
-	struct ti_iic_softc *sc = opaque;
-
-	if (flags & I2C_F_POLL) {
-		if (!mutex_tryenter(&sc->sc_lock))
-			return EBUSY;
-	} else {
-		mutex_enter(&sc->sc_lock);
-	}
-
-	return 0;
-}
-
-static void
-ti_iic_release_bus(void *opaque, int flags)
-{
-	struct ti_iic_softc *sc = opaque;
-
-	mutex_exit(&sc->sc_lock);
-}
-
 static int
 ti_iic_exec(void *opaque, i2c_op_t op, i2c_addr_t addr,
     const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
diff --git a/sys/arch/arm/rockchip/rk_i2c.c b/sys/arch/arm/rockchip/rk_i2c.c
index e874b083d673..7f12ce99b14a 100644
--- a/sys/arch/arm/rockchip/rk_i2c.c
+++ b/sys/arch/arm/rockchip/rk_i2c.c
@@ -115,8 +115,6 @@ struct rk_i2c_softc {
 	u_int			sc_clkfreq;
 
 	struct i2c_controller	sc_ic;
-	kmutex_t		sc_lock;
-	kcondvar_t		sc_cv;
 };
 
 #define	RD4(sc, reg)				\
@@ -161,24 +159,6 @@ rk_i2c_init(struct rk_i2c_softc *sc)
 	WR4(sc, RKI2C_IPD, RD4(sc, RKI2C_IPD));
 }
 
-static int
-rk_i2c_acquire_bus(void *priv, int flags)
-{
-	struct rk_i2c_softc * const sc = priv;
-
-	mutex_enter(&sc->sc_lock);
-
-	return 0;
-}
-
-static void
-rk_i2c_release_bus(void *priv, int flags)
-{
-	struct rk_i2c_softc * const sc = priv;
-
-	mutex_exit(&sc->sc_lock);
-}
-
 static int
 rk_i2c_wait(struct rk_i2c_softc *sc, uint32_t mask)
 {
@@ -333,8 +313,6 @@ rk_i2c_exec(void *priv, i2c_op_t op, i2c_addr_t addr,
 	bool send_start = true;
 	int error;
 
-	KASSERT(mutex_owned(&sc->sc_lock));
-
 	if (I2C_OP_READ_P(op)) {
 		error = rk_i2c_read(sc, addr, cmdbuf, cmdlen, buf, buflen, flags, send_start);
 	} else {
@@ -413,9 +391,6 @@ rk_i2c_attach(device_t parent, device_t self, void *aux)
 		return;
 	}
 
-	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SCHED);
-	cv_init(&sc->sc_cv, "rkiic");
-
 	aprint_naive("\n");
 	aprint_normal(": Rockchip I2C (%u Hz)\n", sc->sc_clkfreq);
 
@@ -423,9 +398,8 @@ rk_i2c_attach(device_t parent, device_t self, void *aux)
 
 	rk_i2c_init(sc);
 
+	iic_tag_init(&sc->sc_ic);
 	sc->sc_ic.ic_cookie = sc;
-	sc->sc_ic.ic_acquire_bus = rk_i2c_acquire_bus;
-	sc->sc_ic.ic_release_bus = rk_i2c_release_bus;
 	sc->sc_ic.ic_exec = rk_i2c_exec;
 
 	fdtbus_register_i2c_controller(self, phandle, &rk_i2c_funcs);
diff --git a/sys/arch/arm/samsung/exynos_i2c.c b/sys/arch/arm/samsung/exynos_i2c.c
index 4b5e4af9e757..7d02c0762369 100644
--- a/sys/arch/arm/samsung/exynos_i2c.c
+++ b/sys/arch/arm/samsung/exynos_i2c.c
@@ -71,9 +71,6 @@ struct exynos_i2c_softc {
 
 static int	exynos_i2c_intr(void *);
 
-static int	exynos_i2c_acquire_bus(void *, int);
-static void	exynos_i2c_release_bus(void *, int);
-
 static int	exynos_i2c_send_start(void *, int);
 static int	exynos_i2c_send_stop(void *, int);
 static int	exynos_i2c_initiate_xfer(void *, i2c_addr_t, int);
@@ -173,9 +170,8 @@ exynos_i2c_attach(device_t parent, device_t self, void *aux)
 	}
 	aprint_normal_dev(self, "interrupting on %s\n", intrstr);
 	
+	iic_tag_init(&sc->sc_ic);
 	sc->sc_ic.ic_cookie = sc;
-	sc->sc_ic.ic_acquire_bus = exynos_i2c_acquire_bus;
-	sc->sc_ic.ic_release_bus = exynos_i2c_release_bus;
 	sc->sc_ic.ic_send_start  = exynos_i2c_send_start;
 	sc->sc_ic.ic_send_stop   = exynos_i2c_send_stop;
 	sc->sc_ic.ic_initiate_xfer = exynos_i2c_initiate_xfer;
@@ -213,23 +209,6 @@ exynos_i2c_intr(void *priv)
 	return 1;
 }
 
-static int
-exynos_i2c_acquire_bus(void *cookie, int flags)
-{
-	struct exynos_i2c_softc *i2c_sc = cookie;
-
-	mutex_enter(&i2c_sc->sc_lock);
-	return 0;
-}
-
-static void
-exynos_i2c_release_bus(void *cookie, int flags)
-{
-	struct exynos_i2c_softc *i2c_sc = cookie;
-
-	mutex_exit(&i2c_sc->sc_lock);
-}
-
 static int
 exynos_i2c_wait(struct exynos_i2c_softc *sc, int flags)
 {
@@ -265,46 +244,90 @@ exynos_i2c_wait(struct exynos_i2c_softc *sc, int flags)
 
 
 static int
-exynos_i2c_send_start(void *cookie, int flags)
+exynos_i2c_send_start_locked(struct exynos_i2c_softc *sc, int flags)
 {
-	struct exynos_i2c_softc *sc = cookie;
 	I2C_WRITE(sc, IICSTAT, 0xF0);
 	return 0;
 }
 
 static int
-exynos_i2c_send_stop(void *cookie, int flags)
+exynos_i2c_send_stop_locked(struct exynos_i2c_softc *sc, int flags)
 {
-	struct exynos_i2c_softc *sc = cookie;
 	I2C_WRITE(sc, IICSTAT, 0xD0);
 	return 0;
 }
 
+static int
+exynos_i2c_write_byte_locked(struct exynos_i2c_softc *sc, uint8_t byte,
+    int flags)
+{
+	int error = exynos_i2c_wait(sc, flags);
+	if (error) {
+		return error;
+	}
+	I2C_WRITE(sc, IICDS, byte);
+	return 0;
+}
+
+static int
+exynos_i2c_send_start(void *cookie, int flags)
+{
+	struct exynos_i2c_softc *sc = cookie;
+
+	mutex_enter(&sc->sc_lock);
+	int error = exynos_i2c_send_start_locked(sc, flags);
+	mutex_exit(&sc->sc_lock);
+	return error;
+}
+
+static int
+exynos_i2c_send_stop(void *cookie, int flags)
+{
+	struct exynos_i2c_softc *sc = cookie;
+
+	mutex_enter(&sc->sc_lock);
+	int error = exynos_i2c_send_stop_locked(sc, flags);
+	mutex_exit(&sc->sc_lock);
+	return error;
+}
+
 static int
 exynos_i2c_initiate_xfer(void *cookie, i2c_addr_t addr, int flags)
 {
 	struct exynos_i2c_softc *sc = cookie;
 	uint8_t byte = addr & 0x7f;
+	int error;
+
 	if (flags & I2C_F_READ)
 		byte |= READBIT;
 	else
 		byte &= ~READBIT;
+
+	mutex_enter(&sc->sc_lock);
 	I2C_WRITE(sc, IICADD, addr);
-	exynos_i2c_send_start(cookie, flags);
-	exynos_i2c_write_byte(cookie, byte, flags);
-	return exynos_i2c_wait(cookie, flags);
+	exynos_i2c_send_start_locked(sc, flags);
+	exynos_i2c_write_byte_locked(sc, byte, flags);
+	error = exynos_i2c_wait(cookie, flags);
+	mutex_exit(&sc->sc_lock);
+
+	return error;
 }
 
 static int
 exynos_i2c_read_byte(void *cookie, uint8_t *bytep, int flags)
 {
 	struct exynos_i2c_softc *sc = cookie;
+
+	mutex_enter(&sc->sc_lock);
 	int error = exynos_i2c_wait(sc, flags);
-	if (error)
+	if (error) {
+		mutex_exit(&sc->sc_lock);
 		return error;
+	}
 	*bytep = I2C_READ(sc, IICDS) & 0xff;
 	if (flags & I2C_F_STOP)
-		exynos_i2c_send_stop(cookie, flags);
+		exynos_i2c_send_stop_locked(sc, flags);
+	mutex_exit(&sc->sc_lock);
 	return 0;
 }
 
@@ -312,9 +335,9 @@ static int
 exynos_i2c_write_byte(void *cookie, uint8_t byte, int flags)
 {
 	struct exynos_i2c_softc *sc = cookie;
-	int error = exynos_i2c_wait(sc, flags);
-	if (error)
-		return error;
-	I2C_WRITE(sc, IICDS, byte);
-	return 0;
+
+	mutex_enter(&sc->sc_lock);
+	int error = exynos_i2c_write_byte_locked(sc, byte, flags);
+	mutex_exit(&sc->sc_lock);
+	return error;
 }
diff --git a/sys/arch/arm/sunxi/sunxi_hdmi.c b/sys/arch/arm/sunxi/sunxi_hdmi.c
index a84a7548571e..b8576b85dd9c 100644
--- a/sys/arch/arm/sunxi/sunxi_hdmi.c
+++ b/sys/arch/arm/sunxi/sunxi_hdmi.c
@@ -114,8 +114,6 @@ static const struct of_compat_data compat_data[] = {
 static int	sunxi_hdmi_match(device_t, cfdata_t, void *);
 static void	sunxi_hdmi_attach(device_t, device_t, void *);
 static void	sunxi_hdmi_i2c_init(struct sunxi_hdmi_softc *);
-static int	sunxi_hdmi_i2c_acquire_bus(void *, int);
-static void	sunxi_hdmi_i2c_release_bus(void *, int);
 static int	sunxi_hdmi_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *,
 				   size_t, void *, size_t, int);
 static int	sunxi_hdmi_i2c_xfer(void *, i2c_addr_t, uint8_t, uint8_t,
@@ -265,35 +263,11 @@ sunxi_hdmi_i2c_init(struct sunxi_hdmi_softc *sc)
 
 	mutex_init(&sc->sc_ic_lock, MUTEX_DEFAULT, IPL_NONE);
 
+	iic_tag_init(ic);
 	ic->ic_cookie = sc;
-	ic->ic_acquire_bus = sunxi_hdmi_i2c_acquire_bus;
-	ic->ic_release_bus = sunxi_hdmi_i2c_release_bus;
 	ic->ic_exec = sunxi_hdmi_i2c_exec;
 }
 
-static int
-sunxi_hdmi_i2c_acquire_bus(void *priv, int flags)
-{
-	struct sunxi_hdmi_softc *sc = priv;
-
-	if (flags & I2C_F_POLL) {
-		if (!mutex_tryenter(&sc->sc_ic_lock))
-			return EBUSY;
-	} else {
-		mutex_enter(&sc->sc_ic_lock);
-	}
-
-	return 0;
-}
-
-static void
-sunxi_hdmi_i2c_release_bus(void *priv, int flags)
-{
-	struct sunxi_hdmi_softc *sc = priv;
-
-	mutex_exit(&sc->sc_ic_lock);
-}
-
 static int
 sunxi_hdmi_i2c_exec(void *priv, i2c_op_t op, i2c_addr_t addr,
     const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
@@ -305,7 +279,8 @@ sunxi_hdmi_i2c_exec(void *priv, i2c_op_t op, i2c_addr_t addr,
 	off_t off;
 	int err;
 
-	KASSERT(mutex_owned(&sc->sc_ic_lock));
+	mutex_enter(&sc->sc_ic_lock);
+
 	KASSERT(op == I2C_OP_READ_WITH_STOP);
 	KASSERT(addr == DDC_ADDR);
 	KASSERT(cmdlen > 0);
@@ -349,6 +324,7 @@ sunxi_hdmi_i2c_exec(void *priv, i2c_op_t op, i2c_addr_t addr,
 	}
 
 done:
+	mutex_exit(&sc->sc_ic_lock);
 	return err;
 }
 
diff --git a/sys/arch/arm/sunxi/sunxi_rsb.c b/sys/arch/arm/sunxi/sunxi_rsb.c
index b7481f499f62..104bbe1bff3d 100644
--- a/sys/arch/arm/sunxi/sunxi_rsb.c
+++ b/sys/arch/arm/sunxi/sunxi_rsb.c
@@ -100,8 +100,6 @@ struct sunxi_rsb_softc {
 #define RSB_WRITE(sc, reg, val) \
     bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
 
-static int	sunxi_rsb_acquire_bus(void *, int);
-static void     sunxi_rsb_release_bus(void *, int);
 static int	sunxi_rsb_exec(void *, i2c_op_t, i2c_addr_t, const void *,
 			       size_t, void *, size_t, int);
 
@@ -192,9 +190,8 @@ sunxi_rsb_attach(device_t parent, device_t self, void *aux)
 	}
 	aprint_normal_dev(self, "interrupting on %s\n", intrstr);
 
+	iic_tag_init(&sc->sc_ic);
 	sc->sc_ic.ic_cookie = sc;
-	sc->sc_ic.ic_acquire_bus = sunxi_rsb_acquire_bus;
-	sc->sc_ic.ic_release_bus = sunxi_rsb_release_bus;
 	sc->sc_ic.ic_exec = sunxi_rsb_exec;
 
 	fdtbus_register_i2c_controller(self, phandle, &sunxi_rsb_funcs);
@@ -322,31 +319,6 @@ sunxi_rsb_rsb_config(struct sunxi_rsb_softc *sc, uint8_t rta, i2c_addr_t da,
 	return sunxi_rsb_wait(sc, flags);
 }
 
-static int
-sunxi_rsb_acquire_bus(void *priv, int flags)
-{
-	struct sunxi_rsb_softc *sc = priv;
-
-	for (;;) {
-		mutex_enter(&sc->sc_lock);
-		if (sc->sc_busy == false)
-			break;
-		mutex_exit(&sc->sc_lock);
-	}
-	sc->sc_busy = true;
-
-	return 0;
-}
-
-static void
-sunxi_rsb_release_bus(void *priv, int flags)
-{
-	struct sunxi_rsb_softc *sc = priv;
-
-	sc->sc_busy = false;
-	mutex_exit(&sc->sc_lock);
-}
-
 static int
 sunxi_rsb_exec(void *priv, i2c_op_t op, i2c_addr_t addr,
     const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
@@ -356,14 +328,14 @@ sunxi_rsb_exec(void *priv, i2c_op_t op, i2c_addr_t addr,
 	uint8_t rta;
 	int error, i;
 
-	KASSERT(mutex_owned(&sc->sc_lock));
-	KASSERT(sc->sc_busy == true);
-
 	if (cmdlen != 1 || (len != 1 && len != 2 && len != 4))
 		return EINVAL;
 
+	mutex_enter(&sc->sc_lock);
+
 	error = sunxi_rsb_soft_reset(sc);
 	if (error != 0) {
+		mutex_exit(&sc->sc_lock);
 		device_printf(sc->sc_dev, "soft reset timed out\n");
 		return error;
 	}
@@ -386,6 +358,7 @@ sunxi_rsb_exec(void *priv, i2c_op_t op, i2c_addr_t addr,
 				break;
 			}
 		if (rta == 0) {
+			mutex_exit(&sc->sc_lock);
 			device_printf(sc->sc_dev,
 			    "RTA not known for address %#x\n", addr);
 			return ENXIO;
@@ -492,6 +465,7 @@ sunxi_rsb_exec(void *priv, i2c_op_t op, i2c_addr_t addr,
 
 done:
 	RSB_WRITE(sc, RSB_CTRL_REG, 0);
+	mutex_exit(&sc->sc_lock);
 
 	return error;
 }
diff --git a/sys/arch/arm/xscale/i80312_i2c.c b/sys/arch/arm/xscale/i80312_i2c.c
index 666ac89ee72e..4680d4d52c41 100644
--- a/sys/arch/arm/xscale/i80312_i2c.c
+++ b/sys/arch/arm/xscale/i80312_i2c.c
@@ -91,8 +91,6 @@ iic312_attach(device_t parent, device_t self, void *aux)
 
 	/* XXX Reset the I2C unit? */
 
-	mutex_init(&sc->sc_buslock, MUTEX_DEFAULT, IPL_NONE);
-
 	/* XXX We don't currently use interrupts.  Fix this some day. */
 #if 0
 	sc->sc_ih = i80321_intr_establish(ICU_INT_I2C, IPL_BIO,
diff --git a/sys/arch/arm/xscale/i80321_i2c.c b/sys/arch/arm/xscale/i80321_i2c.c
index 4bdff17c72d8..48d38af4cf43 100644
--- a/sys/arch/arm/xscale/i80321_i2c.c
+++ b/sys/arch/arm/xscale/i80321_i2c.c
@@ -98,8 +98,6 @@ iic321_attach(device_t parent, device_t self, void *aux)
 
 	/* XXX Reset the I2C unit? */
 
-	mutex_init(&sc->sc_buslock, MUTEX_DEFAULT, IPL_NONE);
-
 	/* XXX We don't currently use interrupts.  Fix this some day. */
 #if 0
 	sc->sc_ih = i80321_intr_establish((ia->ia_offset == VERDE_I2C_BASE0) ?
diff --git a/sys/arch/arm/xscale/iopi2c.c b/sys/arch/arm/xscale/iopi2c.c
index a3101c4884fd..a1cc63046f38 100644
--- a/sys/arch/arm/xscale/iopi2c.c
+++ b/sys/arch/arm/xscale/iopi2c.c
@@ -56,9 +56,6 @@ __KERNEL_RCSID(0, "$NetBSD: iopi2c.c,v 1.8 2016/02/14 19:54:20 chs Exp $");
 #include <arm/xscale/iopi2creg.h>
 #include <arm/xscale/iopi2cvar.h>
 
-static int iopiic_acquire_bus(void *, int);
-static void iopiic_release_bus(void *, int);
-
 static int iopiic_send_start(void *, int);
 static int iopiic_send_stop(void *, int);
 static int iopiic_initiate_xfer(void *, uint16_t, int);
@@ -70,9 +67,8 @@ iopiic_attach(struct iopiic_softc *sc)
 {
 	struct i2cbus_attach_args iba;
 
+	iic_tag_init(&sc->sc_i2c);
 	sc->sc_i2c.ic_cookie = sc;
-	sc->sc_i2c.ic_acquire_bus = iopiic_acquire_bus;
-	sc->sc_i2c.ic_release_bus = iopiic_release_bus;
 	sc->sc_i2c.ic_send_start = iopiic_send_start;
 	sc->sc_i2c.ic_send_stop = iopiic_send_stop;
 	sc->sc_i2c.ic_initiate_xfer = iopiic_initiate_xfer;
@@ -84,31 +80,6 @@ iopiic_attach(struct iopiic_softc *sc)
 	(void) config_found_ia(sc->sc_dev, "i2cbus", &iba, iicbus_print);
 }
 
-static int
-iopiic_acquire_bus(void *cookie, int flags)
-{
-	struct iopiic_softc *sc = cookie;
-
-	/* XXX What should we do for the polling case? */
-	if (flags & I2C_F_POLL)
-		return (0);
-
-	mutex_enter(&sc->sc_buslock);
-	return (0);
-}
-
-static void
-iopiic_release_bus(void *cookie, int flags)
-{
-	struct iopiic_softc *sc = cookie;
-
-	/* XXX See above. */
-	if (flags & I2C_F_POLL)
-		return;
-
-	mutex_exit(&sc->sc_buslock);
-}
-
 #define	IOPIIC_TIMEOUT		100	/* protocol timeout, in uSecs */
 
 static int
diff --git a/sys/arch/arm/xscale/iopi2cvar.h b/sys/arch/arm/xscale/iopi2cvar.h
index e696a6213919..4a69295f562b 100644
--- a/sys/arch/arm/xscale/iopi2cvar.h
+++ b/sys/arch/arm/xscale/iopi2cvar.h
@@ -46,7 +46,6 @@ struct iopiic_softc {
 	void *sc_ih;
 
 	struct i2c_controller sc_i2c;
-	kmutex_t sc_buslock;
 	uint32_t sc_icr;
 };
 
diff --git a/sys/arch/evbarm/armadillo/armadillo9_iic.c b/sys/arch/evbarm/armadillo/armadillo9_iic.c
index 2e3b38157a90..d0bf65fab5c1 100644
--- a/sys/arch/evbarm/armadillo/armadillo9_iic.c
+++ b/sys/arch/evbarm/armadillo/armadillo9_iic.c
@@ -48,7 +48,6 @@ __KERNEL_RCSID(0, "$NetBSD: armadillo9_iic.c,v 1.8 2016/02/14 19:54:20 chs Exp $
 
 struct armadillo9iic_softc {
 	struct i2c_controller	sc_i2c;
-	kmutex_t		sc_buslock;
 	int			sc_port;
 	int			sc_sda;
 	int			sc_scl;
@@ -58,8 +57,6 @@ struct armadillo9iic_softc {
 static int armadillo9iic_match(device_t, cfdata_t, void *);
 static void armadillo9iic_attach(device_t, device_t, void *);
 
-static int armadillo9iic_acquire_bus(void *, int);
-static void armadillo9iic_release_bus(void *, int);
 static int armadillo9iic_send_start(void *, int);
 static int armadillo9iic_send_stop(void *, int);
 static int armadillo9iic_initiate_xfer(void *, uint16_t, int);
@@ -94,7 +91,6 @@ armadillo9iic_attach(device_t parent, device_t self, void *aux)
 #if NSEEPROM > 0
 	struct epgpio_attach_args *ga = aux;
 #endif
-	mutex_init(&sc->sc_buslock, MUTEX_DEFAULT, IPL_NONE);
 
 	sc->sc_port = ga->ga_port;
 	sc->sc_sda = ga->ga_bit1;
@@ -106,9 +102,8 @@ armadillo9iic_attach(device_t parent, device_t self, void *aux)
 	armadillo9iic_bbops.ibo_bits[I2C_BIT_OUTPUT] = sc->sc_sda;
 	armadillo9iic_bbops.ibo_bits[I2C_BIT_INPUT] = 0;
 
+	iic_tag_init(&sc->sc_i2c);
 	sc->sc_i2c.ic_cookie = sc;
-	sc->sc_i2c.ic_acquire_bus = armadillo9iic_acquire_bus;
-	sc->sc_i2c.ic_release_bus = armadillo9iic_release_bus;
 	sc->sc_i2c.ic_send_start = armadillo9iic_send_start;
 	sc->sc_i2c.ic_send_stop = armadillo9iic_send_stop;
 	sc->sc_i2c.ic_initiate_xfer = armadillo9iic_initiate_xfer;
@@ -137,31 +132,6 @@ armadillo9iic_attach(device_t parent, device_t self, void *aux)
 #endif
 }
 
-int
-armadillo9iic_acquire_bus(void *cookie, int flags)
-{
-	struct armadillo9iic_softc *sc = cookie;
-
-	/* XXX What should we do for the polling case? */
-	if (flags & I2C_F_POLL)
-		return 0;
-
-	mutex_enter(&sc->sc_buslock);
-	return 0;
-}
-
-void
-armadillo9iic_release_bus(void *cookie, int flags)
-{
-	struct armadillo9iic_softc *sc = cookie;
-
-	/* XXX See above. */
-	if (flags & I2C_F_POLL)
-		return;
-
-	mutex_exit(&sc->sc_buslock);
-}
-
 int
 armadillo9iic_send_start(void *cookie, int flags)
 {
diff --git a/sys/arch/evbarm/gumstix/gxiic.c b/sys/arch/evbarm/gumstix/gxiic.c
index bec33f41d2ee..ac2279084c4d 100644
--- a/sys/arch/evbarm/gumstix/gxiic.c
+++ b/sys/arch/evbarm/gumstix/gxiic.c
@@ -44,7 +44,6 @@ struct gxiic_softc {
 	struct pxa2x0_i2c_softc sc_pxa_i2c;
 
 	struct i2c_controller sc_i2c;
-	kmutex_t sc_lock;
 };
 
 
@@ -96,17 +95,11 @@ gxiicattach(device_t parent, device_t self, void *aux)
 		return;
 	}
 
-	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
-
 	/* Initialize i2c_controller  */
+	iic_tag_init(&sc->sc_i2c);
 	sc->sc_i2c.ic_cookie = sc;
 	sc->sc_i2c.ic_acquire_bus = gxiic_acquire_bus;
 	sc->sc_i2c.ic_release_bus = gxiic_release_bus;
-	sc->sc_i2c.ic_send_start = NULL;
-	sc->sc_i2c.ic_send_stop = NULL;
-	sc->sc_i2c.ic_initiate_xfer = NULL;
-	sc->sc_i2c.ic_read_byte = NULL;
-	sc->sc_i2c.ic_write_byte = NULL;
 	sc->sc_i2c.ic_exec = gxiic_exec;
 
 	memset(&iba, 0, sizeof(iba));
@@ -121,7 +114,6 @@ gxiic_acquire_bus(void *cookie, int flags)
 {
 	struct gxiic_softc *sc = cookie;
 
-	mutex_enter(&sc->sc_lock);
 	pxa2x0_i2c_open(&sc->sc_pxa_i2c);
 
 	return 0;
@@ -133,8 +125,6 @@ gxiic_release_bus(void *cookie, int flags)
 	struct gxiic_softc *sc = cookie;
 
 	pxa2x0_i2c_close(&sc->sc_pxa_i2c);
-	mutex_exit(&sc->sc_lock);
-	return;
 }
 
 static int
diff --git a/sys/arch/evbarm/nslu2/nslu2_iic.c b/sys/arch/evbarm/nslu2/nslu2_iic.c
index 141d54ccd1aa..f90a7fd070a1 100644
--- a/sys/arch/evbarm/nslu2/nslu2_iic.c
+++ b/sys/arch/evbarm/nslu2/nslu2_iic.c
@@ -47,33 +47,9 @@
 struct slugiic_softc {
 	struct i2c_controller sc_ic;
 	struct i2c_bitbang_ops sc_ibo;
-	kmutex_t sc_lock;
 	uint32_t sc_dirout;
 };
 
-static int
-slugiic_acquire_bus(void *arg, int flags)
-{
-	struct slugiic_softc *sc = arg;
-
-	if (flags & I2C_F_POLL)
-		return (0);
-
-	mutex_enter(&sc->sc_lock);
-	return (0);
-}
-
-static void
-slugiic_release_bus(void *arg, int flags)
-{
-	struct slugiic_softc *sc = arg;
-
-	if (flags & I2C_F_POLL)
-		return;
-
-	mutex_exit(&sc->sc_lock);
-}
-
 static int
 slugiic_send_start(void *arg, int flags)
 {
@@ -230,10 +206,8 @@ slugiic_attach(device_t parent, device_t self, void *aux)
 	aprint_naive("\n");
 	aprint_normal(": I2C bus\n");
 
+	iic_tag_init(&sc->sc_ic);
 	sc->sc_ic.ic_cookie = sc;
-	sc->sc_ic.ic_acquire_bus = slugiic_acquire_bus;
-	sc->sc_ic.ic_release_bus = slugiic_release_bus;
-	sc->sc_ic.ic_exec = NULL;
 	sc->sc_ic.ic_send_start = slugiic_send_start;
 	sc->sc_ic.ic_send_stop = slugiic_send_stop;
 	sc->sc_ic.ic_initiate_xfer = slugiic_initiate_xfer;
@@ -248,8 +222,6 @@ slugiic_attach(device_t parent, device_t self, void *aux)
 	sc->sc_ibo.ibo_bits[I2C_BIT_OUTPUT] = 1;
 	sc->sc_ibo.ibo_bits[I2C_BIT_INPUT] = 0;
 
-	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
-
 	sc->sc_dirout = 0;
 
 	/*
diff --git a/sys/arch/hpcarm/dev/nbpiic.c b/sys/arch/hpcarm/dev/nbpiic.c
index bad24ec70bc3..9e696d622f95 100644
--- a/sys/arch/hpcarm/dev/nbpiic.c
+++ b/sys/arch/hpcarm/dev/nbpiic.c
@@ -64,8 +64,6 @@ static int nbpiic_intr(void *);
 int nbpiic_poll(void *, int, char *);
 
 /* fuctions for i2c_controller */
-static int nbpiic_acquire_bus(void *, int);
-static void nbpiic_release_bus(void *, int);
 static int nbpiic_exec(void *cookie, i2c_op_t, i2c_addr_t, const void *, size_t,
     void *, size_t, int);
 
@@ -110,7 +108,11 @@ pxaiic_attach(device_t parent, device_t self, void *aux)
 		return;
 	}
 
-	/* Initialize mutex with IPL_HIGH.  Keyboard was connected to us. */
+	/*
+	 * Initialize mutex with IPL_HIGH.  Keyboard was connected to us.
+	 * This is orthogonal to the lock held at the i2c layer; this
+	 * is just to interlock us with the keyboard interrupt.
+	 */
 	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_HIGH);
 
 	ih = pxa2x0_intr_establish(pxa->pxa_intr, IPL_HIGH, nbpiic_intr, sc);
@@ -120,14 +122,8 @@ pxaiic_attach(device_t parent, device_t self, void *aux)
 	}
 
 	/* Initialize i2c_controller  */
+	iic_tag_init(&sc->sc_i2c);
 	sc->sc_i2c.ic_cookie = sc;
-	sc->sc_i2c.ic_acquire_bus = nbpiic_acquire_bus;
-	sc->sc_i2c.ic_release_bus = nbpiic_release_bus;
-	sc->sc_i2c.ic_send_start = NULL;
-	sc->sc_i2c.ic_send_stop = NULL;
-	sc->sc_i2c.ic_initiate_xfer = NULL;
-	sc->sc_i2c.ic_read_byte = NULL;
-	sc->sc_i2c.ic_write_byte = NULL;
 	sc->sc_i2c.ic_exec = nbpiic_exec;
 
 	memset(&iba, 0, sizeof(iba));
@@ -183,26 +179,6 @@ nbpiic_poll(void *cookie, int buflen, char *buf)
 	return rv;
 }
 
-static int
-nbpiic_acquire_bus(void *cookie, int flags)
-{
-	struct nbpiic_softc *sc = cookie;
-
-	mutex_enter(&sc->sc_lock);
-
-	return 0;
-}
-
-static void
-nbpiic_release_bus(void *cookie, int flags)
-{
-	struct nbpiic_softc *sc = cookie;
-
-	mutex_exit(&sc->sc_lock);
-
-	return;
-}
-
 static int
 nbpiic_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *vcmd,
 	    size_t cmdlen, void *vbuf, size_t buflen, int flags)
@@ -211,6 +187,8 @@ nbpiic_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *vcmd,
 	int rv = -1;
 	const u_char cmd = *(const u_char *)vcmd; 
 
+	mutex_enter(&sc->sc_lock);
+
 	if (I2C_OP_READ_P(op) && (cmdlen == 0) && (buflen == 1))
 		rv = pxa2x0_i2c_read(&sc->sc_pxa_i2c, addr, (u_char *)vbuf);
 
@@ -257,5 +235,7 @@ printf("%s: write cmdlen=1, buflen=2: Ooops, maybe error...\n", __func__);
 		rv = pxa2x0_i2c_quick(&sc->sc_pxa_i2c, addr,
 			I2C_OP_READ_P(op) ? 1 : 0);
 
+	mutex_exit(&sc->sc_lock);
+
 	return rv;
 }
diff --git a/sys/arch/i386/pci/viapcib.c b/sys/arch/i386/pci/viapcib.c
index dbc2779747cc..d902bf754143 100644
--- a/sys/arch/i386/pci/viapcib.c
+++ b/sys/arch/i386/pci/viapcib.c
@@ -90,8 +90,6 @@ struct viapcib_softc {
 	struct i2c_controller sc_i2c;
 
 	int sc_revision;
-
-	kmutex_t sc_lock;
 };
 
 static int	viapcib_match(device_t, cfdata_t, void *);
@@ -107,8 +105,6 @@ static int	viapcib_busy(struct viapcib_softc *);
 
 #define	VIAPCIB_SMBUS_TIMEOUT	10000
 
-static int	viapcib_acquire_bus(void *, int);
-static void	viapcib_release_bus(void *, int);
 static int	viapcib_exec(void *, i2c_op_t, i2c_addr_t, const void *,
 			     size_t, void *, size_t, int);
 
@@ -171,8 +167,6 @@ viapcib_attach(device_t parent, device_t self, void *opaque)
 		goto core_pcib;
 	}
 
-	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
-
 	val = pci_conf_read(pa->pa_pc, pa->pa_tag, SMB_HOST_CONFIG);
 	if ((val & 0x10000) == 0) {
 		printf(": SMBus is disabled\n");
@@ -214,15 +208,10 @@ core_pcib:
 		b = viapcib_smbus_read(sc, SMBSLVCNT);
 		viapcib_smbus_write(sc, SMBSLVCNT, b & ~1);
 
-		memset(&sc->sc_i2c, 0, sizeof(sc->sc_i2c));
 		memset(&iba, 0, sizeof(iba));
-#ifdef I2C_TYPE_SMBUS
-		iba.iba_type = I2C_TYPE_SMBUS;
-#endif
 		iba.iba_tag = &sc->sc_i2c;
+		iic_tag_init(&sc->sc_i2c);
 		iba.iba_tag->ic_cookie = (void *)sc;
-		iba.iba_tag->ic_acquire_bus = viapcib_acquire_bus;
-		iba.iba_tag->ic_release_bus = viapcib_release_bus;
 		iba.iba_tag->ic_exec = viapcib_exec;
 
 		config_found_ia(self, "i2cbus", &iba, iicbus_print);
@@ -278,26 +267,6 @@ viapcib_busy(struct viapcib_softc *sc)
 	return (val & SMBHSTSTS_BUSY);
 }
 
-static int
-viapcib_acquire_bus(void *opaque, int flags)
-{
-	struct viapcib_softc *sc = (struct viapcib_softc *)opaque;
-
-	DPRINTF(("viapcib_i2c_acquire_bus(%p, 0x%x)\n", opaque, flags));
-	mutex_enter(&sc->sc_lock);
-
-	return 0;
-}
-
-static void
-viapcib_release_bus(void *opaque, int flags)
-{
-	struct viapcib_softc *sc = (struct viapcib_softc *)opaque;
-
-	mutex_exit(&sc->sc_lock);
-	DPRINTF(("viapcib_i2c_release_bus(%p, 0x%x)\n", opaque, flags));
-}
-
 static int
 viapcib_exec(void *opaque, i2c_op_t op, i2c_addr_t addr, const void *vcmd,
     size_t cmdlen, void *vbuf, size_t buflen, int flags)
diff --git a/sys/arch/macppc/dev/cuda.c b/sys/arch/macppc/dev/cuda.c
index 638667c74e2c..b36be8fea32b 100644
--- a/sys/arch/macppc/dev/cuda.c
+++ b/sys/arch/macppc/dev/cuda.c
@@ -79,7 +79,6 @@ struct cuda_softc {
 	struct todr_chip_handle sc_todr;
 	struct adb_bus_accessops sc_adbops;
 	struct i2c_controller sc_i2c;
-	kmutex_t sc_buslock;
 	bus_space_tag_t sc_memt;
 	bus_space_handle_t sc_memh;
 	int sc_node;
@@ -145,8 +144,6 @@ static 	int cuda_adb_send(void *, int, int, int, uint8_t *);
 static	int cuda_adb_set_handler(void *, void (*)(void *, int, uint8_t *), void *);
 
 /* i2c stuff */
-static int cuda_i2c_acquire_bus(void *, int);
-static void cuda_i2c_release_bus(void *, int);
 static int cuda_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t,
 		    void *, size_t, int);
 
@@ -277,17 +274,10 @@ cuda_attach(device_t parent, device_t self, void *aux)
 		prop_object_release(dev);
 	}
 
-	mutex_init(&sc->sc_buslock, MUTEX_DEFAULT, IPL_NONE);
 	memset(&iba, 0, sizeof(iba));
 	iba.iba_tag = &sc->sc_i2c;
+	iic_tag_init(&sc->sc_i2c);
 	sc->sc_i2c.ic_cookie = sc;
-	sc->sc_i2c.ic_acquire_bus = cuda_i2c_acquire_bus;
-	sc->sc_i2c.ic_release_bus = cuda_i2c_release_bus;
-	sc->sc_i2c.ic_send_start = NULL;
-	sc->sc_i2c.ic_send_stop = NULL;
-	sc->sc_i2c.ic_initiate_xfer = NULL;
-	sc->sc_i2c.ic_read_byte = NULL;
-	sc->sc_i2c.ic_write_byte = NULL;
 	sc->sc_i2c.ic_exec = cuda_i2c_exec;
 	config_found_ia(self, "i2cbus", &iba, iicbus_print);
 
@@ -938,23 +928,6 @@ cuda_adb_set_handler(void *cookie, void (*handler)(void *, int, uint8_t *),
 
 /* i2c message handling */
 
-static int
-cuda_i2c_acquire_bus(void *cookie, int flags)
-{
-	struct cuda_softc *sc = cookie;
-
-	mutex_enter(&sc->sc_buslock);
-	return 0;
-}
-
-static void
-cuda_i2c_release_bus(void *cookie, int flags)
-{
-	struct cuda_softc *sc = cookie;
-
-	mutex_exit(&sc->sc_buslock);
-}
-
 static int
 cuda_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *_send,
     size_t send_len, void *_recv, size_t recv_len, int flags)
diff --git a/sys/arch/macppc/dev/ki2c.c b/sys/arch/macppc/dev/ki2c.c
index aa8687c8a8ce..2b603cb91afb 100644
--- a/sys/arch/macppc/dev/ki2c.c
+++ b/sys/arch/macppc/dev/ki2c.c
@@ -58,8 +58,6 @@ int ki2c_read(struct ki2c_softc *, int, int, void *, int);
 int ki2c_write(struct ki2c_softc *, int, int, void *, int);
 
 /* I2C glue */
-static int ki2c_i2c_acquire_bus(void *, int);
-static void ki2c_i2c_release_bus(void *, int);
 static int ki2c_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t,
 		    void *, size_t, int);
 
@@ -126,7 +124,6 @@ ki2c_attach(device_t parent, device_t self, void *aux)
 	ki2c_setmode(sc, I2C_STDSUBMODE);
 	ki2c_setspeed(sc, I2C_100kHz);		/* XXX rate */
 	
-	mutex_init(&sc->sc_buslock, MUTEX_DEFAULT, IPL_NONE);
 	ki2c_writereg(sc, IER,I2C_INT_DATA|I2C_INT_ADDR|I2C_INT_STOP);
 	
 	cfg = prop_array_create();
@@ -197,14 +194,8 @@ ki2c_attach(device_t parent, device_t self, void *aux)
 	}
 
 	/* fill in the i2c tag */
+	iic_tag_init(&sc->sc_i2c);
 	sc->sc_i2c.ic_cookie = sc;
-	sc->sc_i2c.ic_acquire_bus = ki2c_i2c_acquire_bus;
-	sc->sc_i2c.ic_release_bus = ki2c_i2c_release_bus;
-	sc->sc_i2c.ic_send_start = NULL;
-	sc->sc_i2c.ic_send_stop = NULL;
-	sc->sc_i2c.ic_initiate_xfer = NULL;
-	sc->sc_i2c.ic_read_byte = NULL;
-	sc->sc_i2c.ic_write_byte = NULL;
 	sc->sc_i2c.ic_exec = ki2c_i2c_exec;
 
 	memset(&iba, 0, sizeof(iba));
@@ -389,23 +380,6 @@ ki2c_write(struct ki2c_softc *sc, int addr, int subaddr, void *data, int len)
 	return ki2c_start(sc, addr, subaddr, data, len);
 }
 
-static int
-ki2c_i2c_acquire_bus(void *cookie, int flags)
-{
-	struct ki2c_softc *sc = cookie;
-
-	mutex_enter(&sc->sc_buslock);
-	return 0;
-}
-
-static void
-ki2c_i2c_release_bus(void *cookie, int flags)
-{
-	struct ki2c_softc *sc = cookie;
-
-	mutex_exit(&sc->sc_buslock);
-}
-
 int
 ki2c_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *vcmd,
     size_t cmdlen, void *vbuf, size_t buflen, int flags)
diff --git a/sys/arch/macppc/dev/pmu.c b/sys/arch/macppc/dev/pmu.c
index 2f30415d135e..a0c463938a35 100644
--- a/sys/arch/macppc/dev/pmu.c
+++ b/sys/arch/macppc/dev/pmu.c
@@ -85,7 +85,6 @@ struct pmu_softc {
 	struct todr_chip_handle sc_todr;
 	struct adb_bus_accessops sc_adbops;
 	struct i2c_controller sc_i2c;
-	kmutex_t sc_i2c_lock;
 	struct pmu_ops sc_pmu_ops;
 	struct sysmon_pswitch sc_lidswitch;
 	struct sysmon_pswitch sc_powerbutton;
@@ -147,8 +146,6 @@ static 	int pmu_adb_send(void *, int, int, int, uint8_t *);
 static	int pmu_adb_set_handler(void *, void (*)(void *, int, uint8_t *), void *);
 
 /* i2c stuff */
-static int pmu_i2c_acquire_bus(void *, int);
-static void pmu_i2c_release_bus(void *, int);
 static int pmu_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t,
 		    void *, size_t, int);
 
@@ -381,15 +378,8 @@ pmu_attach(device_t parent, device_t self, void *aux)
 			}
 			memset(&iba, 0, sizeof(iba));
 			iba.iba_tag = &sc->sc_i2c;
-			mutex_init(&sc->sc_i2c_lock, MUTEX_DEFAULT, IPL_NONE);
+			iic_tag_init(&sc->sc_i2c);
 			sc->sc_i2c.ic_cookie = sc;
-			sc->sc_i2c.ic_acquire_bus = pmu_i2c_acquire_bus;
-			sc->sc_i2c.ic_release_bus = pmu_i2c_release_bus;
-			sc->sc_i2c.ic_send_start = NULL;
-			sc->sc_i2c.ic_send_stop = NULL;
-			sc->sc_i2c.ic_initiate_xfer = NULL;
-			sc->sc_i2c.ic_read_byte = NULL;
-			sc->sc_i2c.ic_write_byte = NULL;
 			sc->sc_i2c.ic_exec = pmu_i2c_exec;
 			config_found_ia(sc->sc_dev, "i2cbus", &iba,
 			    iicbus_print);
@@ -925,24 +915,6 @@ pmu_adb_set_handler(void *cookie, void (*handler)(void *, int, uint8_t *),
 	return 0;
 }
 
-static int
-pmu_i2c_acquire_bus(void *cookie, int flags)
-{
-	struct pmu_softc *sc = cookie;
-
-	mutex_enter(&sc->sc_i2c_lock);
-
-	return 0;
-}
-
-static void
-pmu_i2c_release_bus(void *cookie, int flags)
-{
-	struct pmu_softc *sc = cookie;
-
-	mutex_exit(&sc->sc_i2c_lock);
-}
-
 static int
 pmu_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *_send,
     size_t send_len, void *_recv, size_t recv_len, int flags)
diff --git a/sys/arch/macppc/dev/smu.c b/sys/arch/macppc/dev/smu.c
index 7a90fef48824..51f9e20a19a8 100644
--- a/sys/arch/macppc/dev/smu.c
+++ b/sys/arch/macppc/dev/smu.c
@@ -113,7 +113,6 @@ struct smu_softc {
 	int sc_num_fans;
 	struct smu_fan sc_fans[SMU_MAX_FANS];
 
-	kmutex_t sc_iicbus_lock;
 	int sc_num_iicbus;
 	struct smu_iicbus sc_iicbus[SMU_MAX_IICBUS];
 
@@ -166,8 +165,6 @@ static int smu_todr_settime_ymdhms(todr_chip_handle_t, struct clock_ymdhms *);
 static int smu_fan_update_rpm(struct smu_fan *);
 static int smu_fan_get_rpm(struct smu_fan *, int *);
 static int smu_fan_set_rpm(struct smu_fan *, int);
-static int smu_iicbus_acquire_bus(void *, int);
-static void smu_iicbus_release_bus(void *, int);
 static int smu_iicbus_exec(void *, i2c_op_t, i2c_addr_t, const void *,
     size_t, void *, size_t, int);
 static int smu_sysctl_fan_rpm(SYSCTLFN_ARGS);
@@ -434,8 +431,6 @@ smu_setup_iicbus(struct smu_softc *sc)
 	int node;
 	char name[32];
 
-	mutex_init(&sc->sc_iicbus_lock, MUTEX_DEFAULT, IPL_NONE);
-
 	node = of_getnode_byname(sc->sc_node, "smu-i2c-control");
 	for (node = OF_child(node);
 	    (node != 0) && (sc->sc_num_iicbus < SMU_MAX_IICBUS);
@@ -454,14 +449,8 @@ smu_setup_iicbus(struct smu_softc *sc)
 
 		DPRINTF("iicbus: reg %x\n", iicbus->reg);
 
+		iic_tag_init(i2c);
 		i2c->ic_cookie = iicbus;
-		i2c->ic_acquire_bus = smu_iicbus_acquire_bus;
-		i2c->ic_release_bus = smu_iicbus_release_bus;
-		i2c->ic_send_start = NULL;
-		i2c->ic_send_stop = NULL;
-		i2c->ic_initiate_xfer = NULL;
-		i2c->ic_read_byte = NULL;
-		i2c->ic_write_byte = NULL;
 		i2c->ic_exec = smu_iicbus_exec;
 
 		ca.ca_name = name;
@@ -772,26 +761,6 @@ smu_fan_set_rpm(struct smu_fan *fan, int rpm)
 	return ret;
 }
 
-static int
-smu_iicbus_acquire_bus(void *cookie, int flags)
-{
-	struct smu_iicbus *iicbus = cookie;
-	struct smu_softc *sc = iicbus->sc;
-
-	mutex_enter(&sc->sc_iicbus_lock);
-
-	return 0;
-}
-
-static void
-smu_iicbus_release_bus(void *cookie, int flags)
-{
-	struct smu_iicbus *iicbus = cookie;
-	struct smu_softc *sc = iicbus->sc;
-
-	mutex_exit(&sc->sc_iicbus_lock);
-}
-
 static int
 smu_iicbus_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *send,
     size_t send_len, void *recv, size_t recv_len, int flags)
diff --git a/sys/arch/macppc/macppc/memory.c b/sys/arch/macppc/macppc/memory.c
index 5e041da6cb42..053d1b433285 100644
--- a/sys/arch/macppc/macppc/memory.c
+++ b/sys/arch/macppc/macppc/memory.c
@@ -75,8 +75,6 @@ void	memory_attach(device_t, device_t, void *);
 CFATTACH_DECL_NEW(memory, sizeof(struct memory_softc), memory_match, memory_attach,
               NULL, NULL);
 
-int	memory_i2c_acquire_bus(void *, int);
-void	memory_i2c_release_bus(void *, int);
 int	memory_i2c_exec(void *, i2c_op_t, i2c_addr_t,
    	                const void *, size_t, void *, size_t, int);
 
@@ -116,10 +114,8 @@ memory_attach(device_t parent, device_t self, void *aux)
 
 		OF_getprop(ca->ca_node, "dimm-info", sc->sc_buf, sc->sc_len);
 
-		memset(&ic, 0, sizeof ic);
+		iic_tag_init(&ic);
 		ic.ic_cookie = sc;
-		ic.ic_acquire_bus = memory_i2c_acquire_bus;
-		ic.ic_release_bus = memory_i2c_release_bus;
 		ic.ic_exec = memory_i2c_exec;
 
 		memset(&ia, 0, sizeof ia);
@@ -140,20 +136,10 @@ memory_attach(device_t parent, device_t self, void *aux)
 		/* No need to keep the "dimm-info" contents around. */
 		free(sc->sc_buf, M_DEVBUF);
 		sc->sc_len = -1;
+		iic_tag_fini(&ic);
 	}
 }
 
-int
-memory_i2c_acquire_bus(void *cookie, int flags)
-{
-	return (0);
-}
-
-void
-memory_i2c_release_bus(void *cookie, int flags)
-{
-}
-
 int
 memory_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr,
                 const void *cmdbuf, size_t cmdlen, 
diff --git a/sys/arch/mips/alchemy/dev/ausmbus_psc.c b/sys/arch/mips/alchemy/dev/ausmbus_psc.c
index 2e1a561a9888..a7c71b994989 100644
--- a/sys/arch/mips/alchemy/dev/ausmbus_psc.c
+++ b/sys/arch/mips/alchemy/dev/ausmbus_psc.c
@@ -126,14 +126,10 @@ ausmbus_attach(device_t parent, device_t self, void *aux)
 	sc->sc_ctrl = aa->aupsc_ctrl;
 
 	/* Initialize i2c_controller for SMBus */
+	iic_tag_init(&sc->sc_i2c);
 	sc->sc_i2c.ic_cookie = sc;
 	sc->sc_i2c.ic_acquire_bus = ausmbus_acquire_bus;
 	sc->sc_i2c.ic_release_bus = ausmbus_release_bus;
-	sc->sc_i2c.ic_send_start = NULL;
-	sc->sc_i2c.ic_send_stop = NULL;
-	sc->sc_i2c.ic_initiate_xfer = NULL;
-	sc->sc_i2c.ic_read_byte = NULL;
-	sc->sc_i2c.ic_write_byte = NULL;
 	sc->sc_i2c.ic_exec = ausmbus_exec;
 	sc->sc_smbus_timeout = 10;
 
diff --git a/sys/arch/mips/ingenic/jziic.c b/sys/arch/mips/ingenic/jziic.c
index a6bcd05d2292..749f6dc2ad2c 100644
--- a/sys/arch/mips/ingenic/jziic.c
+++ b/sys/arch/mips/ingenic/jziic.c
@@ -69,7 +69,7 @@ struct jziic_softc {
 	bus_space_tag_t 	sc_memt;
 	bus_space_handle_t 	sc_memh;
 	struct i2c_controller 	sc_i2c;
-	kmutex_t		sc_buslock, sc_cvlock;
+	kmutex_t		sc_cvlock;
 	uint32_t		sc_pclk;
 	/* stuff used for interrupt-driven transfers */
 	const uint8_t		*sc_cmd;
@@ -89,8 +89,6 @@ STATIC int jziic_enable(struct jziic_softc *);
 STATIC void jziic_disable(struct jziic_softc *);
 STATIC int jziic_wait(struct jziic_softc *);
 STATIC void jziic_set_speed(struct jziic_softc *);
-STATIC int jziic_i2c_acquire_bus(void *, int);
-STATIC void jziic_i2c_release_bus(void *, int);
 STATIC int jziic_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t,
 		    void *, size_t, int);
 STATIC int jziic_i2c_exec_poll(struct jziic_softc *, i2c_op_t, i2c_addr_t,
@@ -138,7 +136,6 @@ jziic_attach(device_t parent, device_t self, void *aux)
 		return;
 	}
 
-	mutex_init(&sc->sc_buslock, MUTEX_DEFAULT, IPL_NONE);
 	mutex_init(&sc->sc_cvlock, MUTEX_DEFAULT, IPL_NONE);
 	cv_init(&sc->sc_ping, device_xname(self));
 
@@ -175,14 +172,8 @@ jziic_attach(device_t parent, device_t self, void *aux)
 #endif
 
 	/* fill in the i2c tag */
+	iic_tag_init(&sc->sc_i2c);
 	sc->sc_i2c.ic_cookie = sc;
-	sc->sc_i2c.ic_acquire_bus = jziic_i2c_acquire_bus;
-	sc->sc_i2c.ic_release_bus = jziic_i2c_release_bus;
-	sc->sc_i2c.ic_send_start = NULL;
-	sc->sc_i2c.ic_send_stop = NULL;
-	sc->sc_i2c.ic_initiate_xfer = NULL;
-	sc->sc_i2c.ic_read_byte = NULL;
-	sc->sc_i2c.ic_write_byte = NULL;
 	sc->sc_i2c.ic_exec = jziic_i2c_exec;
 
 	memset(&iba, 0, sizeof(iba));
@@ -232,23 +223,6 @@ jziic_disable(struct jziic_softc *sc)
 	DPRINTF("bail: %d\n", bail);
 }
 
-STATIC int
-jziic_i2c_acquire_bus(void *cookie, int flags)
-{
-	struct jziic_softc *sc = cookie;
-
-	mutex_enter(&sc->sc_buslock);
-	return 0;
-}
-
-STATIC void
-jziic_i2c_release_bus(void *cookie, int flags)
-{
-	struct jziic_softc *sc = cookie;
-
-	mutex_exit(&sc->sc_buslock);
-}
-
 STATIC int
 jziic_wait(struct jziic_softc *sc)
 {
diff --git a/sys/arch/mips/ralink/ralink_i2c.c b/sys/arch/mips/ralink/ralink_i2c.c
index 34cd3e426a3c..17a12de88b46 100644
--- a/sys/arch/mips/ralink/ralink_i2c.c
+++ b/sys/arch/mips/ralink/ralink_i2c.c
@@ -86,8 +86,6 @@ static void i2c_read_stop(ra_i2c_softc_t *, u_long, u_char *);
 #endif
 
 /* i2c driver functions */
-int  ra_i2c_acquire_bus(void *, int);
-void ra_i2c_release_bus(void *, int);
 int  ra_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t,
 	void *, size_t, int);
 void ra_i2c_reset(ra_i2c_softc_t *);
@@ -155,13 +153,11 @@ ra_i2c_attach(device_t parent, device_t self, void *aux)
 	bus_space_write_4(sc->sc_memt, sc->sc_sy_memh,
 		RA_SYSCTL_GPIOMODE, r);
 
+	iic_tag_init(&sc->sc_i2c);
 	sc->sc_i2c.ic_cookie = sc;
-	sc->sc_i2c.ic_acquire_bus = ra_i2c_acquire_bus;
-	sc->sc_i2c.ic_release_bus = ra_i2c_release_bus;
 	sc->sc_i2c.ic_exec = ra_i2c_exec;
 
 	memset(&iba, 0, sizeof(iba));
-	iba.iba_type = I2C_TYPE_SMBUS;
 	iba.iba_tag = &sc->sc_i2c;
 	config_found(self, &iba, iicbus_print);
 }
@@ -172,23 +168,6 @@ ra_i2c_attach(device_t parent, device_t self, void *aux)
  * I2C API
  */
 
-/* Might not be needed.  JCL. */
-int
-ra_i2c_acquire_bus(void *cookie, int flags)
-{
-	/* nothing */
-	return 0;
-}
-
-
-
-/* Might not be needed.  JCL. */
-void
-ra_i2c_release_bus(void *cookie, int flags)
-{
-	/* nothing */
-}
-
 int
 ra_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *cmdbuf,
 	size_t cmdlen, void *buf, size_t len, int flags)
diff --git a/sys/arch/mmeye/dev/rtciic.c b/sys/arch/mmeye/dev/rtciic.c
index e8083b07d1a1..3063e8122a3b 100644
--- a/sys/arch/mmeye/dev/rtciic.c
+++ b/sys/arch/mmeye/dev/rtciic.c
@@ -72,8 +72,6 @@ struct rtciic_softc {
 static int rtciic_match(device_t, cfdata_t , void *);
 static void rtciic_attach(device_t, device_t, void *);
 
-static int rtciic_acquire_bus(void *, int);
-static void rtciic_release_bus(void *, int);
 static int rtciic_send_start(void *, int);
 static int rtciic_send_stop(void *, int);
 static int rtciic_initiate_xfer(void *, i2c_addr_t, int);
@@ -127,10 +125,8 @@ rtciic_attach(device_t parent, device_t self, void *aux)
 	sc->sc_rw = RTCIIC_READ(sc) & RTCIIC_RW;
 
 	/* register with iic */
+	iic_tag_init(&sc->sc_i2c);
 	sc->sc_i2c.ic_cookie = sc;
-	sc->sc_i2c.ic_acquire_bus = rtciic_acquire_bus;
-	sc->sc_i2c.ic_release_bus = rtciic_release_bus;
-	sc->sc_i2c.ic_exec = NULL;
 	sc->sc_i2c.ic_send_start = rtciic_send_start;
 	sc->sc_i2c.ic_send_stop = rtciic_send_stop;
 	sc->sc_i2c.ic_initiate_xfer = rtciic_initiate_xfer;
@@ -150,20 +146,6 @@ rtciic_attach(device_t parent, device_t self, void *aux)
 	(void) config_found_ia(sc->sc_dev, "i2cbus", &iba, iicbus_print);
 }
 
-
-static int
-rtciic_acquire_bus(void *cookie, int flags)
-{
-
-	return 0;
-}
-
-static void
-rtciic_release_bus(void *cookie, int flags)
-{
-	/* nothing */
-}
-
 static int
 rtciic_send_start(void *arg, int flags)
 {
diff --git a/sys/arch/powerpc/ibm4xx/dev/gpiic_opb.c b/sys/arch/powerpc/ibm4xx/dev/gpiic_opb.c
index 897fe63935c1..b3b383906534 100644
--- a/sys/arch/powerpc/ibm4xx/dev/gpiic_opb.c
+++ b/sys/arch/powerpc/ibm4xx/dev/gpiic_opb.c
@@ -59,7 +59,6 @@ struct gpiic_softc {
 	uint8_t sc_tx;
 	struct i2c_controller sc_i2c;
 	struct i2c_bitbang_ops sc_bops;
-	kmutex_t sc_buslock;
 };
 
 static int	gpiic_match(device_t, cfdata_t, void *);
@@ -68,8 +67,6 @@ static void	gpiic_attach(device_t, device_t, void *);
 CFATTACH_DECL_NEW(gpiic, sizeof(struct gpiic_softc),
     gpiic_match, gpiic_attach, NULL, NULL);
 
-static int	gpiic_acquire_bus(void *, int);
-static void	gpiic_release_bus(void *, int);
 static int	gpiic_send_start(void *, int);
 static int	gpiic_send_stop(void *, int);
 static int	gpiic_initiate_xfer(void *, i2c_addr_t, int);
@@ -105,14 +102,10 @@ gpiic_attach(device_t parent, device_t self, void *args)
 
 	bus_space_map(sc->sc_bust, oaa->opb_addr, IIC_NREG, 0, &sc->sc_bush);
 
-	mutex_init(&sc->sc_buslock, MUTEX_DEFAULT, IPL_NONE);
-
 	sc->sc_txen = 0;
 	sc->sc_tx = IIC_DIRECTCNTL_SCC | IIC_DIRECTCNTL_SDAC;
+	iic_tag_init(&sc->sc_i2c);
 	sc->sc_i2c.ic_cookie = sc;
-	sc->sc_i2c.ic_acquire_bus = gpiic_acquire_bus;
-	sc->sc_i2c.ic_release_bus = gpiic_release_bus;
-	sc->sc_i2c.ic_exec = NULL;
 	sc->sc_i2c.ic_send_start = gpiic_send_start;
 	sc->sc_i2c.ic_send_stop = gpiic_send_stop;
 	sc->sc_i2c.ic_initiate_xfer = gpiic_initiate_xfer;
@@ -142,29 +135,6 @@ gpiic_attach(device_t parent, device_t self, void *args)
 	(void) config_found_ia(self, "i2cbus", &iba, iicbus_print);
 }
 
-static int
-gpiic_acquire_bus(void *arg, int flags)
-{
-	struct gpiic_softc * const sc = arg;
-
-	if (flags & I2C_F_POLL)
-		return (0);
-
-	mutex_enter(&sc->sc_buslock);
-	return (0);
-}
-
-static void
-gpiic_release_bus(void *arg, int flags)
-{
-	struct gpiic_softc * const sc = arg;
-
-	if (flags & I2C_F_POLL)
-		return;
-
-	mutex_exit(&sc->sc_buslock);
-}
-
 static int
 gpiic_send_start(void *arg, int flags)
 {
diff --git a/sys/arch/sgimips/dev/crmfb.c b/sys/arch/sgimips/dev/crmfb.c
index a3c6d8086247..8089a8d2f7ec 100644
--- a/sys/arch/sgimips/dev/crmfb.c
+++ b/sys/arch/sgimips/dev/crmfb.c
@@ -204,8 +204,6 @@ static void	crmfb_putchar(void *, int, int, u_int, long);
 static void	crmfb_putchar_aa(void *, int, int, u_int, long);
 
 /* I2C glue */
-static int crmfb_i2c_acquire_bus(void *, int);
-static void crmfb_i2c_release_bus(void *, int);
 static int crmfb_i2c_send_start(void *, int);
 static int crmfb_i2c_send_stop(void *, int);
 static int crmfb_i2c_initiate_xfer(void *, i2c_addr_t, int);
@@ -1617,15 +1615,13 @@ crmfb_setup_ddc(struct crmfb_softc *sc)
 	int i;
 
 	memset(sc->sc_edid_data, 0, 128);
+	iic_tag_init(&sc->sc_i2c);
 	sc->sc_i2c.ic_cookie = sc;
-	sc->sc_i2c.ic_acquire_bus = crmfb_i2c_acquire_bus;
-	sc->sc_i2c.ic_release_bus = crmfb_i2c_release_bus;
 	sc->sc_i2c.ic_send_start = crmfb_i2c_send_start;
 	sc->sc_i2c.ic_send_stop = crmfb_i2c_send_stop;
 	sc->sc_i2c.ic_initiate_xfer = crmfb_i2c_initiate_xfer;
 	sc->sc_i2c.ic_read_byte = crmfb_i2c_read_byte;
 	sc->sc_i2c.ic_write_byte = crmfb_i2c_write_byte;
-	sc->sc_i2c.ic_exec = NULL;
 	i = 0;
 	while (sc->sc_edid_data[1] == 0 && i++ < 10)
 		ddc_read_edid(&sc->sc_i2c, sc->sc_edid_data, 128);
@@ -1662,22 +1658,6 @@ crmfb_i2cbb_read(void *cookie)
 	return bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_I2C_VGA) ^ 3;
 }
 
-/* higher level I2C stuff */
-static int
-crmfb_i2c_acquire_bus(void *cookie, int flags)
-{
-
-	/* private bus */
-	return 0;
-}
-
-static void
-crmfb_i2c_release_bus(void *cookie, int flags)
-{
-
-	/* private bus */
-}
-
 static int
 crmfb_i2c_send_start(void *cookie, int flags)
 {
diff --git a/sys/arch/sparc64/dev/ffb.c b/sys/arch/sparc64/dev/ffb.c
index f77caa3f8c85..4f430d282ac1 100644
--- a/sys/arch/sparc64/dev/ffb.c
+++ b/sys/arch/sparc64/dev/ffb.c
@@ -157,8 +157,6 @@ struct wsdisplay_accessops ffb_accessops = {
 };
 
 /* I2C glue */
-static int ffb_i2c_acquire_bus(void *, int);
-static void ffb_i2c_release_bus(void *, int);
 static int ffb_i2c_send_start(void *, int);
 static int ffb_i2c_send_stop(void *, int);
 static int ffb_i2c_initiate_xfer(void *, i2c_addr_t, int);
@@ -387,15 +385,13 @@ ffb_attach_i2c(struct ffb_softc *sc)
 {
 
 	/* Fill in the i2c tag */
+	iic_tag_init(&sc->sc_i2c);
 	sc->sc_i2c.ic_cookie = sc;
-	sc->sc_i2c.ic_acquire_bus = ffb_i2c_acquire_bus;
-	sc->sc_i2c.ic_release_bus = ffb_i2c_release_bus;
 	sc->sc_i2c.ic_send_start = ffb_i2c_send_start;
 	sc->sc_i2c.ic_send_stop = ffb_i2c_send_stop;
 	sc->sc_i2c.ic_initiate_xfer = ffb_i2c_initiate_xfer;
 	sc->sc_i2c.ic_read_byte = ffb_i2c_read_byte;
 	sc->sc_i2c.ic_write_byte = ffb_i2c_write_byte;
-	sc->sc_i2c.ic_exec = NULL;
 }
 
 int
@@ -1313,19 +1309,6 @@ static uint32_t ffb_i2cbb_read(void *cookie)
 }
 
 /* higher level I2C stuff */
-static int
-ffb_i2c_acquire_bus(void *cookie, int flags)
-{
-	/* private bus */
-	return (0);
-}
-
-static void
-ffb_i2c_release_bus(void *cookie, int flags)
-{
-	/* private bus */
-}
-
 static int
 ffb_i2c_send_start(void *cookie, int flags)
 {
diff --git a/sys/arch/sparc64/dev/jbus-i2c.c b/sys/arch/sparc64/dev/jbus-i2c.c
index 19fefe86dabe..6c678b8772c9 100644
--- a/sys/arch/sparc64/dev/jbus-i2c.c
+++ b/sys/arch/sparc64/dev/jbus-i2c.c
@@ -48,8 +48,6 @@ __KERNEL_RCSID(0, "$NetBSD: jbus-i2c.c,v 1.3 2018/11/03 14:56:36 martin Exp $");
 #endif
 
 /* I2C glue */
-static int jbusi2c_i2c_acquire_bus(void *, int);
-static void jbusi2c_i2c_release_bus(void *, int);
 static int jbusi2c_i2c_send_start(void *, int);
 static int jbusi2c_i2c_send_stop(void *, int);
 static int jbusi2c_i2c_initiate_xfer(void *, i2c_addr_t, int);
@@ -79,7 +77,6 @@ static	void	jbusi2c_attach(device_t, device_t, void *);
 struct jbusi2c_softc {
 	device_t sc_dev;
 	struct i2c_controller sc_i2c;
-	kmutex_t sc_i2c_lock;
 	bus_space_tag_t sc_bustag;
 	bus_space_handle_t sc_regh;
 	int sc_node;
@@ -144,15 +141,13 @@ jbusi2c_setup_i2c(struct jbusi2c_softc *sc)
 	int devs, regs[2], addr;
 	char name[64], compat[256];
 
+	iic_tag_init(&sc->sc_i2c);
 	sc->sc_i2c.ic_cookie = sc;
-	sc->sc_i2c.ic_acquire_bus = jbusi2c_i2c_acquire_bus;
-	sc->sc_i2c.ic_release_bus = jbusi2c_i2c_release_bus;
 	sc->sc_i2c.ic_send_start = jbusi2c_i2c_send_start;
 	sc->sc_i2c.ic_send_stop = jbusi2c_i2c_send_stop;
 	sc->sc_i2c.ic_initiate_xfer = jbusi2c_i2c_initiate_xfer;
 	sc->sc_i2c.ic_read_byte = jbusi2c_i2c_read_byte;
 	sc->sc_i2c.ic_write_byte = jbusi2c_i2c_write_byte;
-	sc->sc_i2c.ic_exec = NULL;
 
 	/* round up i2c devices */
 	devs = OF_child(sc->sc_node);
@@ -185,7 +180,6 @@ jbusi2c_setup_i2c(struct jbusi2c_softc *sc)
 	}
 	memset(&iba, 0, sizeof(iba));
 	iba.iba_tag = &sc->sc_i2c;
-	mutex_init(&sc->sc_i2c_lock, MUTEX_DEFAULT, IPL_NONE);
 	config_found_ia(sc->sc_dev, "i2cbus", &iba,
 	    iicbus_print);
 }
@@ -228,23 +222,6 @@ jbusi2c_i2cbb_read(void *cookie)
 }
 
 /* higher level I2C stuff */
-static int
-jbusi2c_i2c_acquire_bus(void *cookie, int flags)
-{
-	struct jbusi2c_softc *sc = cookie;
-
-	mutex_enter(&sc->sc_i2c_lock);
-	return 0;
-}
-
-static void
-jbusi2c_i2c_release_bus(void *cookie, int flags)
-{
-	struct jbusi2c_softc *sc = cookie;
-
-	mutex_exit(&sc->sc_i2c_lock);
-}
-
 static int
 jbusi2c_i2c_send_start(void *cookie, int flags)
 {
diff --git a/sys/arch/x86/acpi/acpi_cpu_md.c b/sys/arch/x86/acpi/acpi_cpu_md.c
index cc7dacee925e..1a2a575a60f8 100644
--- a/sys/arch/x86/acpi/acpi_cpu_md.c
+++ b/sys/arch/x86/acpi/acpi_cpu_md.c
@@ -378,7 +378,6 @@ acpicpu_md_cstate_stop(void)
 {
 	static char text[16];
 	void (*func)(void);
-	uint64_t xc;
 	bool ipi;
 
 	x86_cpu_idle_get(&func, text, sizeof(text));
@@ -393,8 +392,7 @@ acpicpu_md_cstate_stop(void)
 	 * Run a cross-call to ensure that all CPUs are
 	 * out from the ACPI idle-loop before detachment.
 	 */
-	xc = xc_broadcast(0, (xcfunc_t)nullop, NULL, NULL);
-	xc_wait(xc);
+	xc_barrier(0);
 
 	return 0;
 }
diff --git a/sys/arch/x86/pci/imcsmb/imcsmb.c b/sys/arch/x86/pci/imcsmb/imcsmb.c
index 49aee059fa86..64af9c252812 100644
--- a/sys/arch/x86/pci/imcsmb/imcsmb.c
+++ b/sys/arch/x86/pci/imcsmb/imcsmb.c
@@ -130,7 +130,6 @@ imcsmb_attach(device_t parent, device_t self, void *aux)
 	sc->sc_regs = imca->ia_regs;
 	sc->sc_pci_tag = imca->ia_pci_tag;
 	sc->sc_pci_chipset_tag = imca->ia_pci_chipset_tag;
-	mutex_init(&sc->sc_i2c_mutex, MUTEX_DEFAULT, IPL_NONE);
 
 	if (!pmf_device_register(self, NULL, NULL))
 		aprint_error_dev(self, "couldn't establish power handler\n");
@@ -151,13 +150,13 @@ imcsmb_rescan(device_t self, const char *ifattr, const int *flags)
 	if (sc->sc_smbus != NULL)
 		return 0;
 
+	iic_tag_init(&sc->sc_i2c_tag);
 	sc->sc_i2c_tag.ic_cookie = sc;
 	sc->sc_i2c_tag.ic_acquire_bus = imcsmb_acquire_bus;
 	sc->sc_i2c_tag.ic_release_bus = imcsmb_release_bus;
 	sc->sc_i2c_tag.ic_exec = imcsmb_exec;
 
 	memset(&iba, 0, sizeof(iba));
-	iba.iba_type = I2C_TYPE_SMBUS;
 	iba.iba_tag = &sc->sc_i2c_tag;
 	sc->sc_smbus = config_found_ia(self, ifattr, &iba, iicbus_print);
 
@@ -196,7 +195,7 @@ imcsmb_detach(device_t self, int flags)
 	}
 
 	pmf_device_deregister(self);
-	mutex_destroy(&sc->sc_i2c_mutex);
+	iic_tag_fini(&sc->sc_i2c_tag);
 	return 0;
 }
 
@@ -224,8 +223,6 @@ imcsmb_acquire_bus(void *cookie, int flags)
 	if (cold)
 		return 0;
 
-	mutex_enter(&sc->sc_i2c_mutex);
-
 	imc_callback(sc, IMC_BIOS_DISABLE);
 
 	return 0;
@@ -240,8 +237,6 @@ imcsmb_release_bus(void *cookie, int flags)
 		return;
 
 	imc_callback(sc, IMC_BIOS_ENABLE);
-
-	mutex_exit(&sc->sc_i2c_mutex);
 }
 
 static int
diff --git a/sys/arch/zaurus/dev/ziic.c b/sys/arch/zaurus/dev/ziic.c
index 871b28a19064..897fa2790224 100644
--- a/sys/arch/zaurus/dev/ziic.c
+++ b/sys/arch/zaurus/dev/ziic.c
@@ -55,7 +55,6 @@ struct pxaiic_softc {
 	void *			sc_ih;
 
 	struct i2c_controller	sc_i2c;
-	kmutex_t		sc_buslock;
 };
 
 static int pxaiic_match(device_t, cfdata_t, void *);
@@ -106,9 +105,9 @@ pxaiic_attach(device_t parent, device_t self, void *aux)
 		return;
 	}
 
-	mutex_init(&sc->sc_buslock, MUTEX_DEFAULT, IPL_TTY);
-
 #if 0
+	mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_TTY);
+
 	sc->sc_ih = pxa2x0_intr_establish(PXA2X0_INT_I2C, IPL_TTY,
 	    pxa2x0_i2c_intr, &psc);
 	if (sc->sc_ih == NULL) {
@@ -118,6 +117,7 @@ pxaiic_attach(device_t parent, device_t self, void *aux)
 #endif
 
 	/* Initialize i2c_controller */
+	iic_tag_init(&sc->sc_i2c);
 	sc->sc_i2c.ic_cookie = sc;
 	sc->sc_i2c.ic_acquire_bus = pxaiic_acquire_bus;
 	sc->sc_i2c.ic_release_bus = pxaiic_release_bus;
@@ -126,7 +126,6 @@ pxaiic_attach(device_t parent, device_t self, void *aux)
 	sc->sc_i2c.ic_initiate_xfer = pxaiic_initiate_xfer;
 	sc->sc_i2c.ic_read_byte = pxaiic_read_byte;
 	sc->sc_i2c.ic_write_byte = pxaiic_write_byte;
-	sc->sc_i2c.ic_exec = NULL;
 
 	memset(&iba, 0, sizeof(iba));
 	iba.iba_tag = &sc->sc_i2c;
@@ -139,7 +138,6 @@ pxaiic_acquire_bus(void *cookie, int flags)
 	struct pxaiic_softc *sc = cookie;
 	struct pxa2x0_i2c_softc *psc = &sc->sc_pxa_i2c;
 
-	mutex_enter(&sc->sc_buslock);
 	pxa2x0_i2c_open(psc);
 
 	return 0;
@@ -152,7 +150,6 @@ pxaiic_release_bus(void *cookie, int flags)
 	struct pxa2x0_i2c_softc *psc = &sc->sc_pxa_i2c;
 
 	pxa2x0_i2c_close(psc);
-	mutex_exit(&sc->sc_buslock);
 }
 
 static int
diff --git a/sys/dev/acpi/smbus_acpi.c b/sys/dev/acpi/smbus_acpi.c
index 996cf6df70e5..80de62270b2f 100644
--- a/sys/dev/acpi/smbus_acpi.c
+++ b/sys/dev/acpi/smbus_acpi.c
@@ -73,7 +73,6 @@ struct acpi_smbus_softc {
 	struct callout		sc_callout;
 	struct i2c_controller	sc_i2c_tag;
 	device_t		sc_dv;
-	kmutex_t		sc_i2c_mutex;
 	int			sc_poll_alert;
 };
 
@@ -81,8 +80,6 @@ static int	acpi_smbus_match(device_t, cfdata_t, void *);
 static void	acpi_smbus_attach(device_t, device_t, void *);
 static int	acpi_smbus_detach(device_t, int);
 static int	acpi_smbus_poll_alert(ACPI_HANDLE, int *);
-static int	acpi_smbus_acquire_bus(void *, int);
-static void	acpi_smbus_release_bus(void *, int);
 static int	acpi_smbus_exec(void *, i2c_op_t, i2c_addr_t, const void *,
 				size_t, void *, size_t, int);
 static void	acpi_smbus_alerts(struct acpi_smbus_softc *);
@@ -151,11 +148,8 @@ acpi_smbus_attach(device_t parent, device_t self, void *aux)
 	sc->sc_poll_alert = 2;
 
 	/* Attach I2C bus. */
-	mutex_init(&sc->sc_i2c_mutex, MUTEX_DEFAULT, IPL_NONE);
-
+	iic_tag_init(&sc->sc_i2c_tag);
 	sc->sc_i2c_tag.ic_cookie = sc;
-	sc->sc_i2c_tag.ic_acquire_bus = acpi_smbus_acquire_bus;
-	sc->sc_i2c_tag.ic_release_bus = acpi_smbus_release_bus;
 	sc->sc_i2c_tag.ic_exec = acpi_smbus_exec;
 
 	(void)acpi_smbus_poll_alert(aa->aa_node->ad_handle,&sc->sc_poll_alert);
@@ -194,7 +188,7 @@ acpi_smbus_detach(device_t self, int flags)
 	callout_halt(&sc->sc_callout, NULL);
 	callout_destroy(&sc->sc_callout);
 
-	mutex_destroy(&sc->sc_i2c_mutex);
+	iic_tag_fini(&sc->sc_i2c_tag);
 
 	return 0;
 }
@@ -259,23 +253,6 @@ out:
 	return (ACPI_FAILURE(rv)) ? 0 : 1;
 }
 
-static int
-acpi_smbus_acquire_bus(void *cookie, int flags)
-{
-        struct acpi_smbus_softc *sc = cookie;
-
-        mutex_enter(&sc->sc_i2c_mutex);
-
-        return 0;
-}
-
-static void
-acpi_smbus_release_bus(void *cookie, int flags)
-{
-        struct acpi_smbus_softc *sc = cookie;
-
-        mutex_exit(&sc->sc_i2c_mutex);
-}
 static int
 acpi_smbus_exec(void *cookie, i2c_op_t op, i2c_addr_t addr,
 	const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
diff --git a/sys/dev/gpio/gpioiic.c b/sys/dev/gpio/gpioiic.c
index 0e676bd994a0..dc3be39a7bc8 100644
--- a/sys/dev/gpio/gpioiic.c
+++ b/sys/dev/gpio/gpioiic.c
@@ -54,7 +54,6 @@ struct gpioiic_softc {
 
 	struct i2c_controller	sc_i2c_tag;
 	device_t		sc_i2c_dev;
-	krwlock_t		sc_i2c_lock;
 
 	int			sc_pin_sda;
 	int			sc_pin_scl;
@@ -67,8 +66,6 @@ int		gpioiic_match(device_t, cfdata_t, void *);
 void		gpioiic_attach(device_t, device_t, void *);
 int		gpioiic_detach(device_t, int);
 
-int		gpioiic_i2c_acquire_bus(void *, int);
-void		gpioiic_i2c_release_bus(void *, int);
 int		gpioiic_i2c_send_start(void *, int);
 int		gpioiic_i2c_send_stop(void *, int);
 int		gpioiic_i2c_initiate_xfer(void *, i2c_addr_t, int);
@@ -185,19 +182,15 @@ gpioiic_attach(device_t parent, device_t self, void *aux)
 	aprint_normal("\n");
 
 	/* Attach I2C bus */
-	rw_init(&sc->sc_i2c_lock);
+	iic_tag_init(&sc->sc_i2c_tag);
 	sc->sc_i2c_tag.ic_cookie = sc;
-	sc->sc_i2c_tag.ic_acquire_bus = gpioiic_i2c_acquire_bus;
-	sc->sc_i2c_tag.ic_release_bus = gpioiic_i2c_release_bus;
 	sc->sc_i2c_tag.ic_send_start = gpioiic_i2c_send_start;
 	sc->sc_i2c_tag.ic_send_stop = gpioiic_i2c_send_stop;
 	sc->sc_i2c_tag.ic_initiate_xfer = gpioiic_i2c_initiate_xfer;
 	sc->sc_i2c_tag.ic_read_byte = gpioiic_i2c_read_byte;
 	sc->sc_i2c_tag.ic_write_byte = gpioiic_i2c_write_byte;
-	sc->sc_i2c_tag.ic_exec = NULL;
 
 	memset(&iba, 0, sizeof(iba));
-	iba.iba_type = I2C_TYPE_SMBUS;
 	iba.iba_tag = &sc->sc_i2c_tag;
 	sc->sc_i2c_dev = config_found(self, &iba, iicbus_print);
 
@@ -220,35 +213,13 @@ gpioiic_detach(device_t self, int flags)
 		rv = config_detach(sc->sc_i2c_dev, flags);
 
 	if (!rv) {
+		iic_tag_fini(&sc->sc_i2c_tag);
 		gpio_pin_unmap(sc->sc_gpio, &sc->sc_map);
 		pmf_device_deregister(self);
 	}
 	return rv;
 }
 
-int
-gpioiic_i2c_acquire_bus(void *cookie, int flags)
-{
-	struct gpioiic_softc *sc = cookie;
-
-	if (flags & I2C_F_POLL)
-		return 1;
-
-	rw_enter(&sc->sc_i2c_lock, RW_WRITER);
-	return 0;
-}
-
-void
-gpioiic_i2c_release_bus(void *cookie, int flags)
-{
-	struct gpioiic_softc *sc = cookie;
-
-	if (flags & I2C_F_POLL)
-		return;
-
-	rw_exit(&sc->sc_i2c_lock);
-}
-
 int
 gpioiic_i2c_send_start(void *cookie, int flags)
 {
diff --git a/sys/dev/i2c/gttwsi_core.c b/sys/dev/i2c/gttwsi_core.c
index 7ac6dff9bfb5..1b2041da05fa 100644
--- a/sys/dev/i2c/gttwsi_core.c
+++ b/sys/dev/i2c/gttwsi_core.c
@@ -83,8 +83,6 @@ __KERNEL_RCSID(0, "$NetBSD: gttwsi_core.c,v 1.8 2018/10/01 09:39:20 bouyer Exp $
 #include <dev/i2c/gttwsireg.h>
 #include <dev/i2c/gttwsivar.h>
 
-static int	gttwsi_acquire_bus(void *, int);
-static void	gttwsi_release_bus(void *, int);
 static int	gttwsi_send_start(void *v, int flags);
 static int	gttwsi_send_stop(void *v, int flags);
 static int	gttwsi_initiate_xfer(void *v, i2c_addr_t addr, int flags);
@@ -149,17 +147,14 @@ gttwsi_attach_subr(device_t self, bus_space_tag_t iot, bus_space_handle_t ioh)
 	if (sc->sc_reg_write == NULL)
 		sc->sc_reg_write = gttwsi_default_write_4;
 
-	mutex_init(&sc->sc_buslock, MUTEX_DEFAULT, IPL_VM);
 	mutex_init(&sc->sc_mtx, MUTEX_DEFAULT, IPL_BIO);
 	cv_init(&sc->sc_cv, device_xname(self));
 
 	prop_dictionary_get_bool(cfg, "iflg-rwc", &sc->sc_iflg_rwc);
 
 	sc->sc_started = false;
+	iic_tag_init(&sc->sc_i2c);
 	sc->sc_i2c.ic_cookie = sc;
-	sc->sc_i2c.ic_acquire_bus = gttwsi_acquire_bus;
-	sc->sc_i2c.ic_release_bus = gttwsi_release_bus;
-	sc->sc_i2c.ic_exec = NULL;
 	sc->sc_i2c.ic_send_start = gttwsi_send_start;
 	sc->sc_i2c.ic_send_stop = gttwsi_send_stop;
 	sc->sc_i2c.ic_initiate_xfer = gttwsi_initiate_xfer;
@@ -204,33 +199,6 @@ gttwsi_intr(void *arg)
 	return 0;
 }
 
-/* ARGSUSED */
-static int
-gttwsi_acquire_bus(void *arg, int flags)
-{
-	struct gttwsi_softc *sc = arg;
-
-	mutex_enter(&sc->sc_buslock);
-	while (sc->sc_inuse)
-		cv_wait(&sc->sc_cv, &sc->sc_buslock);
-	sc->sc_inuse = true;
-	mutex_exit(&sc->sc_buslock);
-
-	return 0;
-}
-
-/* ARGSUSED */
-static void
-gttwsi_release_bus(void *arg, int flags)
-{
-	struct gttwsi_softc *sc = arg;
-
-	mutex_enter(&sc->sc_buslock);
-	sc->sc_inuse = false;
-	cv_broadcast(&sc->sc_cv);
-	mutex_exit(&sc->sc_buslock);
-}
-
 static int
 gttwsi_send_start(void *v, int flags)
 {
diff --git a/sys/dev/i2c/i2c.c b/sys/dev/i2c/i2c.c
index fc5ca267d1d5..8add1ec56a06 100644
--- a/sys/dev/i2c/i2c.c
+++ b/sys/dev/i2c/i2c.c
@@ -69,7 +69,6 @@ __KERNEL_RCSID(0, "$NetBSD: i2c.c,v 1.69 2019/03/26 09:20:38 mlelstv Exp $");
 struct iic_softc {
 	device_t sc_dev;
 	i2c_tag_t sc_tag;
-	int sc_type;
 	device_t sc_devices[I2C_MAX_ADDR + 1];
 };
 
@@ -285,7 +284,6 @@ iic_search(device_t parent, cfdata_t cf, const int *ldesc, void *aux)
 	}
 
 	ia.ia_tag = sc->sc_tag;
-	ia.ia_type = sc->sc_type;
 
 	ia.ia_name = NULL;
 	ia.ia_ncompat = 0;
@@ -409,7 +407,6 @@ iic_attach(device_t parent, device_t self, void *aux)
 
 	sc->sc_dev = self;
 	sc->sc_tag = iba->iba_tag;
-	sc->sc_type = iba->iba_type;
 	ic = sc->sc_tag;
 	ic->ic_devname = device_xname(self);
 
@@ -464,7 +461,6 @@ iic_attach(device_t parent, device_t self, void *aux)
 
 			memset(&ia, 0, sizeof ia);
 			ia.ia_addr = addr;
-			ia.ia_type = sc->sc_type;
 			ia.ia_tag = ic;
 			ia.ia_name = name;
 			ia.ia_cookie = cookie;
diff --git a/sys/dev/i2c/i2c_exec.c b/sys/dev/i2c/i2c_exec.c
index 885673d6d5db..32bb627f4611 100644
--- a/sys/dev/i2c/i2c_exec.c
+++ b/sys/dev/i2c/i2c_exec.c
@@ -61,6 +61,33 @@ iic_op_flags(int flags)
 	return flags | (cold ? I2C_F_POLL : 0);
 }
 
+/*
+ * iic_tag_init:
+ *
+ *	Perform some basic initialization of the i2c controller tag.
+ */
+void
+iic_tag_init(i2c_tag_t tag)
+{
+
+	memset(tag, 0, sizeof(*tag));
+	mutex_init(&tag->ic_bus_lock, MUTEX_DEFAULT, IPL_NONE);
+	LIST_INIT(&tag->ic_list);
+	LIST_INIT(&tag->ic_proc_list);
+}
+
+/*
+ * iic_tag_fini:
+ *
+ *	Teardown of the i2c controller tag.
+ */
+void
+iic_tag_fini(i2c_tag_t tag)
+{
+
+	mutex_destroy(&tag->ic_bus_lock);
+}
+
 /*
  * iic_acquire_bus:
  *
@@ -72,7 +99,44 @@ iic_acquire_bus(i2c_tag_t tag, int flags)
 
 	flags = iic_op_flags(flags);
 
-	return (*tag->ic_acquire_bus)(tag->ic_cookie, flags);
+	if (flags & I2C_F_POLL) {
+		/*
+		 * Polling should only be used in rare and/or
+		 * extreme circumstances; most i2c clients
+		 * should be allowed to sleep.
+		 *
+		 * Really, the ONLY user of I2C_F_POLL should be
+		 * "when cold", i.e. during early autoconfiguration
+		 * when there is only proc0, and we might have to
+		 * read SEEPROMs, etc.  There should be no other
+		 * users interfering with our access of the i2c bus
+		 * in that case.
+		 */
+		if (mutex_tryenter(&tag->ic_bus_lock) == 0) {
+			return EBUSY;
+		}
+	} else {
+		/*
+		 * N.B. We implement this as a mutex that we hold across
+		 * across a series of requests beause we'd like to get the
+		 * priority boost if a higher-priority process wants the
+		 * i2c bus while we're asleep waiting for the controller
+		 * to perform the I/O.
+		 *
+		 * XXXJRT Disable preemption here?  We'd like to keep
+		 * the CPU while holding this resource, unless we release
+		 * it voluntarily (which should only happen while waiting
+		 * for a controller to complete I/O).
+		 */
+		mutex_enter(&tag->ic_bus_lock);
+	}
+
+	int error = 0;
+	if (tag->ic_acquire_bus) {
+		error = (*tag->ic_acquire_bus)(tag->ic_cookie, flags);
+	}
+
+	return error;
 }
 
 /*
@@ -86,7 +150,11 @@ iic_release_bus(i2c_tag_t tag, int flags)
 
 	flags = iic_op_flags(flags);
 
-	(*tag->ic_release_bus)(tag->ic_cookie, flags);
+	if (tag->ic_release_bus) {
+		(*tag->ic_release_bus)(tag->ic_cookie, flags);
+	}
+
+	mutex_exit(&tag->ic_bus_lock);
 }
 
 /*
diff --git a/sys/dev/i2c/i2cvar.h b/sys/dev/i2c/i2cvar.h
index 13b019399847..24063d35a915 100644
--- a/sys/dev/i2c/i2cvar.h
+++ b/sys/dev/i2c/i2cvar.h
@@ -39,6 +39,7 @@
 #define	_DEV_I2C_I2CVAR_H_
 
 #include <sys/device.h>
+#include <sys/mutex.h>
 #include <dev/i2c/i2c_io.h>
 #include <prop/proplib.h>
 
@@ -90,10 +91,12 @@ typedef struct i2c_controller {
 	 * the driver is finished, it should release the
 	 * bus.
 	 *
-	 * This is provided by the back-end since a single
-	 * controller may present e.g. i2c and smbus views
-	 * of the same set of i2c wires.
+	 * The main synchronization logic is handled by the
+	 * generic i2c layer, but optional hooks to back-end
+	 * drivers are provided in case additional processing
+	 * is needed (e.g. enabling the i2c controller).
 	 */
+	kmutex_t ic_bus_lock;
 	int	(*ic_acquire_bus)(void *, int);
 	void	(*ic_release_bus)(void *, int);
 
@@ -119,13 +122,9 @@ typedef struct i2c_controller {
 	const char *ic_devname;
 } *i2c_tag_t;
 
-/* I2C bus types */
-#define	I2C_TYPE_SMBUS	1
-
 /* Used to attach the i2c framework to the controller. */
 struct i2cbus_attach_args {
 	i2c_tag_t iba_tag;		/* the controller */
-	int iba_type;			/* bus type */
 	prop_array_t iba_child_devices;	/* child devices (direct config) */
 };
 
@@ -159,6 +158,8 @@ struct i2c_attach_args {
  * API presented to i2c controllers.
  */
 int	iicbus_print(void *, const char *);
+void	iic_tag_init(i2c_tag_t);
+void	iic_tag_fini(i2c_tag_t);
 
 /*
  * API presented to i2c devices.
diff --git a/sys/dev/i2c/motoi2c.c b/sys/dev/i2c/motoi2c.c
index fda4f8485aee..c93eaf51ec32 100644
--- a/sys/dev/i2c/motoi2c.c
+++ b/sys/dev/i2c/motoi2c.c
@@ -78,12 +78,6 @@ static int  motoi2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t,
 		void *, size_t, int);
 static int  motoi2c_busy_wait(struct motoi2c_softc *, uint8_t);
 
-static const struct i2c_controller motoi2c = {
-	.ic_acquire_bus = motoi2c_acquire_bus,
-	.ic_release_bus = motoi2c_release_bus,
-	.ic_exec	= motoi2c_exec,
-};
-
 static const struct motoi2c_settings motoi2c_default_settings = {
 	.i2c_adr	= MOTOI2C_ADR_DEFAULT,
 	.i2c_fdr	= MOTOI2C_FDR_DEFAULT,
@@ -113,13 +107,14 @@ motoi2c_attach_common(device_t self, struct motoi2c_softc *sc,
 {
 	struct i2cbus_attach_args iba;
 
-	mutex_init(&sc->sc_buslock, MUTEX_DEFAULT, IPL_NONE);
-
 	if (i2c == NULL)
 		i2c = &motoi2c_default_settings;
 
-	sc->sc_i2c = motoi2c;
+	iic_tag_init(&sc->sc_i2c);
 	sc->sc_i2c.ic_cookie = sc;
+	sc->sc_i2c.ic_acquire_bus = motoi2c_acquire_bus;
+	sc->sc_i2c.ic_release_bus = motoi2c_release_bus;
+	sc->sc_i2c.ic_exec = motoi2c_exec;
 	if (sc->sc_iord == NULL)
 		sc->sc_iord = motoi2c_iord1;
 	if (sc->sc_iowr == NULL)
@@ -148,7 +143,6 @@ motoi2c_acquire_bus(void *v, int flags)
 {
 	struct motoi2c_softc * const sc = v;
 
-	mutex_enter(&sc->sc_buslock);
 	I2C_WRITE(I2CCR, CR_MEN);	/* enable the I2C module */
 
 	return 0;
@@ -160,7 +154,6 @@ motoi2c_release_bus(void *v, int flags)
 	struct motoi2c_softc * const sc = v;
 
 	I2C_WRITE(I2CCR, 0);		/* reset before changing anything */
-	mutex_exit(&sc->sc_buslock);
 }
 
 /* busy waiting for byte data transfer completion */
diff --git a/sys/dev/i2c/motoi2cvar.h b/sys/dev/i2c/motoi2cvar.h
index 847449bb9985..9a19060f44f6 100644
--- a/sys/dev/i2c/motoi2cvar.h
+++ b/sys/dev/i2c/motoi2cvar.h
@@ -48,7 +48,6 @@ struct motoi2c_softc {
 	bus_space_tag_t		sc_iot;
 	bus_space_handle_t	sc_ioh;
 	struct i2c_controller	sc_i2c;
-	kmutex_t		sc_buslock;
 	motoi2c_iord_t		sc_iord;
 	motoi2c_iowr_t		sc_iowr;
 	int			sc_phandle;
diff --git a/sys/dev/ic/dw_hdmi.c b/sys/dev/ic/dw_hdmi.c
index ac3747026368..8c02ffdae3d2 100644
--- a/sys/dev/ic/dw_hdmi.c
+++ b/sys/dev/ic/dw_hdmi.c
@@ -187,24 +187,6 @@ __KERNEL_RCSID(0, "$NetBSD: dw_hdmi.c,v 1.1 2019/01/30 01:19:49 jmcneill Exp $")
 #define	 HDMI_I2CM_SOFTRSTZ_I2C_SOFTRST		__BIT(0)
 #define	HDMI_I2CM_SEGPTR	0x7e0a
 
-static int
-dwhdmi_ddc_acquire_bus(void *priv, int flags)
-{
-	struct dwhdmi_softc * const sc = priv;
-
-	mutex_enter(&sc->sc_ic_lock);
-
-	return 0;
-}
-
-static void
-dwhdmi_ddc_release_bus(void *priv, int flags)
-{
-	struct dwhdmi_softc * const sc = priv;
-
-	mutex_exit(&sc->sc_ic_lock);
-}
-
 static int
 dwhdmi_ddc_exec(void *priv, i2c_op_t op, i2c_addr_t addr,
     const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
@@ -214,8 +196,6 @@ dwhdmi_ddc_exec(void *priv, i2c_op_t op, i2c_addr_t addr,
 	uint8_t *pbuf = buf;
 	int off, n, retry;
 
-	KASSERT(mutex_owned(&sc->sc_ic_lock));
-
 	if (addr != DDC_ADDR || op != I2C_OP_READ_WITH_STOP || cmdlen == 0 || buf == NULL) {
 		printf("dwhdmi_ddc_exec: bad args addr=%#x op=%#x cmdlen=%d buf=%p\n",
 		    addr, op, (int)cmdlen, buf);
@@ -631,11 +611,8 @@ dwhdmi_attach(struct dwhdmi_softc *sc)
 		return EINVAL;
 	}
 
-	mutex_init(&sc->sc_ic_lock, MUTEX_DEFAULT, IPL_NONE);
-
+	iic_tag_init(ic);
 	ic->ic_cookie = sc;
-	ic->ic_acquire_bus = dwhdmi_ddc_acquire_bus;
-	ic->ic_release_bus = dwhdmi_ddc_release_bus;
 	ic->ic_exec = dwhdmi_ddc_exec;
 
 	return 0;
diff --git a/sys/dev/ic/dwiic.c b/sys/dev/ic/dwiic.c
index b7e32fe8d6ed..1670163377c1 100644
--- a/sys/dev/ic/dwiic.c
+++ b/sys/dev/ic/dwiic.c
@@ -145,8 +145,6 @@ __KERNEL_RCSID(0, "$NetBSD: dwiic.c,v 1.5 2018/09/26 19:06:33 jakllsch Exp $");
 
 static int	dwiic_init(struct dwiic_softc *);
 static void	dwiic_enable(struct dwiic_softc *, bool);
-static int	dwiic_i2c_acquire_bus(void *, int);
-static void	dwiic_i2c_release_bus(void *, int);
 static uint32_t	dwiic_read(struct dwiic_softc *, int);
 static void	dwiic_write(struct dwiic_softc *, int, uint32_t);
 static int	dwiic_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *,
@@ -184,16 +182,14 @@ dwiic_attach(struct dwiic_softc *sc)
 	dwiic_enable(sc, 0);
 	dwiic_read(sc, DW_IC_CLR_INTR);
 
-	mutex_init(&sc->sc_i2c_lock, MUTEX_DEFAULT, IPL_NONE);
 	mutex_init(&sc->sc_int_lock, MUTEX_DEFAULT, IPL_VM);
 	cv_init(&sc->sc_int_readwait, "dwiicr");
 	cv_init(&sc->sc_int_writewait, "dwiicw");
 	cv_init(&sc->sc_int_stopwait, "dwiics");
 
 	/* setup and attach iic bus */
+	iic_tag_init(&sc->sc_i2c_tag);
 	sc->sc_i2c_tag.ic_cookie = sc;
-	sc->sc_i2c_tag.ic_acquire_bus = dwiic_i2c_acquire_bus;
-	sc->sc_i2c_tag.ic_release_bus = dwiic_i2c_release_bus;
 	sc->sc_i2c_tag.ic_exec = dwiic_i2c_exec;
 
 	sc->sc_iba.iba_tag = &sc->sc_i2c_tag;
@@ -269,29 +265,6 @@ dwiic_write(struct dwiic_softc *sc, int offset, uint32_t val)
 	    val));
 }
 
-static int
-dwiic_i2c_acquire_bus(void *cookie, int flags)
-{
-	struct dwiic_softc *sc = cookie;
-
-	if (cold || sc->sc_poll || (flags & I2C_F_POLL))
-		return (0);
-
-	mutex_enter(&sc->sc_i2c_lock);
-	return 0;
-}
-
-void
-dwiic_i2c_release_bus(void *cookie, int flags)
-{
-	struct dwiic_softc *sc = cookie;
-
-	if (cold || sc->sc_poll || (flags & I2C_F_POLL))
-		return;
-
-	mutex_exit(&sc->sc_i2c_lock);
-}
-
 static int
 dwiic_init(struct dwiic_softc *sc)
 {
diff --git a/sys/dev/ic/pca9564.c b/sys/dev/ic/pca9564.c
index 70e421db1fd6..62b664889dd1 100644
--- a/sys/dev/ic/pca9564.c
+++ b/sys/dev/ic/pca9564.c
@@ -67,8 +67,7 @@ pca9564_attach(struct pca9564_softc *sc)
 	aprint_naive("\n");
 	aprint_normal(": PCA9564 I2C Controller\n");
 
-	mutex_init(&sc->sc_buslock, MUTEX_DEFAULT, IPL_NONE);
-
+	iic_tag_init(&sc->sc_i2c);
 	sc->sc_i2c.ic_cookie = sc;
 	sc->sc_i2c.ic_acquire_bus = pca9564_acquire_bus;
 	sc->sc_i2c.ic_release_bus = pca9564_release_bus;
@@ -77,7 +76,6 @@ pca9564_attach(struct pca9564_softc *sc)
 	sc->sc_i2c.ic_initiate_xfer = pca9564_initiate_xfer;
 	sc->sc_i2c.ic_read_byte = pca9564_read_byte;
 	sc->sc_i2c.ic_write_byte = pca9564_write_byte;
-	sc->sc_i2c.ic_exec = NULL;
 
 	/* set serial clock rate */
 	switch (sc->sc_i2c_clock) {
@@ -124,8 +122,6 @@ pca9564_acquire_bus(void *cookie, int flags)
 	struct pca9564_softc *sc = cookie;
 	uint8_t control;
 
-	mutex_enter(&sc->sc_buslock);
-
 	/* Enable SIO and set clock */
 	control = CSR_READ(sc, PCA9564_I2CCON);
 	control |= I2CCON_ENSIO;
@@ -148,8 +144,6 @@ pca9564_release_bus(void *cookie, int flags)
 	control = CSR_READ(sc, PCA9564_I2CCON);
 	control &= ~I2CCON_ENSIO;
 	CSR_WRITE(sc, PCA9564_I2CCON, control);
-
-	mutex_exit(&sc->sc_buslock);
 }
 
 #define	PCA9564_TIMEOUT		100	/* protocol timeout, in uSecs */
diff --git a/sys/dev/ic/pca9564var.h b/sys/dev/ic/pca9564var.h
index d623e543f7dd..97838d27a8b9 100644
--- a/sys/dev/ic/pca9564var.h
+++ b/sys/dev/ic/pca9564var.h
@@ -41,7 +41,6 @@ struct pca9564_softc {
 	int sc_i2c_clock;
 
 	struct i2c_controller sc_i2c;
-	kmutex_t sc_buslock;
 };
 
 void pca9564_attach(struct pca9564_softc *);
diff --git a/sys/dev/ic/pcf8584.c b/sys/dev/ic/pcf8584.c
index 9ff03bdf9082..797a5169969c 100644
--- a/sys/dev/ic/pcf8584.c
+++ b/sys/dev/ic/pcf8584.c
@@ -22,7 +22,6 @@
 #include <sys/device.h>
 #include <sys/malloc.h>
 #include <sys/kernel.h>
-#include <sys/rwlock.h>
 #include <sys/proc.h>
 #include <sys/bus.h>
 
@@ -94,10 +93,8 @@ pcfiic_attach(struct pcfiic_softc *sc, i2c_addr_t addr, u_int8_t clock,
 	if (sc->sc_master)
 		pcfiic_choose_bus(sc, 0);
 
-	rw_init(&sc->sc_lock);
+	iic_tag_init(&sc->sc_i2c);
 	sc->sc_i2c.ic_cookie = sc;
-	sc->sc_i2c.ic_acquire_bus = pcfiic_i2c_acquire_bus;
-	sc->sc_i2c.ic_release_bus = pcfiic_i2c_release_bus;
 	sc->sc_i2c.ic_exec = pcfiic_i2c_exec;
 
 	bzero(&iba, sizeof(iba));
@@ -111,23 +108,6 @@ pcfiic_intr(void *arg)
 	return (0);
 }
 
-int
-pcfiic_i2c_acquire_bus(void *arg, int flags)
-{
-	struct pcfiic_softc	*sc = arg;
-
-	rw_enter(&sc->sc_lock, RW_WRITER);
-	return 0;
-}
-
-void
-pcfiic_i2c_release_bus(void *arg, int flags)
-{
-	struct pcfiic_softc	*sc = arg;
-
-	rw_exit(&sc->sc_lock);
-}
-
 int
 pcfiic_i2c_exec(void *arg, i2c_op_t op, i2c_addr_t addr,
     const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
diff --git a/sys/dev/ic/pcf8584var.h b/sys/dev/ic/pcf8584var.h
index b2d351467987..59947e79cbcb 100644
--- a/sys/dev/ic/pcf8584var.h
+++ b/sys/dev/ic/pcf8584var.h
@@ -31,7 +31,6 @@ struct pcfiic_softc {
 	int			sc_poll;
 
 	struct i2c_controller	sc_i2c;
-	krwlock_t		sc_lock;
 };
 
 void	pcfiic_attach(struct pcfiic_softc *, i2c_addr_t, u_int8_t, int);
diff --git a/sys/dev/pci/alipm.c b/sys/dev/pci/alipm.c
index 1cb19588b3a2..546f7852577a 100644
--- a/sys/dev/pci/alipm.c
+++ b/sys/dev/pci/alipm.c
@@ -104,7 +104,6 @@ struct alipm_softc {
 	bus_space_handle_t sc_ioh;
 
 	struct i2c_controller sc_smb_tag;
-	kmutex_t sc_smb_mutex;
 };
 
 static int	alipm_match(device_t, cfdata_t, void *);
@@ -205,10 +204,8 @@ alipm_attach(device_t parent, device_t self, void *aux)
 	aprint_naive("\n");
 
 	/* Attach I2C bus */
-	mutex_init(&sc->sc_smb_mutex, MUTEX_DEFAULT, IPL_NONE);
+	iic_tag_init(&sc->sc_smb_tag);
 	sc->sc_smb_tag.ic_cookie = sc;
-	sc->sc_smb_tag.ic_acquire_bus = alipm_smb_acquire_bus;
-	sc->sc_smb_tag.ic_release_bus = alipm_smb_release_bus;
 	sc->sc_smb_tag.ic_exec = alipm_smb_exec;
 
 	memset(&iba, 0, sizeof iba);
@@ -221,23 +218,6 @@ fail:
 	bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize);
 }
 
-int
-alipm_smb_acquire_bus(void *cookie, int flags)
-{
-	struct alipm_softc *sc = cookie;
-
-	mutex_enter(&sc->sc_smb_mutex);
-	return 0;
-}
-
-void
-alipm_smb_release_bus(void *cookie, int flags)
-{
-	struct alipm_softc *sc = cookie;
-
-	mutex_exit(&sc->sc_smb_mutex);
-}
-
 int
 alipm_smb_exec(void *cookie, i2c_op_t op, i2c_addr_t addr,
     const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
diff --git a/sys/dev/pci/amdpm_smbus.c b/sys/dev/pci/amdpm_smbus.c
index 68c0b4a41a8e..7650e76bb267 100644
--- a/sys/dev/pci/amdpm_smbus.c
+++ b/sys/dev/pci/amdpm_smbus.c
@@ -38,7 +38,6 @@ __KERNEL_RCSID(0, "$NetBSD: amdpm_smbus.c,v 1.22 2016/02/14 19:54:21 chs Exp $")
 #include <sys/systm.h>
 #include <sys/kernel.h>
 #include <sys/device.h>
-#include <sys/mutex.h>
 
 #include <dev/pci/pcireg.h>
 #include <dev/pci/pcivar.h>
@@ -52,8 +51,6 @@ __KERNEL_RCSID(0, "$NetBSD: amdpm_smbus.c,v 1.22 2016/02/14 19:54:21 chs Exp $")
 
 #include <dev/pci/amdpm_smbusreg.h>
 
-static int       amdpm_smbus_acquire_bus(void *, int);
-static void      amdpm_smbus_release_bus(void *, int);
 static int       amdpm_smbus_exec(void *, i2c_op_t, i2c_addr_t, const void *,
 				  size_t, void *, size_t, int);
 static int       amdpm_smbus_check_done(struct amdpm_softc *, i2c_op_t);
@@ -72,14 +69,8 @@ amdpm_smbus_attach(struct amdpm_softc *sc)
         struct i2cbus_attach_args iba;
 	
 	/* register with iic */
+	iic_tag_init(&sc->sc_i2c);
 	sc->sc_i2c.ic_cookie = sc; 
-	sc->sc_i2c.ic_acquire_bus = amdpm_smbus_acquire_bus; 
-	sc->sc_i2c.ic_release_bus = amdpm_smbus_release_bus;
-	sc->sc_i2c.ic_send_start = NULL;
-	sc->sc_i2c.ic_send_stop = NULL;
-	sc->sc_i2c.ic_initiate_xfer = NULL;
-	sc->sc_i2c.ic_read_byte = NULL;
-	sc->sc_i2c.ic_write_byte = NULL;
 	sc->sc_i2c.ic_exec = amdpm_smbus_exec;
 
 	memset(&iba, 0, sizeof(iba));
@@ -87,23 +78,6 @@ amdpm_smbus_attach(struct amdpm_softc *sc)
 	(void)config_found_ia(sc->sc_dev, "i2cbus", &iba, iicbus_print);
 }
 
-static int
-amdpm_smbus_acquire_bus(void *cookie, int flags)
-{
-	struct amdpm_softc *sc = cookie;
-
-	mutex_enter(&sc->sc_mutex);
-	return 0;
-}
-
-static void
-amdpm_smbus_release_bus(void *cookie, int flags)
-{
-	struct amdpm_softc *sc = cookie;
-
-	mutex_exit(&sc->sc_mutex);
-}
-
 static int
 amdpm_smbus_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *cmd,
 		 size_t cmdlen, void *vbuf, size_t buflen, int flags)
diff --git a/sys/dev/pci/amdpmvar.h b/sys/dev/pci/amdpmvar.h
index 5982725ccc58..5965e5caebe7 100644
--- a/sys/dev/pci/amdpmvar.h
+++ b/sys/dev/pci/amdpmvar.h
@@ -32,7 +32,6 @@
 #ifndef _DEV_PCI_AMDPMVAR_H_
 #define _DEV_PCI_AMDPMVAR_H_
 
-#include <sys/mutex.h>
 #include <sys/rndsource.h>
 
 struct amdpm_softc {
diff --git a/sys/dev/pci/coram.c b/sys/dev/pci/coram.c
index 435ee762fe79..4fe913e199da 100644
--- a/sys/dev/pci/coram.c
+++ b/sys/dev/pci/coram.c
@@ -69,8 +69,6 @@ static const struct coram_board * coram_board_lookup(uint16_t, uint16_t);
 
 static int coram_iic_exec(void *, i2c_op_t, i2c_addr_t,
     const void *, size_t, void *, size_t, int);
-static int coram_iic_acquire_bus(void *, int);
-static void coram_iic_release_bus(void *, int);
 static int coram_iic_read(struct coram_iic_softc *, i2c_op_t, i2c_addr_t,
     const void *, size_t, void *, size_t, int);
 static int coram_iic_write(struct coram_iic_softc *, i2c_op_t, i2c_addr_t,
@@ -219,17 +217,14 @@ coram_attach(device_t parent, device_t self, void *aux)
 		    I2C_BASE + (I2C_SIZE * i), I2C_SIZE, &cic->cic_regh))
 			panic("failed to subregion i2c");
 
-		mutex_init(&cic->cic_busmutex, MUTEX_DRIVER, IPL_NONE);
+		iic_tag_init(&cic->cic_i2c);
 		cic->cic_i2c.ic_cookie = cic;
-		cic->cic_i2c.ic_acquire_bus = coram_iic_acquire_bus;
-		cic->cic_i2c.ic_release_bus = coram_iic_release_bus;
 		cic->cic_i2c.ic_exec = coram_iic_exec;
 
 #ifdef CORAM_ATTACH_I2C
 		/* attach iic(4) */
 		memset(&iba, 0, sizeof(iba));
 		iba.iba_tag = &cic->cic_i2c;
-		iba.iba_type = I2C_TYPE_SMBUS;
 		cic->cic_i2cdev = config_found_ia(self, "i2cbus", &iba,
 		    iicbus_print);
 #endif
@@ -307,7 +302,7 @@ coram_detach(device_t self, int flags)
 		cic = &sc->sc_iic[i];
 		if (cic->cic_i2cdev)
 			config_detach(cic->cic_i2cdev, flags);
-		mutex_destroy(&cic->cic_busmutex);
+		iic_tag_fini(&cic->cic_i2c);
 	}
 	pmf_device_deregister(self);
 
@@ -455,36 +450,6 @@ coram_resume(device_t dv, const pmf_qual_t *qual)
 	return true;
 }
 
-static int
-coram_iic_acquire_bus(void *cookie, int flags)
-{
-	struct coram_iic_softc *cic;
-
-	cic = cookie;
-
-	if (flags & I2C_F_POLL) {
-		while (mutex_tryenter(&cic->cic_busmutex) == 0)
-			delay(50);
-		return 0;
-	}
-
-	mutex_enter(&cic->cic_busmutex);
-
-	return 0;
-}
-
-static void
-coram_iic_release_bus(void *cookie, int flags)
-{
-	struct coram_iic_softc *cic;
-
-	cic = cookie;
-
-	mutex_exit(&cic->cic_busmutex);
-
-	return;
-}
-
 /* I2C Bus */
 
 #define I2C_ADDR  0x0000
diff --git a/sys/dev/pci/cxdtv.c b/sys/dev/pci/cxdtv.c
index c58b4ab8d6be..5931968b522c 100644
--- a/sys/dev/pci/cxdtv.c
+++ b/sys/dev/pci/cxdtv.c
@@ -70,8 +70,6 @@ static int cxdtv_intr(void *);
 
 static bool cxdtv_resume(device_t, const pmf_qual_t *);
 
-static int	cxdtv_iic_acquire_bus(void *, int);
-static void	cxdtv_iic_release_bus(void *, int);
 static int	cxdtv_iic_send_start(void *, int);
 static int	cxdtv_iic_send_stop(void *, int);
 static int	cxdtv_iic_initiate_xfer(void *, i2c_addr_t, int);
@@ -233,11 +231,8 @@ cxdtv_attach(device_t parent, device_t self, void *aux)
 	reg |= PCI_COMMAND_MASTER_ENABLE;
 	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, reg);
 
-	mutex_init(&sc->sc_i2c_buslock, MUTEX_DRIVER, IPL_NONE);
+	iic_tag_init(&sc->sc_i2c);
 	sc->sc_i2c.ic_cookie = sc;
-	sc->sc_i2c.ic_exec = NULL;
-	sc->sc_i2c.ic_acquire_bus = cxdtv_iic_acquire_bus;
-	sc->sc_i2c.ic_release_bus = cxdtv_iic_release_bus;
 	sc->sc_i2c.ic_send_start = cxdtv_iic_send_start;
 	sc->sc_i2c.ic_send_stop = cxdtv_iic_send_stop;
 	sc->sc_i2c.ic_initiate_xfer = cxdtv_iic_initiate_xfer;
@@ -282,7 +277,7 @@ cxdtv_detach(device_t self, int flags)
 	if (sc->sc_mems)
 		bus_space_unmap(sc->sc_memt, sc->sc_memh, sc->sc_mems);
 
-	mutex_destroy(&sc->sc_i2c_buslock);
+	iic_tag_fini(&sc->sc_i2c);
 
 	return 0;
 }
@@ -379,26 +374,6 @@ cxdtv_i2cbb_read_bits(void *cookie)
 	return value;
 }
 
-static int
-cxdtv_iic_acquire_bus(void *cookie, int flags)
-{
-	struct cxdtv_softc *sc = cookie;
-
-	mutex_enter(&sc->sc_i2c_buslock);
-
-	return 0;
-}
-
-static void
-cxdtv_iic_release_bus(void *cookie, int flags)
-{
-	struct cxdtv_softc *sc = cookie;
-
-	mutex_exit(&sc->sc_i2c_buslock);
-
-	return;
-}
-
 static int
 cxdtv_iic_send_start(void *cookie, int flags)
 {
diff --git a/sys/dev/pci/ichsmb.c b/sys/dev/pci/ichsmb.c
index 0c53706b170a..39018e872746 100644
--- a/sys/dev/pci/ichsmb.c
+++ b/sys/dev/pci/ichsmb.c
@@ -63,7 +63,6 @@ struct ichsmb_softc {
 	pci_intr_handle_t	*sc_pihp;
 
 	struct i2c_controller	sc_i2c_tag;
-	kmutex_t 		sc_i2c_mutex;
 	struct {
 		i2c_op_t     op;
 		void *       buf;
@@ -80,8 +79,6 @@ static int	ichsmb_detach(device_t, int);
 static int	ichsmb_rescan(device_t, const char *, const int *);
 static void	ichsmb_chdet(device_t, device_t);
 
-static int	ichsmb_i2c_acquire_bus(void *, int);
-static void	ichsmb_i2c_release_bus(void *, int);
 static int	ichsmb_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *,
 		    size_t, void *, size_t, int);
 
@@ -208,7 +205,6 @@ ichsmb_attach(device_t parent, device_t self, void *aux)
 
 	sc->sc_i2c_device = NULL;
 	flags = 0;
-	mutex_init(&sc->sc_i2c_mutex, MUTEX_DEFAULT, IPL_NONE);
 	ichsmb_rescan(self, "i2cbus", &flags);
 
 out:	if (!pmf_device_register(self, NULL, NULL))
@@ -228,13 +224,11 @@ ichsmb_rescan(device_t self, const char *ifattr, const int *flags)
 		return 0;
 
 	/* Attach I2C bus */
+	iic_tag_init(&sc->sc_i2c_tag);
 	sc->sc_i2c_tag.ic_cookie = sc;
-	sc->sc_i2c_tag.ic_acquire_bus = ichsmb_i2c_acquire_bus;
-	sc->sc_i2c_tag.ic_release_bus = ichsmb_i2c_release_bus;
 	sc->sc_i2c_tag.ic_exec = ichsmb_i2c_exec;
 
 	memset(&iba, 0, sizeof(iba));
-	iba.iba_type = I2C_TYPE_SMBUS;
 	iba.iba_tag = &sc->sc_i2c_tag;
 	sc->sc_i2c_device = config_found_ia(self, ifattr, &iba, iicbus_print);
 
@@ -253,7 +247,7 @@ ichsmb_detach(device_t self, int flags)
 			return error;
 	}
 
-	mutex_destroy(&sc->sc_i2c_mutex);
+	iic_tag_fini(&sc->sc_i2c_tag);
 
 	if (sc->sc_ih) {
 		pci_intr_disestablish(sc->sc_pc, sc->sc_ih);
@@ -279,29 +273,6 @@ ichsmb_chdet(device_t self, device_t child)
 		sc->sc_i2c_device = NULL;
 }
 
-static int
-ichsmb_i2c_acquire_bus(void *cookie, int flags)
-{
-	struct ichsmb_softc *sc = cookie;
-
-	if (cold)
-		return 0;
-
-	mutex_enter(&sc->sc_i2c_mutex);
-	return 0;
-}
-
-static void
-ichsmb_i2c_release_bus(void *cookie, int flags)
-{
-	struct ichsmb_softc *sc = cookie;
-
-	if (cold)
-		return;
-
-	mutex_exit(&sc->sc_i2c_mutex);
-}
-
 static int
 ichsmb_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr,
     const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
diff --git a/sys/dev/pci/if_tl.c b/sys/dev/pci/if_tl.c
index b72163338640..48f68eac5d7b 100644
--- a/sys/dev/pci/if_tl.c
+++ b/sys/dev/pci/if_tl.c
@@ -141,8 +141,6 @@ int tl_mii_write(device_t, int, int, uint16_t);
 void tl_statchg(struct ifnet *);
 
 	/* I2C glue */
-static int tl_i2c_acquire_bus(void *, int);
-static void tl_i2c_release_bus(void *, int);
 static int tl_i2c_send_start(void *, int);
 static int tl_i2c_send_stop(void *, int);
 static int tl_i2c_initiate_xfer(void *, i2c_addr_t, int);
@@ -361,9 +359,8 @@ tl_pci_attach(device_t parent, device_t self, void *aux)
 	tl_reset(sc);
 
 	/* fill in the i2c tag */
+	iic_tag_init(&sc->sc_i2c);
 	sc->sc_i2c.ic_cookie = sc;
-	sc->sc_i2c.ic_acquire_bus = tl_i2c_acquire_bus;
-	sc->sc_i2c.ic_release_bus = tl_i2c_release_bus;
 	sc->sc_i2c.ic_send_start = tl_i2c_send_start;
 	sc->sc_i2c.ic_send_stop = tl_i2c_send_stop;
 	sc->sc_i2c.ic_initiate_xfer = tl_i2c_initiate_xfer;
@@ -917,21 +914,6 @@ tl_statchg(struct ifnet *ifp)
 
 /********** I2C glue **********/
 
-static int
-tl_i2c_acquire_bus(void *cookie, int flags)
-{
-
-	/* private bus */
-	return 0;
-}
-
-static void
-tl_i2c_release_bus(void *cookie, int flags)
-{
-
-	/* private bus */
-}
-
 static int
 tl_i2c_send_start(void *cookie, int flags)
 {
diff --git a/sys/dev/pci/igma.c b/sys/dev/pci/igma.c
index 4e5115f54cf4..982cd182de52 100644
--- a/sys/dev/pci/igma.c
+++ b/sys/dev/pci/igma.c
@@ -58,7 +58,6 @@ __KERNEL_RCSID(0, "$NetBSD: igma.c,v 1.3 2016/02/14 19:54:21 chs Exp $");
 
 struct igma_softc;
 struct igma_i2c {
-	kmutex_t		ii_lock;
 	struct igma_softc	*ii_sc;
 	bus_addr_t		ii_reg;
 	struct i2c_controller	ii_i2c;
@@ -457,21 +456,16 @@ igma_i2c_attach(struct igma_softc *sc)
 			panic("don't know GMBUS %d\n",i);
 		}
 
-		mutex_init(&ii->ii_lock, MUTEX_DEFAULT, IPL_NONE);
-
+		iic_tag_init(&ii->ii_i2c);
 		ii->ii_i2c.ic_cookie = ii;
-		ii->ii_i2c.ic_acquire_bus = igma_i2c_acquire_bus;
-		ii->ii_i2c.ic_release_bus = igma_i2c_release_bus;
 		ii->ii_i2c.ic_send_start = igma_i2c_send_start;
 		ii->ii_i2c.ic_send_stop = igma_i2c_send_stop;
 		ii->ii_i2c.ic_initiate_xfer = igma_i2c_initiate_xfer;
 		ii->ii_i2c.ic_read_byte = igma_i2c_read_byte;
 		ii->ii_i2c.ic_write_byte = igma_i2c_write_byte;
-		ii->ii_i2c.ic_exec = NULL;
 
 #if 0
 		memset(&iba, 0, sizeof(iba));
-		iba.iba_type = I2C_TYPE_SMBUS;
 		iba.iba_tag = &ii->ii_i2c;
 		config_found_ia(sc->sc_dev, "i2cbus", &iba, iicbus_print);
 #endif
@@ -482,21 +476,6 @@ igma_i2c_attach(struct igma_softc *sc)
  * I2C interface
  */
 
-static int
-igma_i2c_acquire_bus(void *cookie, int flags)
-{
-	struct igma_i2c *ii = cookie;
-	mutex_enter(&ii->ii_lock);
-	return 0;
-}
-
-static void
-igma_i2c_release_bus(void *cookie, int flags)
-{
-	struct igma_i2c *ii = cookie;
-	mutex_exit(&ii->ii_lock);
-}
-
 static int
 igma_i2c_send_start(void *cookie, int flags)
 {
diff --git a/sys/dev/pci/ismt.c b/sys/dev/pci/ismt.c
index 1d0cd4c48533..e1a8d6b1291e 100644
--- a/sys/dev/pci/ismt.c
+++ b/sys/dev/pci/ismt.c
@@ -68,7 +68,6 @@ __KERNEL_RCSID(0, "$NetBSD: ismt.c,v 1.6 2017/08/17 01:24:09 msaitoh Exp $");
 #include <sys/errno.h>
 #include <sys/kernel.h>
 #include <sys/module.h>
-#include <sys/mutex.h>
 #include <sys/proc.h>
 
 #include <sys/bus.h>
@@ -186,7 +185,6 @@ struct ismt_softc {
 	device_t		smbdev;
 
 	struct i2c_controller	sc_i2c_tag;
-	kmutex_t 		sc_i2c_mutex;
 
 	pci_chipset_tag_t	sc_pc;
 	pcitag_t		sc_pcitag;
@@ -215,8 +213,6 @@ struct ismt_softc {
 };
 
 static int	ismt_intr(void *);
-static int	ismt_i2c_acquire_bus(void *, int);
-static void	ismt_i2c_release_bus(void *, int);
 static int	ismt_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *,
     size_t, void *, size_t, int);
 static struct ismt_desc *ismt_alloc_desc(struct ismt_softc *);
@@ -268,23 +264,6 @@ ismt_intr(void *arg)
 	return 1;
 }
 
-static int
-ismt_i2c_acquire_bus(void *cookie, int flags)
-{
-	struct ismt_softc *sc = cookie;
-
-	mutex_enter(&sc->sc_i2c_mutex);
-	return 0;
-}
-
-static void
-ismt_i2c_release_bus(void *cookie, int flags)
-{
-	struct ismt_softc *sc = cookie;
-
-	mutex_exit(&sc->sc_i2c_mutex);
-}
-
 static int
 ismt_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr,
     const void *cmd, size_t cmdlen, void *buf, size_t buflen, int flags)
@@ -342,8 +321,6 @@ ismt_alloc_desc(struct ismt_softc *sc)
 {
 	struct ismt_desc *desc;
 
-	KASSERT(mutex_owned(&sc->sc_i2c_mutex));
-
 	desc = &sc->desc[sc->head++];
 	if (sc->head == ISMT_DESC_ENTRIES)
 		sc->head = 0;
@@ -675,7 +652,7 @@ ismt_detach(device_t self, int flags)
 	if (sc->mmio_size)
 		bus_space_unmap(sc->mmio_tag, sc->mmio_handle, sc->mmio_size);
 
-	mutex_destroy(&sc->sc_i2c_mutex);
+	iic_tag_fini(&sc->sc_i2c_tag);
 	return rv;
 }
 
@@ -776,7 +753,6 @@ ismt_attach(device_t parent, device_t self, void *aux)
 	aprint_normal_dev(sc->pcidev, "interrupting at %s\n", intrstr);
 
 	sc->smbdev = NULL;
-	mutex_init(&sc->sc_i2c_mutex, MUTEX_DEFAULT, IPL_NONE);
 	if (!pmf_device_register(self, NULL, NULL))
 		aprint_error_dev(self, "couldn't establish power handler\n");
 
@@ -823,13 +799,11 @@ ismt_rescan(device_t self, const char *ifattr, const int *flags)
 		return 0;
 
 	/* Attach I2C bus */
+	iic_tag_init(&sc->sc_i2c_tag);
 	sc->sc_i2c_tag.ic_cookie = sc;
-	sc->sc_i2c_tag.ic_acquire_bus = ismt_i2c_acquire_bus;
-	sc->sc_i2c_tag.ic_release_bus = ismt_i2c_release_bus;
 	sc->sc_i2c_tag.ic_exec = ismt_i2c_exec;
 
 	memset(&iba, 0, sizeof(iba));
-	iba.iba_type = I2C_TYPE_SMBUS;
 	iba.iba_tag = &sc->sc_i2c_tag;
 	sc->smbdev = config_found_ia(self, ifattr, &iba, iicbus_print);
 
diff --git a/sys/dev/pci/nfsmb.c b/sys/dev/pci/nfsmb.c
index 7608f5d952a4..603eda811d57 100644
--- a/sys/dev/pci/nfsmb.c
+++ b/sys/dev/pci/nfsmb.c
@@ -73,7 +73,6 @@ struct nfsmb_softc {
 	bus_space_handle_t sc_ioh;
 
 	struct i2c_controller sc_i2c;	/* i2c controller info */
-	kmutex_t sc_mutex;
 };
 
 
@@ -83,8 +82,6 @@ static int nfsmbc_print(void *, const char *);
 
 static int nfsmb_match(device_t, cfdata_t, void *);
 static void nfsmb_attach(device_t, device_t, void *);
-static int nfsmb_acquire_bus(void *, int);
-static void nfsmb_release_bus(void *, int);
 static int nfsmb_exec(
     void *, i2c_op_t, i2c_addr_t, const void *, size_t, void *, size_t, int);
 static int nfsmb_check_done(struct nfsmb_softc *);
@@ -227,18 +224,10 @@ nfsmb_attach(device_t parent, device_t self, void *aux)
 	sc->sc_iot = nfsmbcap->nfsmb_iot;
 
 	/* register with iic */
+	iic_tag_init(&sc->sc_i2c);
 	sc->sc_i2c.ic_cookie = sc;
-	sc->sc_i2c.ic_acquire_bus = nfsmb_acquire_bus;
-	sc->sc_i2c.ic_release_bus = nfsmb_release_bus;
-	sc->sc_i2c.ic_send_start = NULL;
-	sc->sc_i2c.ic_send_stop = NULL;
-	sc->sc_i2c.ic_initiate_xfer = NULL;
-	sc->sc_i2c.ic_read_byte = NULL;
-	sc->sc_i2c.ic_write_byte = NULL;
 	sc->sc_i2c.ic_exec = nfsmb_exec;
 
-	mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_NONE);
-
 	if (bus_space_map(sc->sc_iot, nfsmbcap->nfsmb_addr, NFORCE_SMBSIZE, 0,
 	    &sc->sc_ioh) != 0) {
 		aprint_error_dev(self, "failed to map SMBus space\n");
@@ -246,7 +235,6 @@ nfsmb_attach(device_t parent, device_t self, void *aux)
 	}
 
 	memset(&iba, 0, sizeof(iba));
-	iba.iba_type = I2C_TYPE_SMBUS;
 	iba.iba_tag = &sc->sc_i2c;
 	(void) config_found_ia(sc->sc_dev, "i2cbus", &iba, iicbus_print);
 
@@ -257,23 +245,6 @@ nfsmb_attach(device_t parent, device_t self, void *aux)
 		aprint_error_dev(self, "couldn't establish power handler\n");
 }
 
-static int
-nfsmb_acquire_bus(void *cookie, int flags)
-{
-	struct nfsmb_softc *sc = cookie;
-
-	mutex_enter(&sc->sc_mutex);
-	return 0;
-}
-
-static void
-nfsmb_release_bus(void *cookie, int flags)
-{
-	struct nfsmb_softc *sc = cookie;
-
-	mutex_exit(&sc->sc_mutex);
-}
-
 static int
 nfsmb_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *cmd,
 	   size_t cmdlen, void *vbuf, size_t buflen, int flags)
diff --git a/sys/dev/pci/piixpm.c b/sys/dev/pci/piixpm.c
index a298ce750db9..8b1881c502e2 100644
--- a/sys/dev/pci/piixpm.c
+++ b/sys/dev/pci/piixpm.c
@@ -332,12 +332,12 @@ piixpm_rescan(device_t self, const char *ifattr, const int *flags)
 			continue;
 		sc->sc_busses[i].sda = i;
 		sc->sc_busses[i].softc = sc;
+		iic_tag_init(&sc->sc_i2c_tags[i]);
 		sc->sc_i2c_tags[i].ic_cookie = &sc->sc_busses[i];
 		sc->sc_i2c_tags[i].ic_acquire_bus = piixpm_i2c_acquire_bus;
 		sc->sc_i2c_tags[i].ic_release_bus = piixpm_i2c_release_bus;
 		sc->sc_i2c_tags[i].ic_exec = piixpm_i2c_exec;
 		memset(&iba, 0, sizeof(iba));
-		iba.iba_type = I2C_TYPE_SMBUS;
 		iba.iba_tag = &sc->sc_i2c_tags[i];
 		sc->sc_i2c_device[i] = config_found_ia(self, ifattr, &iba,
 		    piixpm_iicbus_print);
diff --git a/sys/dev/pci/pm2fb.c b/sys/dev/pci/pm2fb.c
index 102949e7e04c..eb10fae57cd9 100644
--- a/sys/dev/pci/pm2fb.c
+++ b/sys/dev/pci/pm2fb.c
@@ -167,8 +167,6 @@ struct wsdisplay_accessops pm2fb_accessops = {
 };
 
 /* I2C glue */
-static int pm2fb_i2c_acquire_bus(void *, int);
-static void pm2fb_i2c_release_bus(void *, int);
 static int pm2fb_i2c_send_start(void *, int);
 static int pm2fb_i2c_send_stop(void *, int);
 static int pm2fb_i2c_initiate_xfer(void *, i2c_addr_t, int);
@@ -1341,15 +1339,13 @@ pm2_setup_i2c(struct pm2fb_softc *sc)
 #endif
 
 	/* Fill in the i2c tag */
+	iic_tag_init(&sc->sc_i2c);
 	sc->sc_i2c.ic_cookie = sc;
-	sc->sc_i2c.ic_acquire_bus = pm2fb_i2c_acquire_bus;
-	sc->sc_i2c.ic_release_bus = pm2fb_i2c_release_bus;
 	sc->sc_i2c.ic_send_start = pm2fb_i2c_send_start;
 	sc->sc_i2c.ic_send_stop = pm2fb_i2c_send_stop;
 	sc->sc_i2c.ic_initiate_xfer = pm2fb_i2c_initiate_xfer;
 	sc->sc_i2c.ic_read_byte = pm2fb_i2c_read_byte;
 	sc->sc_i2c.ic_write_byte = pm2fb_i2c_write_byte;
-	sc->sc_i2c.ic_exec = NULL;
 
 	DPRINTF("data: %08x\n", bus_space_read_4(sc->sc_memt, sc->sc_regh,
 		PM2_DISPLAY_DATA));
@@ -1447,19 +1443,6 @@ static uint32_t pm2fb_i2cbb_read(void *cookie)
 }
 
 /* higher level I2C stuff */
-static int
-pm2fb_i2c_acquire_bus(void *cookie, int flags)
-{
-	/* private bus */
-	return (0);
-}
-
-static void
-pm2fb_i2c_release_bus(void *cookie, int flags)
-{
-	/* private bus */
-}
-
 static int
 pm2fb_i2c_send_start(void *cookie, int flags)
 {
diff --git a/sys/dev/pci/pm3fb.c b/sys/dev/pci/pm3fb.c
index 2a41a7e34761..d49dec50aa2e 100644
--- a/sys/dev/pci/pm3fb.c
+++ b/sys/dev/pci/pm3fb.c
@@ -133,8 +133,6 @@ struct wsdisplay_accessops pm3fb_accessops = {
 };
 
 /* I2C glue */
-static int pm3fb_i2c_acquire_bus(void *, int);
-static void pm3fb_i2c_release_bus(void *, int);
 static int pm3fb_i2c_send_start(void *, int);
 static int pm3fb_i2c_send_stop(void *, int);
 static int pm3fb_i2c_initiate_xfer(void *, i2c_addr_t, int);
@@ -1004,9 +1002,8 @@ pm3_setup_i2c(struct pm3fb_softc *sc)
 	int i;
 
 	/* Fill in the i2c tag */
+	iic_tag_init(&sc->sc_i2c);
 	sc->sc_i2c.ic_cookie = sc;
-	sc->sc_i2c.ic_acquire_bus = pm3fb_i2c_acquire_bus;
-	sc->sc_i2c.ic_release_bus = pm3fb_i2c_release_bus;
 	sc->sc_i2c.ic_send_start = pm3fb_i2c_send_start;
 	sc->sc_i2c.ic_send_stop = pm3fb_i2c_send_stop;
 	sc->sc_i2c.ic_initiate_xfer = pm3fb_i2c_initiate_xfer;
@@ -1094,19 +1091,6 @@ static uint32_t pm3fb_i2cbb_read(void *cookie)
 }
 
 /* higher level I2C stuff */
-static int
-pm3fb_i2c_acquire_bus(void *cookie, int flags)
-{
-	/* private bus */
-	return (0);
-}
-
-static void
-pm3fb_i2c_release_bus(void *cookie, int flags)
-{
-	/* private bus */
-}
-
 static int
 pm3fb_i2c_send_start(void *cookie, int flags)
 {
diff --git a/sys/dev/pci/radeonfb_i2c.c b/sys/dev/pci/radeonfb_i2c.c
index 07397c3bf12c..49a235109036 100644
--- a/sys/dev/pci/radeonfb_i2c.c
+++ b/sys/dev/pci/radeonfb_i2c.c
@@ -205,6 +205,7 @@ radeonfb_i2c_init(struct radeonfb_softc *sc)
 		struct i2c_controller	*icc = &sc->sc_i2c[i].ric_controller;
 
 		sc->sc_i2c[i].ric_softc = sc;
+		iic_tag_init(icc);
 		icc->ic_cookie = &sc->sc_i2c[i];
 		icc->ic_acquire_bus = radeonfb_i2c_acquire_bus;
 		icc->ic_release_bus = radeonfb_i2c_release_bus;
diff --git a/sys/dev/pci/voodoofb.c b/sys/dev/pci/voodoofb.c
index 3f3b9c05c3ae..3839e1313b37 100644
--- a/sys/dev/pci/voodoofb.c
+++ b/sys/dev/pci/voodoofb.c
@@ -224,8 +224,6 @@ struct wsdisplay_accessops voodoofb_accessops = {
 };
 
 /* I2C glue */
-static int voodoofb_i2c_acquire_bus(void *, int);
-static void voodoofb_i2c_release_bus(void *, int);
 static int voodoofb_i2c_send_start(void *, int);
 static int voodoofb_i2c_send_stop(void *, int);
 static int voodoofb_i2c_initiate_xfer(void *, i2c_addr_t, int);
@@ -1720,15 +1718,13 @@ voodoofb_setup_i2c(struct voodoofb_softc *sc)
 	int i;
 
 	/* Fill in the i2c tag */
+	iic_tag_init(&sc->sc_i2c);
 	sc->sc_i2c.ic_cookie = sc;
-	sc->sc_i2c.ic_acquire_bus = voodoofb_i2c_acquire_bus;
-	sc->sc_i2c.ic_release_bus = voodoofb_i2c_release_bus;
 	sc->sc_i2c.ic_send_start = voodoofb_i2c_send_start;
 	sc->sc_i2c.ic_send_stop = voodoofb_i2c_send_stop;
 	sc->sc_i2c.ic_initiate_xfer = voodoofb_i2c_initiate_xfer;
 	sc->sc_i2c.ic_read_byte = voodoofb_i2c_read_byte;
 	sc->sc_i2c.ic_write_byte = voodoofb_i2c_write_byte;
-	sc->sc_i2c.ic_exec = NULL;
 
 	sc->sc_i2creg = voodoo3_read32(sc, VIDSERPARPORT);
 #ifdef VOODOOFB_DEBUG
@@ -1819,19 +1815,6 @@ static uint32_t voodoofb_i2cbb_read(void *cookie)
 }
 
 /* higher level I2C stuff */
-static int
-voodoofb_i2c_acquire_bus(void *cookie, int flags)
-{
-	/* private bus */
-	return (0);
-}
-
-static void
-voodoofb_i2c_release_bus(void *cookie, int flags)
-{
-	/* private bus */
-}
-
 static int
 voodoofb_i2c_send_start(void *cookie, int flags)
 {
diff --git a/sys/dev/pci/voyager.c b/sys/dev/pci/voyager.c
index 415edc14bb79..32cc87739002 100644
--- a/sys/dev/pci/voyager.c
+++ b/sys/dev/pci/voyager.c
@@ -250,8 +250,8 @@ voyager_attach(device_t parent, device_t self, void *aux)
 		voyager_gpio_dir(sc, 0xffffffff, GPIO_I2C_BITS);
 		
 		/* Fill in the i2c tag */
-		memset(&sc->sc_i2c, 0, sizeof(sc->sc_i2c));
 		memset(&iba, 0, sizeof(iba));
+		iic_tag_init(&sc->sc_i2c);
 		sc->sc_i2c.ic_cookie = sc;
 		sc->sc_i2c.ic_acquire_bus = voyager_i2c_acquire_bus;
 		sc->sc_i2c.ic_release_bus = voyager_i2c_release_bus;
@@ -260,7 +260,6 @@ voyager_attach(device_t parent, device_t self, void *aux)
 		sc->sc_i2c.ic_initiate_xfer = voyager_i2c_initiate_xfer;
 		sc->sc_i2c.ic_read_byte = voyager_i2c_read_byte;
 		sc->sc_i2c.ic_write_byte = voyager_i2c_write_byte;
-		sc->sc_i2c.ic_exec = NULL;
 		iba.iba_tag = &sc->sc_i2c;
 		config_found_ia(self, "i2cbus", &iba, iicbus_print);
 	}
@@ -322,6 +321,7 @@ voyager_i2c_acquire_bus(void *cookie, int flags)
 {
 	struct voyager_softc *sc = cookie;
 
+	/* We also have to serialize against voyager_twiddle_bits() */
 	mutex_enter(&sc->sc_i2c_lock);
 	return 0;
 }
diff --git a/sys/dev/usb/auvitek_i2c.c b/sys/dev/usb/auvitek_i2c.c
index cd2a3af48536..79aef64a552f 100644
--- a/sys/dev/usb/auvitek_i2c.c
+++ b/sys/dev/usb/auvitek_i2c.c
@@ -56,8 +56,6 @@ __KERNEL_RCSID(0, "$NetBSD: auvitek_i2c.c,v 1.4 2016/11/25 12:56:29 skrll Exp $"
 
 /* #define AUVITEK_I2C_DEBUG */
 
-static int	auvitek_i2c_acquire_bus(void *, int);
-static void	auvitek_i2c_release_bus(void *, int);
 static int	auvitek_i2c_exec(void *, i2c_op_t, i2c_addr_t,
 				 const void *, size_t, void *, size_t, int);
 
@@ -73,10 +71,8 @@ static bool	auvitek_i2c_wait_wrdone(struct auvitek_softc *);
 int
 auvitek_i2c_attach(struct auvitek_softc *sc)
 {
-	mutex_init(&sc->sc_i2c_lock, MUTEX_DEFAULT, IPL_NONE);
+	iic_tag_init(&sc->sc_i2c);
 	sc->sc_i2c.ic_cookie = sc;
-	sc->sc_i2c.ic_acquire_bus = auvitek_i2c_acquire_bus;
-	sc->sc_i2c.ic_release_bus = auvitek_i2c_release_bus;
 	sc->sc_i2c.ic_exec = auvitek_i2c_exec;
 
 	auvitek_i2c_rescan(sc, NULL, NULL);
@@ -87,7 +83,7 @@ auvitek_i2c_attach(struct auvitek_softc *sc)
 int
 auvitek_i2c_detach(struct auvitek_softc *sc, int flags)
 {
-	mutex_destroy(&sc->sc_i2c_lock);
+	iic_tag_fini(&sc->sc_i2c);
 
 	if (sc->sc_i2cdev)
 		config_detach(sc->sc_i2cdev, flags);
@@ -104,7 +100,6 @@ auvitek_i2c_rescan(struct auvitek_softc *sc, const char *ifattr,
 
 	if (ifattr_match(ifattr, "i2cbus") && sc->sc_i2cdev == NULL) {
 		memset(&iba, 0, sizeof(iba));
-		iba.iba_type = I2C_TYPE_SMBUS;
 		iba.iba_tag = &sc->sc_i2c;
 		sc->sc_i2cdev = config_found_ia(sc->sc_dev, "i2cbus",
 		    &iba, iicbus_print);
@@ -119,29 +114,6 @@ auvitek_i2c_childdet(struct auvitek_softc *sc, device_t child)
 		sc->sc_i2cdev = NULL;
 }
 
-static int
-auvitek_i2c_acquire_bus(void *opaque, int flags)
-{
-	struct auvitek_softc *sc = opaque;
-
-	if (flags & I2C_F_POLL) {
-		if (!mutex_tryenter(&sc->sc_i2c_lock))
-			return EBUSY;
-	} else {
-		mutex_enter(&sc->sc_i2c_lock);
-	}
-
-	return 0;
-}
-
-static void
-auvitek_i2c_release_bus(void *opaque, int flags)
-{
-	struct auvitek_softc *sc = opaque;
-
-	mutex_exit(&sc->sc_i2c_lock);
-}
-
 static int
 auvitek_i2c_exec(void *opaque, i2c_op_t op, i2c_addr_t addr,
     const void *cmd, size_t cmdlen, void *vbuf, size_t buflen, int flags)
@@ -161,8 +133,6 @@ auvitek_i2c_read(struct auvitek_softc *sc, i2c_addr_t addr,
 	uint8_t v;
 	unsigned int i;
 
-	//KASSERT(mutex_owned(&sc->sc_i2c_lock));
-
 	auvitek_write_1(sc, AU0828_REG_I2C_MBMODE, 1);
 	auvitek_write_1(sc, AU0828_REG_I2C_CLKDIV, sc->sc_i2c_clkdiv);
 	auvitek_write_1(sc, AU0828_REG_I2C_DSTADDR, addr << 1);
@@ -200,8 +170,6 @@ auvitek_i2c_write(struct auvitek_softc *sc, i2c_addr_t addr,
 	uint8_t v;
 	unsigned int i, fifolen;
 
-	//KASSERT(mutex_owned(&sc->sc_i2c_lock));
-
 	auvitek_write_1(sc, AU0828_REG_I2C_MBMODE, 1);
 	auvitek_write_1(sc, AU0828_REG_I2C_CLKDIV, sc->sc_i2c_clkdiv);
 	auvitek_write_1(sc, AU0828_REG_I2C_DSTADDR, addr << 1);
diff --git a/sys/dev/usb/emdtv_i2c.c b/sys/dev/usb/emdtv_i2c.c
index c87697e24f72..dabf692dad53 100644
--- a/sys/dev/usb/emdtv_i2c.c
+++ b/sys/dev/usb/emdtv_i2c.c
@@ -44,8 +44,6 @@ __KERNEL_RCSID(0, "$NetBSD: emdtv_i2c.c,v 1.1 2011/07/11 18:02:04 jmcneill Exp $
 #include <dev/usb/emdtvvar.h>
 #include <dev/usb/emdtvreg.h>
 
-static int	emdtv_i2c_acquire_bus(void *, int);
-static void	emdtv_i2c_release_bus(void *, int);
 static int	emdtv_i2c_exec(void *, i2c_op_t, i2c_addr_t,
 			       const void *, size_t, void *, size_t, int);
 
@@ -58,10 +56,8 @@ static int	emdtv_i2c_send(struct emdtv_softc *, i2c_addr_t,
 int
 emdtv_i2c_attach(struct emdtv_softc *sc)
 {
-	mutex_init(&sc->sc_i2c_lock, MUTEX_DEFAULT, IPL_VM);
+	iic_tag_init(&sc->sc_i2c);
 	sc->sc_i2c.ic_cookie = sc;
-	sc->sc_i2c.ic_acquire_bus = emdtv_i2c_acquire_bus;
-	sc->sc_i2c.ic_release_bus = emdtv_i2c_release_bus;
 	sc->sc_i2c.ic_exec = emdtv_i2c_exec;
 
 	return 0;
@@ -70,17 +66,7 @@ emdtv_i2c_attach(struct emdtv_softc *sc)
 int
 emdtv_i2c_detach(struct emdtv_softc *sc, int flags)
 {
-	mutex_destroy(&sc->sc_i2c_lock);
-
-	return 0;
-}
-
-static int
-emdtv_i2c_acquire_bus(void *opaque, int flags)
-{
-	struct emdtv_softc *sc = opaque;
-
-	mutex_enter(&sc->sc_i2c_lock);
+	iic_tag_fini(&sc->sc_i2c);
 
 	return 0;
 }
@@ -106,14 +92,6 @@ emdtv_i2c_exec(void *opaque, i2c_op_t op, i2c_addr_t addr,
 	return error;
 }
 
-static void
-emdtv_i2c_release_bus(void *opaque, int flags)
-{
-	struct emdtv_softc *sc = opaque;
-
-	mutex_exit(&sc->sc_i2c_lock);
-}
-
 static int
 emdtv_i2c_check(struct emdtv_softc *sc, i2c_addr_t addr)
 {
-- thorpej



Home | Main Index | Thread Index | Old Index