Index: sys/conf/files =================================================================== --- sys/conf/files +++ sys/conf/files @@ -1571,7 +1571,8 @@ dev/gpio/gpioc.c optional gpio \ dependency "gpio_if.h" dev/gpio/gpioiic.c optional gpioiic -dev/gpio/gpioled.c optional gpioled +dev/gpio/gpioled.c optional gpioled !fdt +dev/gpio/gpioled_fdt.c optional gpioled fdt dev/gpio/gpiospi.c optional gpiospi dev/gpio/gpio_if.m optional gpio dev/gpio/gpiobus_if.m optional gpio Index: sys/dev/gpio/gpioled.c =================================================================== --- sys/dev/gpio/gpioled.c +++ sys/dev/gpio/gpioled.c @@ -39,11 +39,6 @@ #include #include -#ifdef FDT -#include -#include -#endif - #include #include @@ -91,66 +86,9 @@ 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; - for (leds = OF_child(root); leds != 0; leds = OF_peer(leds)) { - if (!fdt_is_compatible_strict(leds, "gpio-leds")) - continue; - /* Traverse the 'gpio-leds' node and add its children. */ - for (child = OF_child(leds); child != 0; child = OF_peer(child)) { - if (!OF_hasprop(child, "gpios")) - continue; - if (ofw_gpiobus_add_fdt_child(bus, driver->name, 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; - - OF_prop_free(compat); - } - - if (match == 0) - return (ENXIO); -#endif device_set_desc(dev, "GPIO led"); return (BUS_PROBE_DEFAULT); @@ -161,13 +99,7 @@ { struct gpioled_softc *sc; int state; -#ifdef FDT - phandle_t node; - char *default_state; - char *name; -#else const char *name; -#endif sc = device_get_softc(dev); sc->sc_dev = dev; @@ -176,42 +108,14 @@ state = 0; -#ifdef FDT - if ((node = ofw_bus_get_node(dev)) == -1) - return (ENXIO); - - if (OF_getprop_alloc(node, "default-state", - sizeof(char), (void **)&default_state) != -1) { - if (strcasecmp(default_state, "on") == 0) - state = 1; - else if (strcasecmp(default_state, "off") == 0) - state = 0; - else if (strcasecmp(default_state, "keep") == 0) - state = -1; - else { - device_printf(dev, - "unknown value for default-state in FDT\n"); - } - OF_prop_free(default_state); - } - - name = NULL; - 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; resource_int_value(device_get_name(dev), device_get_unit(dev), "invert", &sc->sc_invert); -#endif sc->sc_leddev = led_create_state(gpioled_control, sc, name ? name : device_get_nameunit(dev), state); -#ifdef FDT - if (name != NULL) - OF_prop_free(name); -#endif return (0); } @@ -234,9 +138,6 @@ 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/gpioled_fdt.c =================================================================== --- /dev/null +++ sys/dev/gpio/gpioled_fdt.c @@ -0,0 +1,230 @@ +/*- + * Copyright (c) 2009 Oleksandr Tymoshenko + * 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_platform.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "gpiobus_if.h" + +struct gpioled +{ + struct gpioleds_softc *parent_sc; + gpio_pin_t pin; + struct cdev *leddev; +}; + +struct gpioleds_softc +{ + device_t sc_dev; + device_t sc_busdev; + struct gpioled *sc_leds; + int sc_total_leds; +}; + +static void gpioled_control(void *, int); +static int gpioled_probe(device_t); +static int gpioled_attach(device_t); +static int gpioled_detach(device_t); + +static void +gpioled_control(void *priv, int onoff) +{ + struct gpioled *led; + + led = (struct gpioled *)priv; + if (led->pin) + gpio_pin_set_active(led->pin, onoff); +} + +static void +gpioleds_attach_led(struct gpioleds_softc *sc, phandle_t node, + struct gpioled *led) +{ + char *name; + int state, err; + char *default_state; + + led->parent_sc = sc; + + state = 0; + if (OF_getprop_alloc(node, "default-state", + sizeof(char), (void **)&default_state) != -1) { + if (strcasecmp(default_state, "on") == 0) + state = 1; + else if (strcasecmp(default_state, "off") == 0) + state = 0; + else if (strcasecmp(default_state, "keep") == 0) + state = -1; + else { + state = -1; + device_printf(sc->sc_dev, + "unknown value for default-state in FDT\n"); + } + OF_prop_free(default_state); + } + + name = NULL; + if (OF_getprop_alloc(node, "label", 1, (void **)&name) == -1) + OF_getprop_alloc(node, "name", 1, (void **)&name); + + if (name == NULL) { + device_printf(sc->sc_dev, + "no name provided for gpio LED, skipping\n"); + return; + } + + err = gpio_pin_get_by_ofw_idx(sc->sc_dev, node, 0, &led->pin); + if (err) { + device_printf(sc->sc_dev, "<%s> failed to map pin\n", name); + if (name) + OF_prop_free(name); + return; + } + gpio_pin_setflags(led->pin, GPIO_PIN_OUTPUT); + + led->leddev = led_create_state(gpioled_control, led, name, + state); + + if (name != NULL) + OF_prop_free(name); +} + +static void +gpioleds_detach_led(struct gpioled *led) +{ + + if (led->leddev != NULL) + led_destroy(led->leddev); + + if (led->pin) + gpio_pin_release(led->pin); +} + +static int +gpioled_probe(device_t dev) +{ + if (!ofw_bus_is_compatible(dev, "gpio-leds")) + return (ENXIO); + + device_set_desc(dev, "GPIO LEDs"); + + return (BUS_PROBE_DEFAULT); +} + +static int +gpioled_attach(device_t dev) +{ + struct gpioleds_softc *sc; + phandle_t child, leds; + int total_leds; + + if ((leds = ofw_bus_get_node(dev)) == -1) + return (ENXIO); + + sc = device_get_softc(dev); + sc->sc_dev = dev; + sc->sc_busdev = device_get_parent(dev); + + /* Traverse the 'gpio-leds' node and count leds */ + total_leds = 0; + for (child = OF_child(leds); child != 0; child = OF_peer(child)) { + if (!OF_hasprop(child, "gpios")) + continue; + total_leds++; + } + + if (total_leds) { + sc->sc_leds = malloc(sizeof(struct gpioled) * total_leds, + M_DEVBUF, M_WAITOK | M_ZERO); + + sc->sc_total_leds = 0; + /* Traverse the 'gpio-leds' node and count leds */ + for (child = OF_child(leds); child != 0; child = OF_peer(child)) { + if (!OF_hasprop(child, "gpios")) + continue; + gpioleds_attach_led(sc, child, &sc->sc_leds[sc->sc_total_leds]); + sc->sc_total_leds++; + } + } + + return (0); +} + +static int +gpioled_detach(device_t dev) +{ + struct gpioleds_softc *sc; + int i; + + sc = device_get_softc(dev); + + for (i = 0; i < sc->sc_total_leds; i++) + gpioleds_detach_led(&sc->sc_leds[i]); + + if (sc->sc_leds) + free(sc->sc_leds, M_DEVBUF); + + return (0); +} + +static devclass_t gpioled_devclass; + +static device_method_t gpioled_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, gpioled_probe), + DEVMETHOD(device_attach, gpioled_attach), + DEVMETHOD(device_detach, gpioled_detach), + + DEVMETHOD_END +}; + +static driver_t gpioled_driver = { + "gpioled", + gpioled_methods, + sizeof(struct gpioleds_softc), +}; + +DRIVER_MODULE(gpioled, ofwbus, gpioled_driver, gpioled_devclass, 0, 0); +DRIVER_MODULE(gpioled, simplebus, gpioled_driver, gpioled_devclass, 0, 0); +MODULE_DEPEND(gpioled, gpiobus, 1, 1, 1); Index: sys/modules/gpio/gpioled/Makefile =================================================================== --- sys/modules/gpio/gpioled/Makefile +++ sys/modules/gpio/gpioled/Makefile @@ -32,7 +32,11 @@ .PATH: ${.CURDIR}/../../../dev/gpio/ KMOD= gpioled +.if !empty(OPT_FDT) +SRCS= gpioled_fdt.c +.else SRCS= gpioled.c +.endif SRCS+= device_if.h bus_if.h gpio_if.h gpiobus_if.h opt_platform.h ofw_bus_if.h CFLAGS+= -I. -I${.CURDIR}/../../../dev/gpio/