xref: /freebsd-src/sys/dev/iicbus/mux/iicmux.c (revision 5b56413d04e608379c9a306373554a8e4d321bc0)
1422d05daSIan Lepore /*-
2422d05daSIan Lepore  * SPDX-License-Identifier: BSD-2-Clause
3422d05daSIan Lepore  *
4422d05daSIan Lepore  * Copyright (c) 2019 Ian Lepore <ian@freebsd.org>
5422d05daSIan Lepore  *
6422d05daSIan Lepore  * Redistribution and use in source and binary forms, with or without
7422d05daSIan Lepore  * modification, are permitted provided that the following conditions
8422d05daSIan Lepore  * are met:
9422d05daSIan Lepore  * 1. Redistributions of source code must retain the above copyright
10422d05daSIan Lepore  *    notice, this list of conditions and the following disclaimer.
11422d05daSIan Lepore  * 2. Redistributions in binary form must reproduce the above copyright
12422d05daSIan Lepore  *    notice, this list of conditions and the following disclaimer in the
13422d05daSIan Lepore  *    documentation and/or other materials provided with the distribution.
14422d05daSIan Lepore  *
15422d05daSIan Lepore  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16422d05daSIan Lepore  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17422d05daSIan Lepore  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18422d05daSIan Lepore  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19422d05daSIan Lepore  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20422d05daSIan Lepore  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21422d05daSIan Lepore  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22422d05daSIan Lepore  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23422d05daSIan Lepore  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24422d05daSIan Lepore  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25422d05daSIan Lepore  * SUCH DAMAGE.
26422d05daSIan Lepore  */
27422d05daSIan Lepore 
28422d05daSIan Lepore #include <sys/cdefs.h>
29422d05daSIan Lepore #include "opt_platform.h"
30422d05daSIan Lepore 
31422d05daSIan Lepore #include <sys/param.h>
32422d05daSIan Lepore #include <sys/bus.h>
33422d05daSIan Lepore #include <sys/kernel.h>
34422d05daSIan Lepore #include <sys/module.h>
35422d05daSIan Lepore #include <sys/sysctl.h>
36422d05daSIan Lepore 
37422d05daSIan Lepore #ifdef FDT
38422d05daSIan Lepore #include <dev/ofw/ofw_bus.h>
39422d05daSIan Lepore #include <dev/ofw/ofw_bus_subr.h>
40422d05daSIan Lepore #include <dev/ofw/openfirm.h>
41422d05daSIan Lepore #endif
42422d05daSIan Lepore 
43422d05daSIan Lepore #include <dev/iicbus/iiconf.h>
44422d05daSIan Lepore #include "iicbus_if.h"
45422d05daSIan Lepore #include "iicmux_if.h"
46422d05daSIan Lepore #include "iicmux.h"
47422d05daSIan Lepore 
48422d05daSIan Lepore /*------------------------------------------------------------------------------
49422d05daSIan Lepore  * iicbus methods, called by the iicbus functions in iiconf.c.
50422d05daSIan Lepore  *
51422d05daSIan Lepore  * All these functions return an IIC adapter-layer error code (because we are
52422d05daSIan Lepore  * pretending to be a host bridge/i2c controller).  Standard errno values
53422d05daSIan Lepore  * returned from these must be encoded using iic2errno().
54422d05daSIan Lepore  *----------------------------------------------------------------------------*/
55422d05daSIan Lepore 
56422d05daSIan Lepore static int
57422d05daSIan Lepore iicmux_callback(device_t dev, int index, caddr_t data)
58422d05daSIan Lepore {
59422d05daSIan Lepore 	struct iicmux_softc *sc = device_get_softc(dev);
60422d05daSIan Lepore 	struct iic_reqbus_data *rd;
61422d05daSIan Lepore 	int err, i;
62422d05daSIan Lepore 
63422d05daSIan Lepore 	/* If it's not one of the operations we know about, bail early. */
64422d05daSIan Lepore 	if (index != IIC_REQUEST_BUS && index != IIC_RELEASE_BUS)
65422d05daSIan Lepore 		return (iic2errno(EOPNOTSUPP));
66422d05daSIan Lepore 
67422d05daSIan Lepore 	/*
68422d05daSIan Lepore 	 * Ensure that the data passed to us includes the device_t of the child
69422d05daSIan Lepore 	 * bus and device.  If missing, someone bypassed iicbus_request_bus()
70422d05daSIan Lepore 	 * and called this method directly using the old calling standard.  If
71422d05daSIan Lepore 	 * present, find the index of the child bus that called us.
72422d05daSIan Lepore 	 */
73422d05daSIan Lepore 	rd = (struct iic_reqbus_data *)data;
74422d05daSIan Lepore 	if (!(rd->flags & IIC_REQBUS_DEV))
75422d05daSIan Lepore 		return (iic2errno(EINVAL));
76422d05daSIan Lepore 
77422d05daSIan Lepore 	for (i = 0; i <= sc->maxbus && sc->childdevs[i] != rd->bus; ++i)
78422d05daSIan Lepore 		continue;
79422d05daSIan Lepore 	if (i > sc->maxbus)
80422d05daSIan Lepore 		return (iic2errno(ENOENT));
81422d05daSIan Lepore 
82422d05daSIan Lepore 	/*
83422d05daSIan Lepore 	 * If the operation is a release it "cannot fail".  Idle the downstream
84422d05daSIan Lepore 	 * bus, then release exclusive use of the upstream bus, and we're done.
85422d05daSIan Lepore 	 */
86422d05daSIan Lepore 	if (index == IIC_RELEASE_BUS) {
87422d05daSIan Lepore 		if (sc->debugmux > 0) {
88422d05daSIan Lepore 			device_printf(dev, "idle the bus for %s on bus %s\n",
89422d05daSIan Lepore 			    device_get_nameunit(rd->dev),
90422d05daSIan Lepore 			    device_get_nameunit(rd->bus));
91422d05daSIan Lepore 		}
92422d05daSIan Lepore 		IICMUX_BUS_SELECT(dev, IICMUX_SELECT_IDLE, rd);
93422d05daSIan Lepore 		iicbus_release_bus(sc->busdev, dev);
94422d05daSIan Lepore 		return (IIC_NOERR);
95422d05daSIan Lepore 	}
96422d05daSIan Lepore 
97422d05daSIan Lepore 	if (sc->debugmux > 0) {
98422d05daSIan Lepore 		device_printf(dev, "select bus idx %d for %s on bus %s\n", i,
99422d05daSIan Lepore 		    device_get_nameunit(rd->dev), device_get_nameunit(rd->bus));
100422d05daSIan Lepore 	}
101422d05daSIan Lepore 
102422d05daSIan Lepore 	/*
103422d05daSIan Lepore 	 * The operation is a request for exclusive use.  First we have to
104422d05daSIan Lepore 	 * request exclusive use of our upstream bus.  If multiple slave devices
105422d05daSIan Lepore 	 * from our different child buses attempt to do IO at the same time,
106422d05daSIan Lepore 	 * this is what ensures that they don't switch the bus out from under
107422d05daSIan Lepore 	 * each other. The first one in proceeds and others wait here (or get an
108422d05daSIan Lepore 	 * EWOULDBLOCK return if they're using IIC_DONTWAIT).
109422d05daSIan Lepore 	 */
110422d05daSIan Lepore 	if ((err = iicbus_request_bus(sc->busdev, dev, rd->flags)) != 0)
111422d05daSIan Lepore 		return (err); /* Already an IIC error code. */
112422d05daSIan Lepore 
113422d05daSIan Lepore 	/*
114422d05daSIan Lepore 	 * Now that we own exclusive use of the upstream bus, connect it to the
115422d05daSIan Lepore 	 * downstream bus where the request came from.
116422d05daSIan Lepore 	 */
117422d05daSIan Lepore 	if ((err = IICMUX_BUS_SELECT(dev, i, rd)) != 0)
118422d05daSIan Lepore 		iicbus_release_bus(sc->busdev, dev);
119422d05daSIan Lepore 
120422d05daSIan Lepore 	return (err);
121422d05daSIan Lepore }
122422d05daSIan Lepore 
123422d05daSIan Lepore static u_int
124422d05daSIan Lepore iicmux_get_frequency(device_t dev, u_char speed)
125422d05daSIan Lepore {
126422d05daSIan Lepore 	struct iicmux_softc *sc = device_get_softc(dev);
127422d05daSIan Lepore 
128422d05daSIan Lepore 	return (IICBUS_GET_FREQUENCY(sc->busdev, speed));
129422d05daSIan Lepore }
130422d05daSIan Lepore 
131422d05daSIan Lepore #ifdef FDT
132422d05daSIan Lepore static phandle_t
133422d05daSIan Lepore iicmux_get_node(device_t dev, device_t child)
134422d05daSIan Lepore {
135422d05daSIan Lepore 	struct iicmux_softc *sc = device_get_softc(dev);
136422d05daSIan Lepore 	int i;
137422d05daSIan Lepore 
138422d05daSIan Lepore 	for (i = 0; i <= sc->maxbus; ++i) {
139422d05daSIan Lepore 		if (sc->childdevs[i] == child)
140422d05daSIan Lepore 			return (sc->childnodes[i]);
141422d05daSIan Lepore 	}
142422d05daSIan Lepore 	return (0); /* null handle */
143422d05daSIan Lepore }
144422d05daSIan Lepore #endif
145422d05daSIan Lepore 
146422d05daSIan Lepore static int
147422d05daSIan Lepore iicmux_intr(device_t dev, int event, char *buf)
148422d05daSIan Lepore {
149422d05daSIan Lepore 	struct iicmux_softc *sc = device_get_softc(dev);
150422d05daSIan Lepore 
151422d05daSIan Lepore 	/* XXX iicbus_intr() in iiconf.c should return status. */
152422d05daSIan Lepore 
153422d05daSIan Lepore 	iicbus_intr(sc->busdev, event, buf);
154422d05daSIan Lepore 	return (0);
155422d05daSIan Lepore }
156422d05daSIan Lepore 
157422d05daSIan Lepore static int
158422d05daSIan Lepore iicmux_read(device_t dev, char *buf, int len, int *bytes, int last, int delay)
159422d05daSIan Lepore {
160422d05daSIan Lepore 	struct iicmux_softc *sc = device_get_softc(dev);
161422d05daSIan Lepore 
162422d05daSIan Lepore 	return (iicbus_read(sc->busdev, buf, len, bytes, last, delay));
163422d05daSIan Lepore }
164422d05daSIan Lepore 
165422d05daSIan Lepore static int
166422d05daSIan Lepore iicmux_repeated_start(device_t dev, u_char slave, int timeout)
167422d05daSIan Lepore {
168422d05daSIan Lepore 	struct iicmux_softc *sc = device_get_softc(dev);
169422d05daSIan Lepore 
170422d05daSIan Lepore 	return (iicbus_repeated_start(sc->busdev, slave, timeout));
171422d05daSIan Lepore }
172422d05daSIan Lepore 
173422d05daSIan Lepore static int
174422d05daSIan Lepore iicmux_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
175422d05daSIan Lepore {
176422d05daSIan Lepore 	struct iicmux_softc *sc = device_get_softc(dev);
177422d05daSIan Lepore 
178422d05daSIan Lepore 	return (iicbus_reset(sc->busdev, speed, addr, oldaddr));
179422d05daSIan Lepore }
180422d05daSIan Lepore 
181422d05daSIan Lepore static int
182422d05daSIan Lepore iicmux_start(device_t dev, u_char slave, int timeout)
183422d05daSIan Lepore {
184422d05daSIan Lepore 	struct iicmux_softc *sc = device_get_softc(dev);
185422d05daSIan Lepore 
186422d05daSIan Lepore 	return (iicbus_start(sc->busdev, slave, timeout));
187422d05daSIan Lepore }
188422d05daSIan Lepore 
189422d05daSIan Lepore static int
190422d05daSIan Lepore iicmux_stop(device_t dev)
191422d05daSIan Lepore {
192422d05daSIan Lepore 	struct iicmux_softc *sc = device_get_softc(dev);
193422d05daSIan Lepore 
194422d05daSIan Lepore 	return (iicbus_stop(sc->busdev));
195422d05daSIan Lepore }
196422d05daSIan Lepore 
197422d05daSIan Lepore static int
198422d05daSIan Lepore iicmux_transfer( device_t dev, struct iic_msg *msgs, uint32_t nmsgs)
199422d05daSIan Lepore {
200422d05daSIan Lepore 	struct iicmux_softc *sc = device_get_softc(dev);
201422d05daSIan Lepore 
202422d05daSIan Lepore 	return (iicbus_transfer(sc->busdev, msgs, nmsgs));
203422d05daSIan Lepore }
204422d05daSIan Lepore 
205422d05daSIan Lepore static int
206422d05daSIan Lepore iicmux_write(device_t dev, const char *buf, int len, int *bytes, int timeout)
207422d05daSIan Lepore {
208422d05daSIan Lepore 	struct iicmux_softc *sc = device_get_softc(dev);
209422d05daSIan Lepore 
210422d05daSIan Lepore 	return (iicbus_write(sc->busdev, buf, len, bytes, timeout));
211422d05daSIan Lepore }
212422d05daSIan Lepore 
213422d05daSIan Lepore /*------------------------------------------------------------------------------
214422d05daSIan Lepore  * iicmux helper functions, called by hardware-specific drivers.
215422d05daSIan Lepore  * All these functions return a standard errno value.
216422d05daSIan Lepore  *----------------------------------------------------------------------------*/
217422d05daSIan Lepore 
218422d05daSIan Lepore int
219422d05daSIan Lepore iicmux_add_child(device_t dev, device_t child, int busidx)
220422d05daSIan Lepore {
221422d05daSIan Lepore 	struct iicmux_softc *sc = device_get_softc(dev);
222422d05daSIan Lepore 
223a5910414SIan Lepore 	if (busidx >= sc->numbuses) {
224a5910414SIan Lepore 		device_printf(dev,
225a5910414SIan Lepore 		    "iicmux_add_child: bus idx %d too big", busidx);
226a5910414SIan Lepore 		return (EINVAL);
227a5910414SIan Lepore 	}
228a5910414SIan Lepore 	if (sc->childdevs[busidx] != NULL) {
229a5910414SIan Lepore 		device_printf(dev, "iicmux_add_child: bus idx %d already added",
230a5910414SIan Lepore 		    busidx);
231a5910414SIan Lepore 		return (EINVAL);
232a5910414SIan Lepore 	}
233422d05daSIan Lepore 
234422d05daSIan Lepore 	sc->childdevs[busidx] = child;
235422d05daSIan Lepore 	if (sc->maxbus < busidx)
236422d05daSIan Lepore 		sc->maxbus = busidx;
237422d05daSIan Lepore 
238422d05daSIan Lepore 	return (0);
239422d05daSIan Lepore }
240422d05daSIan Lepore 
241ca16c2b8SIan Lepore static int
242ca16c2b8SIan Lepore iicmux_attach_children(struct iicmux_softc *sc)
243422d05daSIan Lepore {
244ca16c2b8SIan Lepore 	int i;
245422d05daSIan Lepore #ifdef FDT
246422d05daSIan Lepore 	phandle_t child, node, parent;
247ca16c2b8SIan Lepore 	pcell_t idx;
248422d05daSIan Lepore 
249422d05daSIan Lepore 	/*
250422d05daSIan Lepore 	 * Find our FDT node.  Child nodes within our node will become our
251422d05daSIan Lepore 	 * iicbus children.
252422d05daSIan Lepore 	 */
253422d05daSIan Lepore 	if((node = ofw_bus_get_node(sc->dev)) == 0) {
254422d05daSIan Lepore 		device_printf(sc->dev, "cannot find FDT node\n");
255422d05daSIan Lepore 		return (ENOENT);
256422d05daSIan Lepore 	}
257422d05daSIan Lepore 
258422d05daSIan Lepore 	/*
259422d05daSIan Lepore 	 * First we have to see if there is a child node named "i2c-mux".  If it
260422d05daSIan Lepore 	 * exists, all children of that node are buses, else all children of the
261422d05daSIan Lepore 	 * device node are buses.
262422d05daSIan Lepore 	 */
263422d05daSIan Lepore 	if ((parent = ofw_bus_find_child(node, "i2c-mux")) == 0)
264422d05daSIan Lepore 		parent = node;
265422d05daSIan Lepore 
266422d05daSIan Lepore 	/*
267422d05daSIan Lepore 	 * Attach the children represented in the device tree.
268422d05daSIan Lepore 	 */
269422d05daSIan Lepore 	for (child = OF_child(parent); child != 0; child = OF_peer(child)) {
270ca16c2b8SIan Lepore 		if (OF_getencprop(child, "reg", &idx, sizeof(idx)) == -1) {
271ca16c2b8SIan Lepore 			device_printf(sc->dev,
272422d05daSIan Lepore 			    "child bus missing required 'reg' property\n");
273422d05daSIan Lepore 			continue;
274422d05daSIan Lepore 		}
275422d05daSIan Lepore 		if (idx >= sc->numbuses) {
276ca16c2b8SIan Lepore 			device_printf(sc->dev,
277422d05daSIan Lepore 			    "child bus 'reg' property %d exceeds the number "
278422d05daSIan Lepore 			    "of buses supported by the device (%d)\n",
279422d05daSIan Lepore 			    idx, sc->numbuses);
280422d05daSIan Lepore 			continue;
281422d05daSIan Lepore 		}
282*5b56413dSWarner Losh 		sc->childdevs[idx] = device_add_child(sc->dev, "iicbus", DEVICE_UNIT_ANY);
283422d05daSIan Lepore 		sc->childnodes[idx] = child;
284eda20682SAndriy Gapon 		if (sc->maxbus < (int)idx)
285422d05daSIan Lepore 			sc->maxbus = idx;
286422d05daSIan Lepore 	}
287ca16c2b8SIan Lepore 
288ca16c2b8SIan Lepore 	/* If we configured anything using FDT data, we're done. */
289ca16c2b8SIan Lepore 	if (sc->maxbus >= 0)
290ca16c2b8SIan Lepore 		return (0);
291422d05daSIan Lepore #endif /* FDT */
292422d05daSIan Lepore 
293422d05daSIan Lepore 	/*
294ca16c2b8SIan Lepore 	 * If we make it to here, we didn't add any children based on FDT data.
295ca16c2b8SIan Lepore 	 * Add an iicbus child for every downstream bus supported by the mux.
296422d05daSIan Lepore 	 */
297422d05daSIan Lepore 	for (i = 0; i < sc->numbuses; ++i) {
298*5b56413dSWarner Losh 		sc->childdevs[i] = device_add_child(sc->dev, "iicbus", DEVICE_UNIT_ANY);
299ca16c2b8SIan Lepore 		sc->maxbus = i;
300422d05daSIan Lepore 	}
301ca16c2b8SIan Lepore 
302ca16c2b8SIan Lepore 	return (0);
303ca16c2b8SIan Lepore }
304ca16c2b8SIan Lepore 
305ca16c2b8SIan Lepore int
306ca16c2b8SIan Lepore iicmux_attach(device_t dev, device_t busdev, int numbuses)
307ca16c2b8SIan Lepore {
308ca16c2b8SIan Lepore 	struct iicmux_softc *sc = device_get_softc(dev);
309ca16c2b8SIan Lepore 	int err;
310ca16c2b8SIan Lepore 
311ca16c2b8SIan Lepore 	if (numbuses >= IICMUX_MAX_BUSES) {
312ca16c2b8SIan Lepore 		device_printf(dev, "iicmux_attach: numbuses %d > max %d\n",
313ca16c2b8SIan Lepore 		    numbuses, IICMUX_MAX_BUSES);
314ca16c2b8SIan Lepore 		return (EINVAL);
315ca16c2b8SIan Lepore 	}
316ca16c2b8SIan Lepore 
317ca16c2b8SIan Lepore 	sc->dev = dev;
318ca16c2b8SIan Lepore 	sc->busdev = busdev;
319ca16c2b8SIan Lepore 	sc->maxbus = -1;
320ca16c2b8SIan Lepore 	sc->numbuses = numbuses;
321ca16c2b8SIan Lepore 
322ca16c2b8SIan Lepore 	if ((err = iicmux_attach_children(sc)) != 0)
323ca16c2b8SIan Lepore 		return (err);
324ca16c2b8SIan Lepore 
325ca16c2b8SIan Lepore 	SYSCTL_ADD_UINT(device_get_sysctl_ctx(sc->dev),
326ca16c2b8SIan Lepore 	    SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), OID_AUTO,
327ca16c2b8SIan Lepore 	    "debugmux", CTLFLAG_RWTUN, &sc->debugmux, 0, "debug mux operations");
328422d05daSIan Lepore 
329422d05daSIan Lepore 	return (0);
330422d05daSIan Lepore }
331422d05daSIan Lepore 
332422d05daSIan Lepore int
333422d05daSIan Lepore iicmux_detach(device_t dev)
334422d05daSIan Lepore {
335422d05daSIan Lepore 	struct iicmux_softc *sc = device_get_softc(dev);
336422d05daSIan Lepore 	int err, i;
337422d05daSIan Lepore 
338422d05daSIan Lepore 	/* Delete only the children we added in iicmux_add* functions. */
339422d05daSIan Lepore 	for (i = 0; i <= sc->maxbus; ++i) {
340422d05daSIan Lepore 		if (sc->childdevs[i] == NULL)
341422d05daSIan Lepore 			continue;
342422d05daSIan Lepore 		if ((err = device_delete_child(dev, sc->childdevs[i])) != 0)
343422d05daSIan Lepore 			return (err);
344422d05daSIan Lepore 		sc->childdevs[i] = NULL;
345422d05daSIan Lepore 	}
346422d05daSIan Lepore 
347422d05daSIan Lepore 	return (0);
348422d05daSIan Lepore }
349422d05daSIan Lepore 
350422d05daSIan Lepore static device_method_t iicmux_methods [] = {
351422d05daSIan Lepore 	/* iicbus_if methods */
352422d05daSIan Lepore 	DEVMETHOD(iicbus_intr,			iicmux_intr),
353422d05daSIan Lepore 	DEVMETHOD(iicbus_callback,		iicmux_callback),
354422d05daSIan Lepore 	DEVMETHOD(iicbus_repeated_start,	iicmux_repeated_start),
355422d05daSIan Lepore 	DEVMETHOD(iicbus_start,			iicmux_start),
356422d05daSIan Lepore 	DEVMETHOD(iicbus_stop,			iicmux_stop),
357422d05daSIan Lepore 	DEVMETHOD(iicbus_read,			iicmux_read),
358422d05daSIan Lepore 	DEVMETHOD(iicbus_write,			iicmux_write),
359422d05daSIan Lepore 	DEVMETHOD(iicbus_reset,			iicmux_reset),
360422d05daSIan Lepore 	DEVMETHOD(iicbus_transfer,		iicmux_transfer),
361422d05daSIan Lepore 	DEVMETHOD(iicbus_get_frequency,		iicmux_get_frequency),
362422d05daSIan Lepore 
363422d05daSIan Lepore #ifdef FDT
364422d05daSIan Lepore 	/* ofwbus_if methods */
365422d05daSIan Lepore 	DEVMETHOD(ofw_bus_get_node,		iicmux_get_node),
366422d05daSIan Lepore #endif
367422d05daSIan Lepore 
368422d05daSIan Lepore 	DEVMETHOD_END
369422d05daSIan Lepore };
370422d05daSIan Lepore 
371422d05daSIan Lepore static int
372422d05daSIan Lepore iicmux_modevent(module_t mod, int type, void *unused)
373422d05daSIan Lepore {
374422d05daSIan Lepore 	switch (type) {
375422d05daSIan Lepore 	case MOD_LOAD:
376422d05daSIan Lepore 		return 0;
377422d05daSIan Lepore 	case MOD_UNLOAD:
378422d05daSIan Lepore 		return 0;
379422d05daSIan Lepore 	}
380422d05daSIan Lepore 	return EINVAL;
381422d05daSIan Lepore }
382422d05daSIan Lepore 
383422d05daSIan Lepore static moduledata_t iicmux_mod = {
384422d05daSIan Lepore 	"iicmux",
385422d05daSIan Lepore 	iicmux_modevent,
386422d05daSIan Lepore 	0
387422d05daSIan Lepore };
388422d05daSIan Lepore 
389422d05daSIan Lepore DEFINE_CLASS_0(iicmux, iicmux_driver, iicmux_methods,
390422d05daSIan Lepore     sizeof(struct iicmux_softc));
391422d05daSIan Lepore 
392422d05daSIan Lepore DECLARE_MODULE(iicmux, iicmux_mod, SI_SUB_DRIVERS, SI_ORDER_ANY);
393422d05daSIan Lepore MODULE_VERSION(iicmux, 1);
394422d05daSIan Lepore 
395422d05daSIan Lepore MODULE_DEPEND(iicmux, iicbus, 1, 1, 1);
396