summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--share/man/man4/gpioiic.468
-rw-r--r--share/man/man4/gpioled.470
-rw-r--r--sys/arm/broadcom/bcm2835/bcm2835_gpio.c11
-rw-r--r--sys/arm/conf/BEAGLEBONE1
-rw-r--r--sys/arm/ti/ti_gpio.c16
-rw-r--r--sys/boot/fdt/dts/beaglebone-black.dts24
-rw-r--r--sys/boot/fdt/dts/bindings-gpio.txt2
-rw-r--r--sys/conf/files1
-rw-r--r--sys/dev/gpio/gpiobus.c22
-rw-r--r--sys/dev/gpio/gpiobusvar.h24
-rw-r--r--sys/dev/gpio/gpioiic.c49
-rw-r--r--sys/dev/gpio/gpioled.c88
-rw-r--r--sys/dev/gpio/ofw_gpiobus.c337
-rw-r--r--sys/dev/iicbus/iicbb.c25
-rw-r--r--sys/dev/ofw/ofw_bus_if.m2
-rw-r--r--sys/dev/ofw/ofw_iicbus.c1
-rw-r--r--sys/modules/gpio/gpiobus/Makefile2
-rw-r--r--sys/modules/gpio/gpioiic/Makefile1
-rw-r--r--sys/modules/gpio/gpioled/Makefile2
-rw-r--r--sys/modules/i2c/iicbb/Makefile2
20 files changed, 711 insertions, 37 deletions
diff --git a/share/man/man4/gpioiic.4 b/share/man/man4/gpioiic.4
index cbcaec9..e3f9814 100644
--- a/share/man/man4/gpioiic.4
+++ b/share/man/man4/gpioiic.4
@@ -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 ,
diff --git a/share/man/man4/gpioled.4 b/share/man/man4/gpioled.4
index 76f59fa..74c28e6 100644
--- a/share/man/man4/gpioled.4
+++ b/share/man/man4/gpioled.4
@@ -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
diff --git a/sys/arm/broadcom/bcm2835/bcm2835_gpio.c b/sys/arm/broadcom/bcm2835/bcm2835_gpio.c
index 9c5f5cd..7e8ead7 100644
--- a/sys/arm/broadcom/bcm2835/bcm2835_gpio.c
+++ b/sys/arm/broadcom/bcm2835/bcm2835_gpio.c
@@ -762,6 +762,14 @@ bcm_gpio_detach(device_t dev)
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 @@ static device_method_t bcm_gpio_methods[] = {
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
};
diff --git a/sys/arm/conf/BEAGLEBONE b/sys/arm/conf/BEAGLEBONE
index 3c6bebb..5fc02c1 100644
--- a/sys/arm/conf/BEAGLEBONE
+++ b/sys/arm/conf/BEAGLEBONE
@@ -101,6 +101,7 @@ device am335x_pmic # AM335x Power Management IC (TPC65217)
# GPIO
device gpio
+device gpioled
# USB support
device usb
diff --git a/sys/arm/ti/ti_gpio.c b/sys/arm/ti/ti_gpio.c
index 4edb10e..fdbf2c4 100644
--- a/sys/arm/ti/ti_gpio.c
+++ b/sys/arm/ti/ti_gpio.c
@@ -543,9 +543,9 @@ ti_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *value)
/* Read the value on the pin */
if (val & mask)
- *value = (ti_gpio_read_4(sc, bank, TI_GPIO_DATAOUT) & mask) ? 1 : 0;
- else
*value = (ti_gpio_read_4(sc, bank, TI_GPIO_DATAIN) & mask) ? 1 : 0;
+ else
+ *value = (ti_gpio_read_4(sc, bank, TI_GPIO_DATAOUT) & mask) ? 1 : 0;
TI_GPIO_UNLOCK(sc);
@@ -788,6 +788,14 @@ ti_gpio_detach(device_t dev)
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 @@ static device_method_t ti_gpio_methods[] = {
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},
};
diff --git a/sys/boot/fdt/dts/beaglebone-black.dts b/sys/boot/fdt/dts/beaglebone-black.dts
index 2ab5066..5da633f 100644
--- a/sys/boot/fdt/dts/beaglebone-black.dts
+++ b/sys/boot/fdt/dts/beaglebone-black.dts
@@ -153,6 +153,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";
diff --git a/sys/boot/fdt/dts/bindings-gpio.txt b/sys/boot/fdt/dts/bindings-gpio.txt
index 492616e..b13078a 100644
--- a/sys/boot/fdt/dts/bindings-gpio.txt
+++ b/sys/boot/fdt/dts/bindings-gpio.txt
@@ -82,7 +82,7 @@ dir:
flags:
0x0000---- IN_NONE
- 0x0001---- IN_POL_LOW Polarity low (inverted input value.
+ 0x0001---- IN_POL_LOW Polarity low (active-low).
0x0002---- IN_IRQ_EDGE Interrupt, edge triggered.
0x0004---- IN_IRQ_LEVEL Interrupt, level triggered.
diff --git a/sys/conf/files b/sys/conf/files
index 5d78804..ed2dd01 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -1439,6 +1439,7 @@ dev/gpio/gpioiic.c optional gpioiic
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
diff --git a/sys/dev/gpio/gpiobus.c b/sys/dev/gpio/gpiobus.c
index 6abb10c..d8eacc6 100644
--- a/sys/dev/gpio/gpiobus.c
+++ b/sys/dev/gpio/gpiobus.c
@@ -46,7 +46,6 @@ __FBSDID("$FreeBSD$");
#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_set(device_t, device_t, uint32_t, unsigned int);
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;
@@ -175,7 +164,8 @@ static int
gpiobus_probe(device_t dev)
{
device_set_desc(dev, "GPIO bus");
- return (0);
+
+ return (BUS_PROBE_GENERIC);
}
static int
@@ -190,13 +180,13 @@ gpiobus_attach(device_t dev)
if (res)
return (ENXIO);
+ KASSERT(sc->sc_npins != 0, ("GPIO device with no pins"));
+
/*
* Increase to get number of pins
*/
sc->sc_npins++;
- KASSERT(sc->sc_npins != 0, ("GPIO device with no pins"));
-
sc->sc_pins_mapped = malloc(sizeof(int) * sc->sc_npins, M_DEVBUF,
M_NOWAIT | M_ZERO);
@@ -209,7 +199,9 @@ gpiobus_attach(device_t dev)
/*
* Get parent's pins and mark them as unmapped
*/
+ bus_generic_probe(dev);
bus_enumerate_hinted_children(dev);
+
return (bus_generic_attach(dev));
}
diff --git a/sys/dev/gpio/gpiobusvar.h b/sys/dev/gpio/gpiobusvar.h
index 7a79aed..94ae1ad 100644
--- a/sys/dev/gpio/gpiobusvar.h
+++ b/sys/dev/gpio/gpiobusvar.h
@@ -30,12 +30,25 @@
#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
{
@@ -54,4 +67,11 @@ struct gpiobus_ivar
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__ */
diff --git a/sys/dev/gpio/gpioiic.c b/sys/dev/gpio/gpioiic.c
index 2a6d093..d7772b6 100644
--- a/sys/dev/gpio/gpioiic.c
+++ b/sys/dev/gpio/gpioiic.c
@@ -28,21 +28,24 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include "opt_platform.h"
+
#include <sys/param.h>
#include <sys/systm.h>
-#include <sys/bio.h>
#include <sys/bus.h>
#include <sys/conf.h>
#include <sys/kernel.h>
-#include <sys/kthread.h>
-#include <sys/lock.h>
-#include <sys/malloc.h>
#include <sys/module.h>
-#include <sys/mutex.h>
#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>
@@ -55,7 +58,6 @@ struct gpioiic_softc
{
device_t sc_dev;
device_t sc_busdev;
- struct cdev *sc_leddev;
int scl_pin;
int sda_pin;
};
@@ -77,7 +79,12 @@ 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);
}
@@ -86,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);
@@ -96,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);
@@ -139,7 +159,7 @@ gpioiic_callback(device_t dev, int index, caddr_t data)
error = EINVAL;
}
- return(error);
+ return (error);
}
static void
@@ -214,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[] = {
@@ -230,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 }
};
diff --git a/sys/dev/gpio/gpioled.c b/sys/dev/gpio/gpioled.c
index a03c172..1377a14 100644
--- a/sys/dev/gpio/gpioled.c
+++ b/sys/dev/gpio/gpioled.c
@@ -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"
@@ -75,6 +83,8 @@ gpioled_control(void *priv, int onoff)
GPIOLED_LOCK(sc);
GPIOBUS_LOCK_BUS(sc->sc_busdev);
GPIOBUS_ACQUIRE_BUS(sc->sc_busdev, sc->sc_dev);
+ GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, GPIOLED_PIN,
+ GPIO_PIN_OUTPUT);
GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev, GPIOLED_PIN,
onoff ? GPIO_PIN_HIGH : GPIO_PIN_LOW);
GPIOBUS_RELEASE_BUS(sc->sc_busdev, sc->sc_dev);
@@ -82,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);
}
@@ -93,21 +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;
-
- GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, GPIOLED_PIN,
- GPIO_PIN_OUTPUT);
+#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);
}
@@ -130,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),
diff --git a/sys/dev/gpio/ofw_gpiobus.c b/sys/dev/gpio/ofw_gpiobus.c
new file mode 100644
index 0000000..7641b56
--- /dev/null
+++ b/sys/dev/gpio/ofw_gpiobus.c
@@ -0,0 +1,337 @@
+/*-
+ * 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/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);
diff --git a/sys/dev/iicbus/iicbb.c b/sys/dev/iicbus/iicbb.c
index 44a069f..977d52a 100644
--- a/sys/dev/iicbus/iicbb.c
+++ b/sys/dev/iicbus/iicbb.c
@@ -43,6 +43,8 @@ __FBSDID("$FreeBSD$");
*
*/
+#include "opt_platform.h"
+
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>
@@ -50,6 +52,11 @@ __FBSDID("$FreeBSD$");
#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_write(device_t, const char *, int, int *, int);
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 @@ static device_method_t iicbb_methods[] = {
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 @@ iicbb_detach(device_t dev)
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 )
{
diff --git a/sys/dev/ofw/ofw_bus_if.m b/sys/dev/ofw/ofw_bus_if.m
index e2466b4..0034a15 100644
--- a/sys/dev/ofw/ofw_bus_if.m
+++ b/sys/dev/ofw/ofw_bus_if.m
@@ -158,7 +158,7 @@ METHOD const char * get_name {
} DEFAULT ofw_bus_default_get_name;
# Get the firmware node for the device dev on the bus. The default method will
-# return 0, which signals that there is no such node.
+# return -1, which signals that there is no such node.
METHOD phandle_t get_node {
device_t bus;
device_t dev;
diff --git a/sys/dev/ofw/ofw_iicbus.c b/sys/dev/ofw/ofw_iicbus.c
index 965721a..1574f6e 100644
--- a/sys/dev/ofw/ofw_iicbus.c
+++ b/sys/dev/ofw/ofw_iicbus.c
@@ -80,6 +80,7 @@ static devclass_t ofwiicbus_devclass;
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);
diff --git a/sys/modules/gpio/gpiobus/Makefile b/sys/modules/gpio/gpiobus/Makefile
index 1b7afe8..e868cba 100644
--- a/sys/modules/gpio/gpiobus/Makefile
+++ b/sys/modules/gpio/gpiobus/Makefile
@@ -33,7 +33,7 @@
KMOD= gpiobus
SRCS= gpiobus.c
-SRCS+= device_if.h bus_if.h gpio_if.h gpiobus_if.h
+SRCS+= device_if.h bus_if.h gpio_if.h gpiobus_if.h opt_platform.h
CFLAGS+= -I. -I${.CURDIR}/../../../dev/gpio/
diff --git a/sys/modules/gpio/gpioiic/Makefile b/sys/modules/gpio/gpioiic/Makefile
index be59861..abd835e 100644
--- a/sys/modules/gpio/gpioiic/Makefile
+++ b/sys/modules/gpio/gpioiic/Makefile
@@ -34,6 +34,7 @@
KMOD= gpioiic
SRCS= gpioiic.c
SRCS+= device_if.h bus_if.h gpio_if.h gpiobus_if.h iicbus_if.h iicbb_if.h
+SRCS+= opt_platform.h
CFLAGS+= -I. -I${.CURDIR}/../../../dev/gpio/
diff --git a/sys/modules/gpio/gpioled/Makefile b/sys/modules/gpio/gpioled/Makefile
index 0420b1b..cc5f860 100644
--- a/sys/modules/gpio/gpioled/Makefile
+++ b/sys/modules/gpio/gpioled/Makefile
@@ -33,7 +33,7 @@
KMOD= gpioled
SRCS= gpioled.c
-SRCS+= device_if.h bus_if.h gpio_if.h gpiobus_if.h
+SRCS+= device_if.h bus_if.h gpio_if.h gpiobus_if.h opt_platform.h
CFLAGS+= -I. -I${.CURDIR}/../../../dev/gpio/
diff --git a/sys/modules/i2c/iicbb/Makefile b/sys/modules/i2c/iicbb/Makefile
index ea991e0..75d1c83 100644
--- a/sys/modules/i2c/iicbb/Makefile
+++ b/sys/modules/i2c/iicbb/Makefile
@@ -3,6 +3,6 @@
.PATH: ${.CURDIR}/../../../dev/iicbus
KMOD = iicbb
SRCS = device_if.h bus_if.h iicbus_if.h \
- iicbb_if.h iicbb_if.c iicbb.c
+ iicbb_if.h iicbb_if.c iicbb.c opt_platform.h
.include <bsd.kmod.mk>
OpenPOWER on IntegriCloud