From owner-freebsd-arm@FreeBSD.ORG Thu Feb 6 18:53:46 2014 Return-Path: Delivered-To: freebsd-arm@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 292AFCEE; Thu, 6 Feb 2014 18:53:46 +0000 (UTC) Received: from mail-yh0-x235.google.com (mail-yh0-x235.google.com [IPv6:2607:f8b0:4002:c01::235]) (using TLSv1 with cipher ECDHE-RSA-RC4-SHA (128/128 bits)) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id C03F31899; Thu, 6 Feb 2014 18:53:45 +0000 (UTC) Received: by mail-yh0-f53.google.com with SMTP id v1so2201331yhn.12 for ; Thu, 06 Feb 2014 10:53:44 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:content-type:subject:message-id:date:to:mime-version; bh=DCEdCim3VhC8GO1P2Idv7sb4jXpdtnFbkmoLQm4VvSk=; b=u71oNAfkmVzNKKN4uFI3dApYNNn/YWHT+CFau6ntFc40kiM0VAy9TPMyjfvaCSbz8V stc5FH/uRTEBikXtTY35Fnm6D1ZKn0CPEftWeJhSQZBCDqZqgiB5yJsReNDP+ef12DQT bjobZlyWzVSHXYK3gsYPHjXEfm+fc4EalqRzh/wipFrILlG4AynEnBb8jZrx94UxLtdL XpGlNhcjwRTBqDqEl97OgWsbMidlO8WRUENHZ1So23RyK5OxH6rKxafQ5ji94/AKPCEQ i/wosN5uAVwMifpoNvltVOxIkWmXtxwJ2xDzbtg4DAhkWbd7lFks7EYjE2hmrbL1kXAX GCjg== X-Received: by 10.236.77.231 with SMTP id d67mr1456644yhe.113.1391712818052; Thu, 06 Feb 2014 10:53:38 -0800 (PST) Received: from [192.168.1.13] ([187.120.137.162]) by mx.google.com with ESMTPSA id h66sm4970600yhb.7.2014.02.06.10.53.35 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Thu, 06 Feb 2014 10:53:36 -0800 (PST) From: Luiz Otavio O Souza Content-Type: multipart/mixed; boundary="Apple-Mail=_23B096DF-2D6A-4DAD-91F4-17F5ECEED328" Subject: FDT/OFW GPIO bus Message-Id: <2D5F2707-FD55-46BB-A44F-8870B48E2BB1@gmail.com> Date: Thu, 6 Feb 2014 16:53:27 -0200 To: freebsd-embedded@freebsd.org, freebsd-arm@freebsd.org Mime-Version: 1.0 (Mac OS X Mail 7.1 \(1827\)) X-Mailer: Apple Mail (2.1827) X-BeenThere: freebsd-arm@freebsd.org X-Mailman-Version: 2.1.17 Precedence: list List-Id: "Porting FreeBSD to ARM processors." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 06 Feb 2014 18:53:46 -0000 --Apple-Mail=_23B096DF-2D6A-4DAD-91F4-17F5ECEED328 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=windows-1252 Hello guys, Last call for alcohol^Wtest and reviews. I=92ve finally managed to test these changes on a some FDT and non FDT = systems, so now it is all cleared to commit. I plan to commit these changes on the weekend unless someone objects. They add support to describe GPIO connections on the DTS files. It also = add the support to the in tree GPIO devices (gpioiic(4), gpioled(4)). The last patch (005-bbb-gpioled.diff) sets the gpioled(4) for the 4 on = board LEDs on BBB (beaglebone-black). The RPi led is already set and = just need the first patch (001-ofw-gpiobus.diff) to work. The tests were done on RPi and BBB using I2C devices (two lm75 on the = same bus), LEDs (for gpioled(4)) and even with some non committed = ethernet over SPI. The I2C tests are conducted using the hardware I2C = controller (when available) and also the software big bang controller - = gpioiic(4). I used the RSPRO (MIPS/ar71xx) to check for regressions without any = visible problem. gpioiic(4) devices can be described in DTS as follow: gpio { gpioiic { compatible =3D "gpioiic"; gpios =3D <&gpio 17 2 0 &gpio 21 2 0>; scl =3D <0>; sda =3D <1>; lm750 { compatible =3D "lm75"; i2c-address =3D <0x4b>; }; lm751 { compatible =3D "lm75"; i2c-address =3D <0x4f>; }; }; }; gpioled(4) devices can be described in two ways: - directly under the GPIO controller node: gpio { led0 { compatible =3D "gpioled"; gpios =3D <&gpio 16 2 0>; label =3D "ok"; }; led1 { compatible =3D "gpioled"; gpios =3D <&gpio 17 2 0>; name =3D "user-led1"; }; }; - Or under a single =93gpio-leds=94 node: leds { compatible =3D "gpio-leds"; led1 { gpios =3D <&GPIO 53 2 0>; name =3D "led1"; }; led2 { gpios =3D <&GPIO 54 2 0>; name =3D "led2"; }; }; gpioiic(4) and gpioled(4) man pages were updated to cover FDT/OFW based = systems. =46rom the latest patchset (published on freebsd-arch@ and freebsd-arm@) = i removed the check for disabled devices on DTS as this seems to = indicate that the device needs special attention but should not be = skipped at attach time. Please let me know if there are problems or concerns with the following = changes. Thanks, Luiz --Apple-Mail=_23B096DF-2D6A-4DAD-91F4-17F5ECEED328 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 261556) +++ sys/conf/files (working copy) @@ -1400,6 +1400,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 261556) +++ 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 261556) +++ sys/dev/gpio/gpiobusvar.h (working copy) @@ -30,13 +30,26 @@ #ifndef __GPIOBUS_H__ #define __GPIOBUS_H__ +#include "opt_platform.h" + #include #include #include -#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 +#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 261556) +++ sys/dev/gpio/gpioiic.c (working copy) @@ -28,6 +28,8 @@ #include __FBSDID("$FreeBSD$"); +#include "opt_platform.h" + #include #include #include @@ -38,6 +40,12 @@ #include #include "gpiobus_if.h" +#ifdef FDT +#include +#include +#include +#endif + #include #include @@ -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 261556) +++ sys/dev/gpio/gpioled.c (working copy) @@ -27,6 +27,8 @@ #include __FBSDID("$FreeBSD$"); +#include "opt_platform.h" + #include #include #include @@ -39,6 +41,12 @@ #include #include +#ifdef FDT +#include +#include +#include +#endif + #include #include #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), Index: sys/dev/gpio/ofw_gpiobus.c =================================================================== --- sys/dev/gpio/ofw_gpiobus.c (revision 0) +++ sys/dev/gpio/ofw_gpiobus.c (working copy) @@ -0,0 +1,338 @@ +/*- + * Copyright (c) 2009, Nathan Whitehorn + * Copyright (c) 2013, Luiz Otavio O Souza + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#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; + + /* 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); Property changes on: sys/dev/gpio/ofw_gpiobus.c ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property --Apple-Mail=_23B096DF-2D6A-4DAD-91F4-17F5ECEED328 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 #include #include @@ -50,6 +52,11 @@ #include #include +#ifdef FDT +#include +#include +#include +#endif #include #include @@ -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=_23B096DF-2D6A-4DAD-91F4-17F5ECEED328 Content-Disposition: attachment; filename=003-ofw-gpio-man.diff Content-Type: application/octet-stream; name="003-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=_23B096DF-2D6A-4DAD-91F4-17F5ECEED328 Content-Disposition: attachment; filename=004-gpio-node.diff Content-Type: application/octet-stream; name="004-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=_23B096DF-2D6A-4DAD-91F4-17F5ECEED328 Content-Disposition: attachment; filename=005-bbb-gpioled.diff Content-Type: application/octet-stream; name="005-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=_23B096DF-2D6A-4DAD-91F4-17F5ECEED328--