Skip site navigation (1)Skip section navigation (2)
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>