Index: head/share/man/man4/gpioiic.4 =================================================================== --- head/share/man/man4/gpioiic.4 (revision 355275) +++ head/share/man/man4/gpioiic.4 (revision 355276) @@ -1,171 +1,159 @@ .\" Copyright (c) 2013, Luiz Otavio O Souza .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" $FreeBSD$ .\" -.Dd May 14, 2014 +.Dd December 1, 2019 .Dt GPIOIIC 4 .Os .Sh NAME .Nm gpioiic .Nd GPIO I2C bit-banging device driver .Sh SYNOPSIS To compile this driver into the kernel, place the following lines in your kernel configuration file: .Bd -ragged -offset indent .Cd "device gpio" .Cd "device gpioiic" -.Cd "device iic" .Cd "device iicbb" .Cd "device iicbus" .Ed +.Pp +Alternatively, to load the driver as a +module at boot time, place the following line in +.Xr loader.conf 5 : +.Bd -literal -offset indent +gpioiic_load="YES" +.Ed .Sh DESCRIPTION The .Nm driver provides an IIC bit-banging interface using two GPIO pins for the -SCL and SDA on the -.Nm gpiobus . +SCL and SDA lines on the bus. +.Pp .Nm -implements an open collector kind of output, as recommended by the standard, -when driving the pins on the -.Nm gpiobus , -i.e, they are never switched to the logical value of '1', -or they are '0' or simply open (Hi-Z/tri-state). -So the pullup resistors are required so -.Nm -can work. +simulates an open collector kind of output when managing the pins on the +bus, even on systems which don't directly support configuring gpio pins +in that mode. +The pins are never driven to the logical value of '1'. +They are driven to '0' or switched to input mode (Hi-Z/tri-state), and +an external pullup resistor pulls the line to the 1 state unless some +other device on the bus is driving it to 0. .Pp +.Sh HINTS CONFIGURATION On a .Xr device.hints 5 -based system, like -.Li MIPS , -these values are configurable for the +based system, such as MIPS, these values are configurable for .Nm : .Bl -tag -width ".Va hint.gpioiic.%d.atXXX" .It Va hint.gpioiic.%d.at The .Nm gpiobus you are attaching to. -Normally just gpiobus0. +Normally just gpiobus0 on systems with a single bank of gpio pins. .It Va hint.gpioiic.%d.pins This is a bitmask of the pins on the .Nm gpiobus that are to be used for SCLOCK and SDATA from the GPIO IIC bit-banging bus. To configure pin 0 and 7, use the bitmask of 0b10000001 and convert it to a hexadecimal value of 0x0081. Please note that this mask should only ever have two bits set (any other bits - i.e., pins - will be ignored). +Because +.Nm +must be a child of the gpiobus, both gpio pins must be part of that bus. .It Va hint.gpioiic.%d.scl Indicates which bit in the .Va hint.gpioiic.%d.pins should be used as the SCLOCK source. Optional, defaults to 0. .It Va hint.gpioiic.%d.sda Indicates which bit in the .Va hint.gpioiic.%d.pins should be used as the SDATA source. Optional, defaults to 1. .El -.Pp -On a +.Sh FDT CONFIGURATION +On an .Xr FDT 4 -based system, like -.Li ARM , -the DTS part for a +based system, such as ARM, the DTS node for .Nm gpioiic -device usually looks like: +conforms to the standard bindings document i2c/i2c-gpio.yaml. +The device node typically appears at the root of the device tree. +The following is an example of a +.Nm +node with one slave device +on the IIC bus: .Bd -literal -gpio: gpio { - - gpio-controller; - ... - +/ { gpioiic0 { - compatible = "gpioiic"; - /* - * Attach to GPIO pins 21 and 22. Set them - * initially as inputs. - */ - gpios = <&gpio 21 1 0 - &gpio 22 1 0>; - scl = <0>; /* GPIO pin 21 - optional */ - sda = <1>; /* GPIO pin 22 - optional */ + compatible = "i2c-gpio"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpioiic0>; + scl-gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>; + sda-gpios = <&gpio7 11 GPIO_ACTIVE_HIGH>; + status = "okay"; - /* This is an example of a gpioiic child. */ - gpioiic-child0 { - compatible = "lm75"; - i2c-address = <0x4f>; + /* One slave device on the i2c bus. */ + rtc@51 { + compatible="nxp,pcf2127"; + reg = <0x51>; + status = "okay"; }; }; }; .Ed .Pp Where: .Bl -tag -width ".Va compatible" .It Va compatible -Should always be set to "gpioiic". -.It Va gpios -The -.Va gpios -property indicates which GPIO pins should be used for SCLOCK and SDATA -on the GPIO IIC bit-banging bus. -For more details about the -.Va gpios -property, please consult -.Pa /usr/src/sys/dts/bindings-gpio.txt . -.It Va scl -The -.Va scl -option indicates which bit in the -.Va gpios -should be used as the SCLOCK source. -Optional, defaults to 0. -.It Va sda -The -.Va sda -option indicates which bit in the -.Va gpios -should be used as the SDATA source. -Optional, defaults to 1. +Should be set to "i2c-gpio". +The deprecated string "gpioiic" is also accepted for backwards compatibility. +.It Va scl-gpios Va sda-gpios +These properties indicate which GPIO pins should be used for clock +and data on the GPIO IIC bit-banging bus. +There is no requirement that the two pins belong to the same gpio controller. +.It Va pinctrl-names pinctrl-0 +These properties may be required to configure the chosen pins as gpio +pins, unless the pins default to that state on your system. .El .Sh SEE ALSO .Xr fdt 4 , .Xr gpio 4 , -.Xr gpioled 4 , .Xr iic 4 , .Xr iicbb 4 , .Xr iicbus 4 .Sh HISTORY The .Nm manual page first appeared in .Fx 10.1 . .Sh AUTHORS This manual page was written by .An Luiz Otavio O Souza . Index: head/sys/dev/gpio/gpioiic.c =================================================================== --- head/sys/dev/gpio/gpioiic.c (revision 355275) +++ head/sys/dev/gpio/gpioiic.c (revision 355276) @@ -1,287 +1,363 @@ /*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2009 Oleksandr Tymoshenko - * Copyright (c) 2010 Luiz Otavio O Souza - * All rights reserved. + * Copyright (c) 2010 Luiz Otavio O Souza All rights reserved. + * Copyright (c) 2019 Ian Lepore * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include "opt_platform.h" #include #include #include #include #include #include -#ifdef FDT -#include -#include -#endif - #include #include -#include #include "gpiobus_if.h" #include "iicbb_if.h" #define GPIOIIC_SCL_DFLT 0 #define GPIOIIC_SDA_DFLT 1 #define GPIOIIC_MIN_PINS 2 struct gpioiic_softc { - device_t sc_dev; - device_t sc_busdev; - int scl_pin; - int sda_pin; + device_t dev; + gpio_pin_t sclpin; + gpio_pin_t sdapin; }; -static int gpioiic_probe(device_t); -static int gpioiic_attach(device_t); +#ifdef FDT -/* iicbb interface */ -static void gpioiic_reset_bus(device_t); -static void gpioiic_setsda(device_t, int); -static void gpioiic_setscl(device_t, int); -static int gpioiic_getsda(device_t); -static int gpioiic_getscl(device_t); -static int gpioiic_reset(device_t, u_char, u_char, u_char *); +#include +static struct ofw_compat_data compat_data[] = { + {"i2c-gpio", true}, /* Standard devicetree compat string */ + {"gpioiic", true}, /* Deprecated old freebsd compat string */ + {NULL, false} +}; +OFWBUS_PNP_INFO(compat_data); +SIMPLEBUS_PNP_INFO(compat_data); + +static phandle_t +gpioiic_get_node(device_t bus, device_t dev) +{ + + /* Share our fdt node with iicbus so it can find its child nodes. */ + return (ofw_bus_get_node(bus)); +} + static int -gpioiic_probe(device_t dev) +gpioiic_setup_fdt_pins(struct gpioiic_softc *sc) { - struct gpiobus_ivar *devi; + phandle_t node; + int err; -#ifdef FDT - if (!ofw_bus_status_okay(dev)) - return (ENXIO); - if (!ofw_bus_is_compatible(dev, "gpioiic")) - return (ENXIO); -#endif - devi = GPIOBUS_IVAR(dev); - if (devi->npins < GPIOIIC_MIN_PINS) { - device_printf(dev, - "gpioiic needs at least %d GPIO pins (only %d given).\n", - GPIOIIC_MIN_PINS, devi->npins); - return (ENXIO); - } - device_set_desc(dev, "GPIO I2C bit-banging driver"); + node = ofw_bus_get_node(sc->dev); - return (BUS_PROBE_DEFAULT); + /* + * Historically, we used the first two array elements of the gpios + * property. The modern bindings specify separate scl-gpios and + * sda-gpios properties. We cope with whichever is present. + */ + if (OF_hasprop(node, "gpios")) { + if ((err = gpio_pin_get_by_ofw_idx(sc->dev, node, + GPIOIIC_SCL_DFLT, &sc->sclpin)) != 0) { + device_printf(sc->dev, "invalid gpios property\n"); + return (err); + } + if ((err = gpio_pin_get_by_ofw_idx(sc->dev, node, + GPIOIIC_SDA_DFLT, &sc->sdapin)) != 0) { + device_printf(sc->dev, "ivalid gpios property\n"); + return (err); + } + } else { + if ((err = gpio_pin_get_by_ofw_property(sc->dev, node, + "scl-gpios", &sc->sclpin)) != 0) { + device_printf(sc->dev, "missing scl-gpios property\n"); + return (err); + } + if ((err = gpio_pin_get_by_ofw_property(sc->dev, node, + "sda-gpios", &sc->sdapin)) != 0) { + device_printf(sc->dev, "missing sda-gpios property\n"); + return (err); + } + } + return (0); } +#endif /* FDT */ static int -gpioiic_attach(device_t dev) +gpioiic_setup_hinted_pins(struct gpioiic_softc *sc) { - device_t bitbang; -#ifdef FDT - phandle_t node; - pcell_t pin; -#endif - struct gpiobus_ivar *devi; - struct gpioiic_softc *sc; + device_t busdev; + const char *busname, *devname; + int err, numpins, sclnum, sdanum, unit; - sc = device_get_softc(dev); - sc->sc_dev = dev; - sc->sc_busdev = device_get_parent(dev); - if (resource_int_value(device_get_name(dev), - device_get_unit(dev), "scl", &sc->scl_pin)) - sc->scl_pin = GPIOIIC_SCL_DFLT; - if (resource_int_value(device_get_name(dev), - device_get_unit(dev), "sda", &sc->sda_pin)) - sc->sda_pin = GPIOIIC_SDA_DFLT; + devname = device_get_name(sc->dev); + unit = device_get_unit(sc->dev); + busdev = device_get_parent(sc->dev); + /* + * If there is not an "at" hint naming our actual parent, then we + * weren't instantiated as a child of gpiobus via hints, and we thus + * can't access ivars that only exist for such children. + */ + if (resource_string_value(devname, unit, "at", &busname) != 0 || + (strcmp(busname, device_get_nameunit(busdev)) != 0 && + strcmp(busname, device_get_name(busdev)) != 0)) { + return (ENOENT); + } + + /* Make sure there were hints for at least two pins. */ + numpins = gpiobus_get_npins(sc->dev); + if (numpins < GPIOIIC_MIN_PINS) { #ifdef FDT - if ((node = ofw_bus_get_node(dev)) == -1) - return (ENXIO); - if (OF_getencprop(node, "scl", &pin, sizeof(pin)) > 0) - sc->scl_pin = (int)pin; - if (OF_getencprop(node, "sda", &pin, sizeof(pin)) > 0) - sc->sda_pin = (int)pin; + /* + * Be silent when there are no hints on FDT systems; the FDT + * data will provide the pin config (we'll whine if it doesn't). + */ + if (numpins == 0) { + return (ENOENT); + } #endif + device_printf(sc->dev, + "invalid pins hint; it must contain at least %d pins\n", + GPIOIIC_MIN_PINS); + return (EINVAL); + } - if (sc->scl_pin < 0 || sc->scl_pin > 1) - sc->scl_pin = GPIOIIC_SCL_DFLT; - if (sc->sda_pin < 0 || sc->sda_pin > 1) - sc->sda_pin = GPIOIIC_SDA_DFLT; + /* + * Our parent bus has already parsed the pins hint and it will use that + * info when we call gpio_pin_get_by_child_index(). But we have to + * handle the scl/sda index hints that tell us which of the two pins is + * the clock and which is the data. They're optional, but if present + * they must be a valid index (0 <= index < numpins). + */ + if ((err = resource_int_value(devname, unit, "scl", &sclnum)) != 0) + sclnum = GPIOIIC_SCL_DFLT; + else if (sclnum < 0 || sclnum >= numpins) { + device_printf(sc->dev, "invalid scl hint %d\n", sclnum); + return (EINVAL); + } + if ((err = resource_int_value(devname, unit, "sda", &sdanum)) != 0) + sdanum = GPIOIIC_SDA_DFLT; + else if (sdanum < 0 || sdanum >= numpins) { + device_printf(sc->dev, "invalid sda hint %d\n", sdanum); + return (EINVAL); + } - devi = GPIOBUS_IVAR(dev); - device_printf(dev, "SCL pin: %d, SDA pin: %d\n", - devi->pins[sc->scl_pin], devi->pins[sc->sda_pin]); + /* Allocate gpiobus_pin structs for the pins we found above. */ + if ((err = gpio_pin_get_by_child_index(sc->dev, sclnum, + &sc->sclpin)) != 0) + return (err); + if ((err = gpio_pin_get_by_child_index(sc->dev, sdanum, + &sc->sdapin)) != 0) + return (err); - /* add generic bit-banging code */ - bitbang = device_add_child(dev, "iicbb", -1); - device_probe_and_attach(bitbang); - return (0); } -static int -gpioiic_detach(device_t dev) -{ - - bus_generic_detach(dev); - device_delete_children(dev); - return (0); -} - -/* - * Reset bus by setting SDA first and then SCL. - * Must always be called with gpio bus locked. - */ static void -gpioiic_reset_bus(device_t dev) +gpioiic_setsda(device_t dev, int val) { - struct gpioiic_softc *sc = device_get_softc(dev); + struct gpioiic_softc *sc = device_get_softc(dev); + int err; - GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, sc->sda_pin, - GPIO_PIN_INPUT); - GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, sc->scl_pin, - GPIO_PIN_INPUT); + /* + * Some controllers cannot set an output value while a pin is in input + * mode; in that case we set the pin again after changing mode. + */ + err = gpio_pin_set_active(sc->sdapin, val); + gpio_pin_setflags(sc->sdapin, GPIO_PIN_OUTPUT | GPIO_PIN_OPENDRAIN); + if (err != 0) + gpio_pin_set_active(sc->sdapin, val); } static void -gpioiic_setpin(struct gpioiic_softc *sc, int pin, int val) +gpioiic_setscl(device_t dev, int val) { - int err; + struct gpioiic_softc *sc = device_get_softc(dev); - if (val == 0) { - err = GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev, pin, 0); - GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, pin, - GPIO_PIN_OUTPUT); - - /* - * Some controllers cannot set output value while a pin is in - * input mode. - */ - if (err != 0) - GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev, pin, 0); - } else { - GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, pin, - GPIO_PIN_INPUT); - } + gpio_pin_setflags(sc->sclpin, GPIO_PIN_OUTPUT | GPIO_PIN_OPENDRAIN); + gpio_pin_set_active(sc->sclpin, val); } -static void -gpioiic_setsda(device_t dev, int val) +static int +gpioiic_getscl(device_t dev) { - struct gpioiic_softc *sc = device_get_softc(dev); + struct gpioiic_softc *sc = device_get_softc(dev); + bool val; - gpioiic_setpin(sc, sc->sda_pin, val); + gpio_pin_setflags(sc->sclpin, GPIO_PIN_INPUT); + gpio_pin_is_active(sc->sclpin, &val); + return (val); } -static void -gpioiic_setscl(device_t dev, int val) +static int +gpioiic_getsda(device_t dev) { - struct gpioiic_softc *sc = device_get_softc(dev); + struct gpioiic_softc *sc = device_get_softc(dev); + bool val; - gpioiic_setpin(sc, sc->scl_pin, val); + gpio_pin_setflags(sc->sdapin, GPIO_PIN_INPUT); + gpio_pin_is_active(sc->sdapin, &val); + return (val); } static int -gpioiic_getpin(struct gpioiic_softc *sc, int pin) +gpioiic_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr) { - unsigned int val; + struct gpioiic_softc *sc = device_get_softc(dev); - GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, pin, GPIO_PIN_INPUT); - GPIOBUS_PIN_GET(sc->sc_busdev, sc->sc_dev, pin, &val); - return ((int)val); + /* Stop driving the bus pins. */ + gpio_pin_setflags(sc->sdapin, GPIO_PIN_INPUT); + gpio_pin_setflags(sc->sclpin, GPIO_PIN_INPUT); + + /* Indicate that we have no slave address (master mode). */ + return (IIC_ENOADDR); } -static int -gpioiic_getscl(device_t dev) +static void +gpioiic_cleanup(struct gpioiic_softc *sc) { - struct gpioiic_softc *sc = device_get_softc(dev); - return (gpioiic_getpin(sc, sc->scl_pin)); + device_delete_children(sc->dev); + + if (sc->sclpin != NULL) + gpio_pin_release(sc->sclpin); + + if (sc->sdapin != NULL) + gpio_pin_release(sc->sdapin); } static int -gpioiic_getsda(device_t dev) +gpioiic_probe(device_t dev) { - struct gpioiic_softc *sc = device_get_softc(dev); + int rv; - return (gpioiic_getpin(sc, sc->sda_pin)); + /* + * By default we only bid to attach if specifically added by our parent + * (usually via hint.gpioiic.#.at=busname). On FDT systems we bid as + * the default driver based on being configured in the FDT data. + */ + rv = BUS_PROBE_NOWILDCARD; + +#ifdef FDT + if (ofw_bus_status_okay(dev) && + ofw_bus_search_compatible(dev, compat_data)->ocd_data) + rv = BUS_PROBE_DEFAULT; +#endif + + device_set_desc(dev, "GPIO I2C"); + + return (rv); } static int -gpioiic_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr) +gpioiic_attach(device_t dev) { - struct gpioiic_softc *sc; + struct gpioiic_softc *sc = device_get_softc(dev); + int err; - sc = device_get_softc(dev); - gpioiic_reset_bus(sc->sc_dev); + sc->dev = dev; - return (IIC_ENOADDR); + /* Acquire our gpio pins. */ + err = gpioiic_setup_hinted_pins(sc); +#ifdef FDT + if (err != 0) + err = gpioiic_setup_fdt_pins(sc); +#endif + if (err != 0) { + device_printf(sc->dev, "no pins configured\n"); + gpioiic_cleanup(sc); + return (ENXIO); + } + + /* Say what we came up with for pin config. */ + device_printf(dev, "SCL pin: %s:%d, SDA pin: %s:%d\n", + device_get_nameunit(GPIO_GET_BUS(sc->sclpin->dev)), sc->sclpin->pin, + device_get_nameunit(GPIO_GET_BUS(sc->sdapin->dev)), sc->sdapin->pin); + + /* Add the bitbang driver as our only child; it will add iicbus. */ + device_add_child(sc->dev, "iicbb", -1); + return (bus_generic_attach(dev)); } -#ifdef FDT -static phandle_t -gpioiic_get_node(device_t bus, device_t dev) +static int +gpioiic_detach(device_t dev) { + struct gpioiic_softc *sc = device_get_softc(dev); + int err; - /* We only have one child, the iicbb, which needs our own node. */ - return (ofw_bus_get_node(bus)); + if ((err = bus_generic_detach(dev)) != 0) + return (err); + + gpioiic_cleanup(sc); + + return (0); } -#endif static devclass_t gpioiic_devclass; static device_method_t gpioiic_methods[] = { /* Device interface */ DEVMETHOD(device_probe, gpioiic_probe), DEVMETHOD(device_attach, gpioiic_attach), DEVMETHOD(device_detach, gpioiic_detach), /* iicbb interface */ DEVMETHOD(iicbb_setsda, gpioiic_setsda), DEVMETHOD(iicbb_setscl, gpioiic_setscl), DEVMETHOD(iicbb_getsda, gpioiic_getsda), DEVMETHOD(iicbb_getscl, gpioiic_getscl), DEVMETHOD(iicbb_reset, gpioiic_reset), #ifdef FDT /* OFW bus interface */ DEVMETHOD(ofw_bus_get_node, gpioiic_get_node), #endif DEVMETHOD_END }; static driver_t gpioiic_driver = { "gpioiic", gpioiic_methods, sizeof(struct gpioiic_softc), }; DRIVER_MODULE(gpioiic, gpiobus, gpioiic_driver, gpioiic_devclass, 0, 0); +DRIVER_MODULE(gpioiic, simplebus, gpioiic_driver, gpioiic_devclass, 0, 0); DRIVER_MODULE(iicbb, gpioiic, iicbb_driver, iicbb_devclass, 0, 0); MODULE_DEPEND(gpioiic, iicbb, IICBB_MINVER, IICBB_PREFVER, IICBB_MAXVER); MODULE_DEPEND(gpioiic, gpiobus, 1, 1, 1);