Date: Thu, 12 Dec 2013 17:19:52 -0200 From: Luiz Otavio O Souza <loos.br@gmail.com> To: freebsd-arch@FreeBSD.org Cc: freebsd-arm@freebsd.org Subject: Re: FDT Support for GPIO (gpiobus and friends) Message-ID: <598EB94E-817C-47E9-BBA5-F6E6D5A1B2BA@gmail.com> In-Reply-To: <7DBC8BB4-8CEF-48E0-BB6B-40C00F71284A@gmail.com> References: <BEB9A0F8-560B-4937-8707-653988A26D85@gmail.com> <20121205.060056.592894859995638978.hrs@allbsd.org> <B97B1170-69AD-4AA2-A111-1B9539C71BC3@gmail.com> <7DBC8BB4-8CEF-48E0-BB6B-40C00F71284A@gmail.com>
next in thread | previous in thread | raw e-mail | index | archive | help
--Apple-Mail=_8AC709E8-28F7-4B23-B62B-026FF9B7E725 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=windows-1252 On Nov 26, 2013, at 4:44 PM, Luiz Otavio O Souza <loos.br@gmail.com> = wrote: > Right, so after playing a little bit with IIC and SPI on FDT i have = now a patch, which i believe, is more clean and complete to support an = OFW GPIO bus in the same way as it has been done with IIC and SPI. >=20 > The first patch (001-ofw-gpiobus.diff) implements the OFW GPIO bus and = all the changes to make possible to the available gpio devices (gpioled = and gpioiic) attach to it. >=20 > The second patch (002-iicbb-ofw-iicbus.diff) implements the changes to = make the OFW IIC bus attach to a gpioiic bit-banging (iicbb(4)) kind of = driver. >=20 > The third patch (006-ofw-gpio-man.diff) has the manual changes for = gpioiic and gpioled. >=20 > I would appreciate if you people could take a look and give me some = feedback. Okay, so here are the updated patches (updated to apply clean after the = last changes). I=92ve added one missing patch (000-gpio-node.diff) which gives access = to FDT node of the gpio controller to GPIO OFW bus. For now, this last patch is only for RPi and BBB. Both are tested and = known to work with gpioled(4) and gpioiic(4). There is an additional patch (000-bbb-gpioled.diff) which shows what is = needed to setup gpioled on BBB. In the next days, i=92ll check the changes for regressions with some non = FDT boards and if everything is okay and nobody objects, i=92ll ask for = permission to commit it. Comments ? Luiz --Apple-Mail=_8AC709E8-28F7-4B23-B62B-026FF9B7E725 Content-Disposition: attachment; filename=001-ofw-gpiobus.diff Content-Type: application/octet-stream; name="001-ofw-gpiobus.diff" Content-Transfer-Encoding: 7bit Index: sys/conf/files =================================================================== --- sys/conf/files (revision 259130) +++ sys/conf/files (working copy) @@ -1436,6 +1436,7 @@ dev/gpio/gpioled.c optional gpioled dev/gpio/gpio_if.m optional gpio dev/gpio/gpiobus_if.m optional gpio +dev/gpio/ofw_gpiobus.c optional fdt gpio dev/hatm/if_hatm.c optional hatm pci dev/hatm/if_hatm_intr.c optional hatm pci dev/hatm/if_hatm_ioctl.c optional hatm pci Index: sys/dev/gpio/gpiobus.c =================================================================== --- sys/dev/gpio/gpiobus.c (revision 259130) +++ sys/dev/gpio/gpiobus.c (working copy) @@ -46,7 +46,6 @@ #include "gpio_if.h" #include "gpiobus_if.h" -static void gpiobus_print_pins(struct gpiobus_ivar *); static int gpiobus_parse_pins(struct gpiobus_softc *, device_t, int); static int gpiobus_probe(device_t); static int gpiobus_attach(device_t); @@ -73,17 +72,7 @@ static int gpiobus_pin_get(device_t, device_t, uint32_t, unsigned int*); static int gpiobus_pin_toggle(device_t, device_t, uint32_t); -#define GPIOBUS_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) -#define GPIOBUS_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) -#define GPIOBUS_LOCK_INIT(_sc) \ - mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), \ - "gpiobus", MTX_DEF) -#define GPIOBUS_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx); -#define GPIOBUS_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED); -#define GPIOBUS_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED); - - -static void +void gpiobus_print_pins(struct gpiobus_ivar *devi) { int range_start, range_stop, need_coma; Index: sys/dev/gpio/gpiobusvar.h =================================================================== --- sys/dev/gpio/gpiobusvar.h (revision 259130) +++ sys/dev/gpio/gpiobusvar.h (working copy) @@ -30,13 +30,26 @@ #ifndef __GPIOBUS_H__ #define __GPIOBUS_H__ +#include "opt_platform.h" + #include <sys/param.h> #include <sys/lock.h> #include <sys/mutex.h> -#define GPIOBUS_IVAR(d) (struct gpiobus_ivar *) device_get_ivars(d) -#define GPIOBUS_SOFTC(d) (struct gpiobus_softc *) device_get_softc(d) +#ifdef FDT +#include <dev/ofw/ofw_bus_subr.h> +#endif +#define GPIOBUS_IVAR(d) (struct gpiobus_ivar *) device_get_ivars(d) +#define GPIOBUS_SOFTC(d) (struct gpiobus_softc *) device_get_softc(d) +#define GPIOBUS_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) +#define GPIOBUS_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) +#define GPIOBUS_LOCK_INIT(_sc) mtx_init(&_sc->sc_mtx, \ + device_get_nameunit(_sc->sc_dev), "gpiobus", MTX_DEF) +#define GPIOBUS_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx) +#define GPIOBUS_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED) +#define GPIOBUS_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED) + struct gpiobus_softc { struct mtx sc_mtx; /* bus mutex */ @@ -54,4 +67,11 @@ uint32_t *pins; /* pins map */ }; +void gpiobus_print_pins(struct gpiobus_ivar *); +#ifdef FDT +device_t ofw_gpiobus_add_fdt_child(device_t, phandle_t); +#endif + +extern driver_t gpiobus_driver; + #endif /* __GPIOBUS_H__ */ Index: sys/dev/gpio/gpioiic.c =================================================================== --- sys/dev/gpio/gpioiic.c (revision 259130) +++ sys/dev/gpio/gpioiic.c (working copy) @@ -28,6 +28,8 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); +#include "opt_platform.h" + #include <sys/param.h> #include <sys/systm.h> #include <sys/bus.h> @@ -38,6 +40,12 @@ #include <sys/gpio.h> #include "gpiobus_if.h" +#ifdef FDT +#include <dev/ofw/ofw_bus.h> +#include <dev/ofw/ofw_bus_subr.h> +#include <dev/fdt/fdt_common.h> +#endif + #include <dev/iicbus/iiconf.h> #include <dev/iicbus/iicbus.h> @@ -71,6 +79,10 @@ gpioiic_probe(device_t dev) { +#ifdef FDT + if (!ofw_bus_is_compatible(dev, "gpioiic")) + return (ENXIO); +#endif device_set_desc(dev, "GPIO I2C bit-banging driver"); return (0); @@ -81,6 +93,10 @@ { struct gpioiic_softc *sc = device_get_softc(dev); device_t bitbang; +#ifdef FDT + phandle_t node; + pcell_t pin; +#endif sc->sc_dev = dev; sc->sc_busdev = device_get_parent(dev); @@ -91,6 +107,15 @@ device_get_unit(dev), "sda", &sc->sda_pin)) sc->sda_pin = SDA_PIN_DEFAULT; +#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; +#endif + /* add generic bit-banging code */ bitbang = device_add_child(dev, "iicbb", -1); device_probe_and_attach(bitbang); @@ -209,6 +234,16 @@ return (IIC_ENOADDR); } +#ifdef FDT +static phandle_t +gpioiic_get_node(device_t bus, device_t dev) +{ + + /* We only have one child, the iicbb, which needs our own node. */ + return (ofw_bus_get_node(bus)); +} +#endif + static devclass_t gpioiic_devclass; static device_method_t gpioiic_methods[] = { @@ -225,6 +260,11 @@ DEVMETHOD(iicbb_getscl, gpioiic_getscl), DEVMETHOD(iicbb_reset, gpioiic_reset), +#ifdef FDT + /* OFW bus interface */ + DEVMETHOD(ofw_bus_get_node, gpioiic_get_node), +#endif + { 0, 0 } }; Index: sys/dev/gpio/gpioled.c =================================================================== --- sys/dev/gpio/gpioled.c (revision 259130) +++ sys/dev/gpio/gpioled.c (working copy) @@ -27,6 +27,8 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); +#include "opt_platform.h" + #include <sys/param.h> #include <sys/systm.h> #include <sys/bio.h> @@ -39,6 +41,12 @@ #include <sys/module.h> #include <sys/mutex.h> +#ifdef FDT +#include <dev/fdt/fdt_common.h> +#include <dev/gpio/gpiobusvar.h> +#include <dev/ofw/ofw_bus.h> +#endif + #include <dev/led/led.h> #include <sys/gpio.h> #include "gpiobus_if.h" @@ -84,10 +92,65 @@ GPIOLED_UNLOCK(sc); } +#ifdef FDT +static void +gpioled_identify(driver_t *driver, device_t bus) +{ + phandle_t child, leds, root; + + root = OF_finddevice("/"); + if (root == 0) + return; + leds = fdt_find_compatible(root, "gpio-leds", 1); + if (leds == 0) + return; + + /* Traverse the 'gpio-leds' node and add its children. */ + for (child = OF_child(leds); child != 0; child = OF_peer(child)) + if (ofw_gpiobus_add_fdt_child(bus, child) == NULL) + continue; +} +#endif + static int gpioled_probe(device_t dev) { +#ifdef FDT + int match; + phandle_t node; + char *compat; + + /* + * We can match against our own node compatible string and also against + * our parent node compatible string. The first is normally used to + * describe leds on a gpiobus and the later when there is a common node + * compatible with 'gpio-leds' which is used to concentrate all the + * leds nodes on the dts. + */ + match = 0; + if (ofw_bus_is_compatible(dev, "gpioled")) + match = 1; + + if (match == 0) { + if ((node = ofw_bus_get_node(dev)) == -1) + return (ENXIO); + if ((node = OF_parent(node)) == -1) + return (ENXIO); + if (OF_getprop_alloc(node, "compatible", 1, + (void **)&compat) == -1) + return (ENXIO); + + if (strcasecmp(compat, "gpio-leds") == 0) + match = 1; + + free(compat, M_OFWPROP); + } + + if (match == 0) + return (ENXIO); +#endif device_set_desc(dev, "GPIO led"); + return (0); } @@ -95,18 +158,35 @@ gpioled_attach(device_t dev) { struct gpioled_softc *sc; +#ifdef FDT + phandle_t node; + char *name; +#else const char *name; +#endif sc = device_get_softc(dev); sc->sc_dev = dev; sc->sc_busdev = device_get_parent(dev); GPIOLED_LOCK_INIT(sc); +#ifdef FDT + name = NULL; + if ((node = ofw_bus_get_node(dev)) == -1) + return (ENXIO); + if (OF_getprop_alloc(node, "label", 1, (void **)&name) == -1) + OF_getprop_alloc(node, "name", 1, (void **)&name); +#else if (resource_string_value(device_get_name(dev), device_get_unit(dev), "name", &name)) name = NULL; +#endif sc->sc_leddev = led_create(gpioled_control, sc, name ? name : device_get_nameunit(dev)); +#ifdef FDT + if (name != NULL) + free(name, M_OFWPROP); +#endif return (0); } @@ -129,6 +209,9 @@ static device_method_t gpioled_methods[] = { /* Device interface */ +#ifdef FDT + DEVMETHOD(device_identify, gpioled_identify), +#endif DEVMETHOD(device_probe, gpioled_probe), DEVMETHOD(device_attach, gpioled_attach), DEVMETHOD(device_detach, gpioled_detach), --- /dev/null 2013-12-12 17:00:00.000000000 -0200 +++ sys/dev/gpio/ofw_gpiobus.c 2013-11-25 10:15:00.322070491 -0200 @@ -0,0 +1,342 @@ +/*- + * Copyright (c) 2009, Nathan Whitehorn <nwhitehorn@FreeBSD.org> + * Copyright (c) 2013, Luiz Otavio O Souza <loos@FreeBSD.org> + * Copyright (c) 2013 The FreeBSD Foundation + * 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 unmodified, 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 ``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 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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/bus.h> +#include <sys/gpio.h> +#include <sys/kernel.h> +#include <sys/libkern.h> +#include <sys/lock.h> +#include <sys/module.h> +#include <sys/mutex.h> + +#include <dev/fdt/fdt_common.h> +#include <dev/gpio/gpiobusvar.h> +#include <dev/ofw/ofw_bus.h> +#include <dev/ofw/openfirm.h> + +#include <machine/resource.h> + +#include "gpio_if.h" +#include "gpiobus_if.h" + +struct ofw_gpiobus_devinfo { + struct gpiobus_ivar opd_dinfo; + struct ofw_bus_devinfo opd_obdinfo; +}; + +static int ofw_gpiobus_parse_gpios(struct gpiobus_softc *, + struct gpiobus_ivar *, phandle_t); +static struct ofw_gpiobus_devinfo *ofw_gpiobus_setup_devinfo(device_t, + phandle_t); +static void ofw_gpiobus_destroy_devinfo(struct ofw_gpiobus_devinfo *); + +device_t +ofw_gpiobus_add_fdt_child(device_t bus, phandle_t child) +{ + struct ofw_gpiobus_devinfo *dinfo; + device_t childdev; + + /* + * Set up the GPIO child and OFW bus layer devinfo and add it to bus. + */ + dinfo = ofw_gpiobus_setup_devinfo(bus, child); + if (dinfo == NULL) + return (NULL); + childdev = device_add_child(bus, NULL, -1); + if (childdev == NULL) { + device_printf(bus, "could not add child: %s\n", + dinfo->opd_obdinfo.obd_name); + ofw_gpiobus_destroy_devinfo(dinfo); + return (NULL); + } + device_set_ivars(childdev, dinfo); + + return (childdev); +} + +static int +ofw_gpiobus_parse_gpios(struct gpiobus_softc *sc, struct gpiobus_ivar *dinfo, + phandle_t child) +{ + int i, len; + pcell_t *gpios; + phandle_t gpio; + + /* Check and process 'status' property. */ + if (!(fdt_is_enabled(child))) + return (ENXIO); + + /* Retrieve the gpios property. */ + if ((len = OF_getproplen(child, "gpios")) < 0) + return (EINVAL); + gpios = malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO); + if (gpios == NULL) + return (ENOMEM); + if (OF_getencprop(child, "gpios", gpios, len) < 0) { + free(gpios, M_DEVBUF); + return (EINVAL); + } + + /* + * Each 'gpios' entry must contain 4 pcells. + * The first one is the GPIO controller phandler. + * Then the last three are the GPIO pin, the GPIO pin direction and + * the GPIO pin flags. + */ + if ((len / sizeof(pcell_t)) % 4) { + free(gpios, M_DEVBUF); + return (EINVAL); + } + dinfo->npins = len / (sizeof(pcell_t) * 4); + dinfo->pins = malloc(sizeof(uint32_t) * dinfo->npins, M_DEVBUF, + M_NOWAIT | M_ZERO); + if (dinfo->pins == NULL) { + free(gpios, M_DEVBUF); + return (ENOMEM); + } + + for (i = 0; i < dinfo->npins; i++) { + + /* Verify if we're attaching to the correct gpio controller. */ + gpio = OF_xref_phandle(gpios[i * 4 + 0]); + if (!OF_hasprop(gpio, "gpio-controller") || + gpio != ofw_bus_get_node(sc->sc_dev)) { + free(dinfo->pins, M_DEVBUF); + free(gpios, M_DEVBUF); + return (EINVAL); + } + + /* Get the GPIO pin number. */ + dinfo->pins[i] = gpios[i * 4 + 1]; + /* gpios[i * 4 + 2] - GPIO pin direction */ + /* gpios[i * 4 + 3] - GPIO pin flags */ + + if (dinfo->pins[i] > sc->sc_npins) { + device_printf(sc->sc_busdev, + "invalid pin %d, max: %d\n", + dinfo->pins[i], sc->sc_npins - 1); + free(dinfo->pins, M_DEVBUF); + free(gpios, M_DEVBUF); + return (EINVAL); + } + + /* + * Mark pin as mapped and give warning if it's already mapped. + */ + if (sc->sc_pins_mapped[dinfo->pins[i]]) { + device_printf(sc->sc_busdev, + "warning: pin %d is already mapped\n", + dinfo->pins[i]); + free(dinfo->pins, M_DEVBUF); + free(gpios, M_DEVBUF); + return (EINVAL); + } + sc->sc_pins_mapped[dinfo->pins[i]] = 1; + } + + free(gpios, M_DEVBUF); + + return (0); +} + +static struct ofw_gpiobus_devinfo * +ofw_gpiobus_setup_devinfo(device_t dev, phandle_t node) +{ + struct gpiobus_softc *sc; + struct ofw_gpiobus_devinfo *dinfo; + + sc = device_get_softc(dev); + dinfo = malloc(sizeof(*dinfo), M_DEVBUF, M_NOWAIT | M_ZERO); + if (dinfo == NULL) + return (NULL); + if (ofw_bus_gen_setup_devinfo(&dinfo->opd_obdinfo, node) != 0) { + free(dinfo, M_DEVBUF); + return (NULL); + } + + /* Parse the gpios property for the child. */ + if (ofw_gpiobus_parse_gpios(sc, &dinfo->opd_dinfo, node) != 0) { + ofw_bus_gen_destroy_devinfo(&dinfo->opd_obdinfo); + free(dinfo, M_DEVBUF); + return (NULL); + } + + return (dinfo); +} + +static void +ofw_gpiobus_destroy_devinfo(struct ofw_gpiobus_devinfo *dinfo) +{ + + ofw_bus_gen_destroy_devinfo(&dinfo->opd_obdinfo); + free(dinfo, M_DEVBUF); +} + +static int +ofw_gpiobus_probe(device_t dev) +{ + + if (ofw_bus_get_node(dev) == -1) + return (ENXIO); + device_set_desc(dev, "OFW GPIO bus"); + + return (0); +} + +static int +ofw_gpiobus_attach(device_t dev) +{ + struct gpiobus_softc *sc; + phandle_t child; + + sc = GPIOBUS_SOFTC(dev); + sc->sc_busdev = dev; + sc->sc_dev = device_get_parent(dev); + + /* Read the pin max. value */ + if (GPIO_PIN_MAX(sc->sc_dev, &sc->sc_npins) != 0) + return (ENXIO); + + KASSERT(sc->sc_npins != 0, ("GPIO device with no pins")); + + /* + * Increase to get number of pins. + */ + sc->sc_npins++; + + sc->sc_pins_mapped = malloc(sizeof(int) * sc->sc_npins, M_DEVBUF, + M_NOWAIT | M_ZERO); + + if (!sc->sc_pins_mapped) + return (ENOMEM); + + /* Init the bus lock. */ + GPIOBUS_LOCK_INIT(sc); + + bus_generic_probe(dev); + bus_enumerate_hinted_children(dev); + + /* + * Attach the children represented in the device tree. + */ + for (child = OF_child(ofw_bus_get_node(dev)); child != 0; + child = OF_peer(child)) + if (ofw_gpiobus_add_fdt_child(dev, child) == NULL) + continue; + + return (bus_generic_attach(dev)); +} + +static device_t +ofw_gpiobus_add_child(device_t dev, u_int order, const char *name, int unit) +{ + device_t child; + struct ofw_gpiobus_devinfo *devi; + + child = device_add_child_ordered(dev, order, name, unit); + if (child == NULL) + return (child); + devi = malloc(sizeof(struct ofw_gpiobus_devinfo), M_DEVBUF, + M_NOWAIT | M_ZERO); + if (devi == NULL) { + device_delete_child(dev, child); + return (0); + } + + /* + * NULL all the OFW-related parts of the ivars for non-OFW + * children. + */ + devi->opd_obdinfo.obd_node = -1; + devi->opd_obdinfo.obd_name = NULL; + devi->opd_obdinfo.obd_compat = NULL; + devi->opd_obdinfo.obd_type = NULL; + devi->opd_obdinfo.obd_model = NULL; + + device_set_ivars(child, devi); + + return (child); +} + +static int +ofw_gpiobus_print_child(device_t dev, device_t child) +{ + struct ofw_gpiobus_devinfo *devi; + int retval = 0; + + devi = device_get_ivars(child); + retval += bus_print_child_header(dev, child); + retval += printf(" at pin(s) "); + gpiobus_print_pins(&devi->opd_dinfo); + retval += bus_print_child_footer(dev, child); + + return (retval); +} + +static const struct ofw_bus_devinfo * +ofw_gpiobus_get_devinfo(device_t bus, device_t dev) +{ + struct ofw_gpiobus_devinfo *dinfo; + + dinfo = device_get_ivars(dev); + + return (&dinfo->opd_obdinfo); +} + +static device_method_t ofw_gpiobus_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, ofw_gpiobus_probe), + DEVMETHOD(device_attach, ofw_gpiobus_attach), + + /* Bus interface */ + DEVMETHOD(bus_child_pnpinfo_str, ofw_bus_gen_child_pnpinfo_str), + DEVMETHOD(bus_print_child, ofw_gpiobus_print_child), + DEVMETHOD(bus_add_child, ofw_gpiobus_add_child), + + /* ofw_bus interface */ + DEVMETHOD(ofw_bus_get_devinfo, ofw_gpiobus_get_devinfo), + DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), + DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), + DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), + DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), + DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), + + DEVMETHOD_END +}; + +static devclass_t ofwgpiobus_devclass; + +DEFINE_CLASS_1(gpiobus, ofw_gpiobus_driver, ofw_gpiobus_methods, + sizeof(struct gpiobus_softc), gpiobus_driver); +DRIVER_MODULE(ofw_gpiobus, gpio, ofw_gpiobus_driver, ofwgpiobus_devclass, 0, 0); +MODULE_VERSION(ofw_gpiobus, 1); +MODULE_DEPEND(ofw_gpiobus, gpiobus, 1, 1, 1); --Apple-Mail=_8AC709E8-28F7-4B23-B62B-026FF9B7E725 Content-Disposition: attachment; filename=002-iicbb-ofw-iicbus.diff Content-Type: application/octet-stream; name="002-iicbb-ofw-iicbus.diff" Content-Transfer-Encoding: 7bit Index: sys/dev/iicbus/iicbb.c =================================================================== --- sys/dev/iicbus/iicbb.c (revision 258138) +++ sys/dev/iicbus/iicbb.c (working copy) @@ -43,6 +43,8 @@ * */ +#include "opt_platform.h" + #include <sys/param.h> #include <sys/kernel.h> #include <sys/systm.h> @@ -50,6 +52,11 @@ #include <sys/bus.h> #include <sys/uio.h> +#ifdef FDT +#include <dev/ofw/ofw_bus.h> +#include <dev/ofw/ofw_bus_subr.h> +#include <dev/fdt/fdt_common.h> +#endif #include <dev/iicbus/iiconf.h> #include <dev/iicbus/iicbus.h> @@ -77,6 +84,9 @@ static int iicbb_read(device_t, char *, int, int *, int, int); static int iicbb_reset(device_t, u_char, u_char, u_char *); static int iicbb_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs); +#ifdef FDT +static phandle_t iicbb_get_node(device_t, device_t); +#endif static device_method_t iicbb_methods[] = { /* device interface */ @@ -98,6 +108,11 @@ DEVMETHOD(iicbus_reset, iicbb_reset), DEVMETHOD(iicbus_transfer, iicbb_transfer), +#ifdef FDT + /* ofw_bus interface */ + DEVMETHOD(ofw_bus_get_node, iicbb_get_node), +#endif + { 0, 0 } }; @@ -154,6 +169,16 @@ return (0); } +#ifdef FDT +static phandle_t +iicbb_get_node(device_t bus, device_t dev) +{ + + /* We only have one child, the I2C bus, which needs our own node. */ + return (ofw_bus_get_node(bus)); +} +#endif + static void iicbb_child_detached( device_t dev, device_t child ) { Index: sys/dev/ofw/ofw_iicbus.c =================================================================== --- sys/dev/ofw/ofw_iicbus.c (revision 258138) +++ sys/dev/ofw/ofw_iicbus.c (working copy) @@ -80,6 +80,7 @@ DEFINE_CLASS_1(iicbus, ofw_iicbus_driver, ofw_iicbus_methods, sizeof(struct iicbus_softc), iicbus_driver); +DRIVER_MODULE(ofw_iicbus, iicbb, ofw_iicbus_driver, ofwiicbus_devclass, 0, 0); DRIVER_MODULE(ofw_iicbus, iichb, ofw_iicbus_driver, ofwiicbus_devclass, 0, 0); MODULE_VERSION(ofw_iicbus, 1); MODULE_DEPEND(ofw_iicbus, iicbus, 1, 1, 1); --Apple-Mail=_8AC709E8-28F7-4B23-B62B-026FF9B7E725 Content-Disposition: attachment; filename=006-ofw-gpio-man.diff Content-Type: application/octet-stream; name="006-ofw-gpio-man.diff" Content-Transfer-Encoding: 7bit Index: share/man/man4/gpioiic.4 =================================================================== --- share/man/man4/gpioiic.4 (revision 258550) +++ share/man/man4/gpioiic.4 (working copy) @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd November 5, 2013 +.Dd November 26, 2013 .Dt GPIOIIC 4 .Os .Sh NAME @@ -73,12 +73,75 @@ .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 +.Xr FDT 4 +based system, like +.Li ARM , the dts part for a +.Nm gpioiic +device usually looks like: +.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 */ + sda = <1>; /* GPIO pin 22 */ + + /* This is an example of a gpioiic child. */ + gpioiic-child0 { + compatible = "lm75"; + i2c-address = <0x9e>; + }; + }; +}; +.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/boot/fdt/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. +.El .Sh SEE ALSO .Xr gpio 4 , .Xr gpioled 4 , Index: share/man/man4/gpioled.4 =================================================================== --- share/man/man4/gpioled.4 (revision 258550) +++ share/man/man4/gpioled.4 (working copy) @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd November 5, 2013 +.Dd November 26, 2013 .Dt GPIOLED 4 .Os .Sh NAME @@ -68,6 +68,73 @@ Please note that this mask should only ever have one bit set (any others bits - i.e., pins - will be ignored). .El +.Pp +On a +.Xr FDT 4 +based system, like +.Li ARM , the dts part for a +.Nm gpioled +device usually looks like: +.Bd -literal +gpio: gpio { + + gpio-controller; + ... + + led0 { + compatible = "gpioled"; + gpios = <&gpio 16 2 0>; /* GPIO pin 16. */ + name = "ok"; + }; + + led1 { + compatible = "gpioled"; + gpios = <&gpio 17 2 0>; /* GPIO pin 17. */ + name = "user-led1"; + }; +}; +.Ed +.Pp +And optionally, you can choose combine all the leds under a single +.Dq gpio-leds +compatible node: +.Bd -literal +simplebus0 { + + ... + + leds { + compatible = "gpio-leds"; + + led0 { + gpios = <&gpio 16 2 0>; + name = "ok" + }; + + led1 { + gpios = <&gpio 17 2 0>; + name = "user-led1" + }; + }; +}; +.Ed +.Pp +Both methods are equally supported and it is possible to have the leds +defined with any sort of mix between the methods. +The only restriction is that a GPIO pin cannot be mapped by two different +(gpio)leds. +.Pp +For more details about the +.Va gpios +property, please consult +.Pa /usr/src/sys/boot/fdt/dts/bindings-gpio.txt . +.Pp +The property +.Va name +is the arbitrary name of device in +.Pa /dev/led/ +to create for +.Xr led 4 . .Sh SEE ALSO .Xr gpio 4 , .Xr led 4 , --Apple-Mail=_8AC709E8-28F7-4B23-B62B-026FF9B7E725 Content-Disposition: attachment; filename=000-gpio-node.diff Content-Type: application/octet-stream; x-unix-mode=0644; name="000-gpio-node.diff" Content-Transfer-Encoding: 7bit Index: sys/arm/ti/ti_gpio.c =================================================================== --- sys/arm/ti/ti_gpio.c (revision 258855) +++ sys/arm/ti/ti_gpio.c (working copy) @@ -788,6 +788,14 @@ return(0); } +static phandle_t +ti_gpio_get_node(device_t bus, device_t dev) +{ + + /* We only have one child, the GPIO bus, which needs our own node. */ + return (ofw_bus_get_node(bus)); +} + static device_method_t ti_gpio_methods[] = { DEVMETHOD(device_probe, ti_gpio_probe), DEVMETHOD(device_attach, ti_gpio_attach), @@ -802,6 +810,10 @@ DEVMETHOD(gpio_pin_get, ti_gpio_pin_get), DEVMETHOD(gpio_pin_set, ti_gpio_pin_set), DEVMETHOD(gpio_pin_toggle, ti_gpio_pin_toggle), + + /* ofw_bus interface */ + DEVMETHOD(ofw_bus_get_node, ti_gpio_get_node), + {0, 0}, }; Index: sys/arm/broadcom/bcm2835/bcm2835_gpio.c =================================================================== --- sys/arm/broadcom/bcm2835/bcm2835_gpio.c (revision 258855) +++ sys/arm/broadcom/bcm2835/bcm2835_gpio.c (working copy) @@ -762,6 +762,14 @@ return (EBUSY); } +static phandle_t +bcm_gpio_get_node(device_t bus, device_t dev) +{ + + /* We only have one child, the GPIO bus, which needs our own node. */ + return (ofw_bus_get_node(bus)); +} + static device_method_t bcm_gpio_methods[] = { /* Device interface */ DEVMETHOD(device_probe, bcm_gpio_probe), @@ -778,6 +786,9 @@ DEVMETHOD(gpio_pin_set, bcm_gpio_pin_set), DEVMETHOD(gpio_pin_toggle, bcm_gpio_pin_toggle), + /* ofw_bus interface */ + DEVMETHOD(ofw_bus_get_node, bcm_gpio_get_node), + DEVMETHOD_END }; --Apple-Mail=_8AC709E8-28F7-4B23-B62B-026FF9B7E725 Content-Disposition: attachment; filename=000-bbb-gpioled.diff Content-Type: application/octet-stream; name="000-bbb-gpioled.diff" Content-Transfer-Encoding: 7bit Index: sys/arm/conf/BEAGLEBONE =================================================================== --- sys/arm/conf/BEAGLEBONE (revision 258798) +++ sys/arm/conf/BEAGLEBONE (working copy) @@ -101,6 +101,7 @@ # GPIO device gpio +device gpioled # USB support device usb Index: sys/boot/fdt/dts/beaglebone-black.dts =================================================================== --- sys/boot/fdt/dts/beaglebone-black.dts (revision 258798) +++ sys/boot/fdt/dts/beaglebone-black.dts (working copy) @@ -147,6 +147,30 @@ } }; + leds { + compatible = "gpio-leds"; + + led1 { + gpios = <&GPIO 53 2 0>; + name = "led1"; + }; + + led2 { + gpios = <&GPIO 54 2 0>; + name = "led2"; + }; + + led3 { + gpios = <&GPIO 55 2 0>; + name = "led3"; + }; + + led4 { + gpios = <&GPIO 56 2 0>; + name = "led4"; + }; + }; + chosen { stdin = "uart0"; stdout = "uart0"; --Apple-Mail=_8AC709E8-28F7-4B23-B62B-026FF9B7E725--
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?598EB94E-817C-47E9-BBA5-F6E6D5A1B2BA>