Add OFW support to the in tree gpio compatible devices: gpioiic(4) and

gpioled(4).

Tested on RPi and BBB (using the hardware I2C controller and gpioiic(4) for
the I2C tests).  It was also verified for regressions on RSPRO (MIPS/ar71xx)
used as reference for a non OFW-based system.

Update the gpioled(4) and gpioiic(4) man pages with some details and
examples about the FDT/OFW support.

Some compatibility details pointed out by imp@ will follow in subsequent
commits.

Approved by:	adrian (mentor, implicit)
This commit is contained in:
Luiz Otavio O Souza 2014-02-13 17:58:52 +00:00
parent 6d866ed35b
commit 9a2a079a51
4 changed files with 258 additions and 3 deletions

View File

@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd November 5, 2013
.Dd February 13, 2014
.Dt GPIOIIC 4
.Os
.Sh NAME
@ -65,7 +65,7 @@ This is a bitmask of the pins on the
that are to be used for SCLOCK and SDATA from the GPIO IIC
bit-banging bus.
To configure pin 0 and 7, use the bitmask of
10000001 and convert it to a hexadecimal value of 0x0081.
0b10000001 and convert it to a hexadecimal value of 0x0081.
Please note that this mask should only ever have two bits set
(any others bits - i.e., pins - will be ignored).
.It Va hint.gpioiic.%d.scl
@ -73,13 +73,77 @@ Indicates which bit in the
.Va hint.gpioiic.%d.pins
should be used as the SCLOCK
source.
Optional, defaults to 0.
.It Va hint.gpioiic.%d.sda
Indicates which bit in the
.Va hint.gpioiic.%d.pins
should be used as the SDATA
source.
Optional, defaults to 1.
.El
.Pp
On a
.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 - optional */
sda = <1>; /* GPIO pin 22 - optional */
/* This is an example of a gpioiic child. */
gpioiic-child0 {
compatible = "lm75";
i2c-address = <0x4f>;
};
};
};
.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 fdt 4 ,
.Xr gpio 4 ,
.Xr gpioled 4 ,
.Xr iic 4 ,

View File

@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd November 5, 2013
.Dd February 13, 2014
.Dt GPIOLED 4
.Os
.Sh NAME
@ -68,7 +68,75 @@ Which pin on the GPIO interface to map to this instance.
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 fdt 4 ,
.Xr gpio 4 ,
.Xr led 4 ,
.Xr gpioiic 4

View File

@ -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 @@ __FBSDID("$FreeBSD$");
#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 @@ static int
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 @@ gpioiic_attach(device_t dev)
{
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 @@ gpioiic_attach(device_t dev)
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 @@ gpioiic_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
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 @@ static device_method_t gpioiic_methods[] = {
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 }
};

View File

@ -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 @@ __FBSDID("$FreeBSD$");
#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_control(void *priv, int onoff)
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 @@ static int
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 devclass_t gpioled_devclass;
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),