Date: Thu, 6 Feb 2014 16:53:27 -0200 From: Luiz Otavio O Souza <loos.br@gmail.com> To: freebsd-embedded@freebsd.org, freebsd-arm@freebsd.org Subject: FDT/OFW GPIO bus Message-ID: <2D5F2707-FD55-46BB-A44F-8870B48E2BB1@gmail.com>
next in thread | raw e-mail | index | archive | help
--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 <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 261556)
+++ 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 261556)
+++ 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),
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 <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;
+
+ /* 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 <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=_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--
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?2D5F2707-FD55-46BB-A44F-8870B48E2BB1>
