From owner-svn-src-head@freebsd.org Tue Mar 1 16:10:17 2016 Return-Path: <owner-svn-src-head@freebsd.org> Delivered-To: svn-src-head@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 9E556ABFEBB; Tue, 1 Mar 2016 16:10:17 +0000 (UTC) (envelope-from mmel@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 589AE150E; Tue, 1 Mar 2016 16:10:17 +0000 (UTC) (envelope-from mmel@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id u21GAGCk032539; Tue, 1 Mar 2016 16:10:16 GMT (envelope-from mmel@FreeBSD.org) Received: (from mmel@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id u21GAGdC032537; Tue, 1 Mar 2016 16:10:16 GMT (envelope-from mmel@FreeBSD.org) Message-Id: <201603011610.u21GAGdC032537@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: mmel set sender to mmel@FreeBSD.org using -f From: Michal Meloun <mmel@FreeBSD.org> Date: Tue, 1 Mar 2016 16:10:16 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r296269 - head/sys/dev/gpio X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: SVN commit messages for the src tree for head/-current <svn-src-head.freebsd.org> List-Unsubscribe: <https://lists.freebsd.org/mailman/options/svn-src-head>, <mailto:svn-src-head-request@freebsd.org?subject=unsubscribe> List-Archive: <http://lists.freebsd.org/pipermail/svn-src-head/> List-Post: <mailto:svn-src-head@freebsd.org> List-Help: <mailto:svn-src-head-request@freebsd.org?subject=help> List-Subscribe: <https://lists.freebsd.org/mailman/listinfo/svn-src-head>, <mailto:svn-src-head-request@freebsd.org?subject=subscribe> X-List-Received-Date: Tue, 01 Mar 2016 16:10:17 -0000 Author: mmel Date: Tue Mar 1 16:10:15 2016 New Revision: 296269 URL: https://svnweb.freebsd.org/changeset/base/296269 Log: OFW_GPIOBUS: Add utility functions for easier handling of OFW GPIO pins. Reviewed by: ian, loos (paritaly) Modified: head/sys/dev/gpio/gpiobusvar.h head/sys/dev/gpio/ofw_gpiobus.c Modified: head/sys/dev/gpio/gpiobusvar.h ============================================================================== --- head/sys/dev/gpio/gpiobusvar.h Tue Mar 1 15:21:01 2016 (r296268) +++ head/sys/dev/gpio/gpiobusvar.h Tue Mar 1 16:10:15 2016 (r296269) @@ -38,6 +38,7 @@ #ifdef FDT #include <dev/ofw/ofw_bus_subr.h> +#include <gnu/dts/include/dt-bindings/gpio/gpio.h> #endif #include "gpio_if.h" @@ -83,6 +84,7 @@ struct gpiobus_pin uint32_t flags; /* pin flags */ uint32_t pin; /* pin number */ }; +typedef struct gpiobus_pin *gpio_pin_t; struct gpiobus_ivar { @@ -109,6 +111,16 @@ device_t ofw_gpiobus_add_fdt_child(devic int ofw_gpiobus_parse_gpios(device_t, char *, struct gpiobus_pin **); void ofw_gpiobus_register_provider(device_t); void ofw_gpiobus_unregister_provider(device_t); + +/* Consumers interface. */ +int gpio_pin_get_by_ofw_name(device_t consumer, char *name, gpio_pin_t *gpio); +int gpio_pin_get_by_ofw_idx(device_t consumer, int idx, gpio_pin_t *gpio); +int gpio_pin_get_by_ofw_property(device_t consumer, char *name, + gpio_pin_t *gpio); +void gpio_pin_release(gpio_pin_t gpio); +int gpio_pin_is_active(gpio_pin_t pin, bool *active); +int gpio_pin_set_active(gpio_pin_t pin, bool active); +int gpio_pin_setflags(gpio_pin_t pin, uint32_t flags); #endif int gpio_check_flags(uint32_t, uint32_t); device_t gpiobus_attach_bus(device_t); Modified: head/sys/dev/gpio/ofw_gpiobus.c ============================================================================== --- head/sys/dev/gpio/ofw_gpiobus.c Tue Mar 1 15:21:01 2016 (r296268) +++ head/sys/dev/gpio/ofw_gpiobus.c Tue Mar 1 16:10:15 2016 (r296269) @@ -47,6 +47,166 @@ static void ofw_gpiobus_destroy_devinfo( static int ofw_gpiobus_parse_gpios_impl(device_t, phandle_t, char *, struct gpiobus_softc *, struct gpiobus_pin **); +/* + * Utility functions for easier handling of OFW GPIO pins. + * + * !!! BEWARE !!! + * GPIOBUS uses children's IVARs, so we cannot use this interface for cross + * tree consumers. + * + */ +static int +gpio_pin_get_by_ofw_impl(device_t consumer_dev, char *prop_name, int idx, + gpio_pin_t *out_pin) +{ + phandle_t cnode, xref; + pcell_t *cells; + device_t busdev; + struct gpiobus_pin pin; + int ncells, rv; + + cnode = ofw_bus_get_node(consumer_dev); + if (cnode <= 0) { + device_printf(consumer_dev, + "%s called on not ofw based device\n", __func__); + return (ENXIO); + } + + rv = ofw_bus_parse_xref_list_alloc(cnode, prop_name, "#gpio-cells", + idx, &xref, &ncells, &cells); + if (rv != 0) + return (rv); + + /* Translate provider to device. */ + pin.dev = OF_device_from_xref(xref); + if (pin.dev == NULL) { + free(cells, M_OFWPROP); + return (ENODEV); + } + + /* Test if GPIO bus already exist. */ + busdev = GPIO_GET_BUS(pin.dev); + if (busdev == NULL) { + free(cells, M_OFWPROP); + return (ENODEV); + } + + /* Map GPIO pin. */ + rv = gpio_map_gpios(pin.dev, cnode, OF_node_from_xref(xref), ncells, + cells, &pin.pin, &pin.flags); + free(cells, M_OFWPROP); + if (rv != 0) { + device_printf(consumer_dev, "Cannot map the gpio property.\n"); + return (ENXIO); + } + + /* Reserve GPIO pin. */ + rv = gpiobus_map_pin(busdev, pin.pin); + if (rv != 0) { + device_printf(consumer_dev, "Cannot reserve gpio pin.\n"); + return (EBUSY); + } + + *out_pin = malloc(sizeof(struct gpiobus_pin), M_DEVBUF, + M_WAITOK | M_ZERO); + **out_pin = pin; + return (0); +} + +int +gpio_pin_get_by_ofw_idx(device_t consumer_dev, int idx, gpio_pin_t *pin) +{ + + return (gpio_pin_get_by_ofw_impl(consumer_dev, "gpios", idx, pin)); +} + +int +gpio_pin_get_by_ofw_property(device_t consumer_dev, char *name, gpio_pin_t *pin) +{ + + return (gpio_pin_get_by_ofw_impl(consumer_dev, name, 0, pin)); +} + +int +gpio_pin_get_by_ofw_name(device_t consumer_dev, char *name, gpio_pin_t *pin) +{ + int rv, idx; + phandle_t cnode; + + cnode = ofw_bus_get_node(consumer_dev); + if (cnode <= 0) { + device_printf(consumer_dev, + "%s called on not ofw based device\n", __func__); + return (ENXIO); + } + rv = ofw_bus_find_string_index(cnode, "gpio-names", name, &idx); + if (rv != 0) + return (rv); + return (gpio_pin_get_by_ofw_idx(consumer_dev, idx, pin)); +} + +void +gpio_pin_release(gpio_pin_t gpio) +{ + + if (gpio == NULL) + return; + + /* XXXX Unreserve pin. */ + free(gpio, M_DEVBUF); +} + +int +gpio_pin_is_active(gpio_pin_t pin, bool *active) +{ + int rv; + uint32_t tmp; + + KASSERT(pin != NULL, ("GPIO pin is NULL.")); + KASSERT(pin->dev != NULL, ("GPIO pin device is NULL.")); + rv = GPIO_PIN_GET(pin->dev, pin->pin, &tmp); + if (rv != 0) { + return (rv); + } + + *active = tmp != 0; + if (pin->flags & GPIO_ACTIVE_LOW) + *active = !(*active); + return (0); +} + +int +gpio_pin_set_active(gpio_pin_t pin, bool active) +{ + int rv; + uint32_t tmp; + + if (pin->flags & GPIO_ACTIVE_LOW) + tmp = active ? 0 : 1; + else + tmp = active ? 1 : 0; + + KASSERT(pin != NULL, ("GPIO pin is NULL.")); + KASSERT(pin->dev != NULL, ("GPIO pin device is NULL.")); + rv = GPIO_PIN_SET(pin->dev, pin->pin, tmp); + return (rv); +} + +int +gpio_pin_setflags(gpio_pin_t pin, uint32_t flags) +{ + int rv; + + KASSERT(pin != NULL, ("GPIO pin is NULL.")); + KASSERT(pin->dev != NULL, ("GPIO pin device is NULL.")); + + rv = GPIO_PIN_SETFLAGS(pin->dev, pin->pin, flags); + return (rv); +} + +/* + * OFW_GPIOBUS driver. + */ device_t ofw_gpiobus_add_fdt_child(device_t bus, const char *drvname, phandle_t child) {