Date: Sun, 19 Aug 2012 09:38:52 -0600 From: Warner Losh <imp@bsdimp.com> To: Hiroki Sato <hrs@FreeBSD.org> Cc: gonzo@FreeBSD.org, freebsd-arm@FreeBSD.org Subject: Re: gpiobus_hinted_child >32 pins support, pin_getname method, and gpio-sysctl bridge patch Message-ID: <8CDAB51C-14A0-42F0-8E16-43A3EABA2703@bsdimp.com> In-Reply-To: <20120819.171723.523519054460575158.hrs@allbsd.org> References: <20120819.171723.523519054460575158.hrs@allbsd.org>
next in thread | previous in thread | raw e-mail | index | archive | help
On Aug 19, 2012, at 2:17 AM, Hiroki Sato wrote:
> Hi,
Hi Sato-san,
In general, I like this code in the context of the current GPIO =
framework. I've been growing dissatisfied with the current GPIO =
framework, however, and some of my comments reflect that more than any =
comments about this specific code.
> Can you review the attached patches? The first one is to add >32 pins
> support for hint.devname.%d.pins and pin_getname method into gpiobus
> similar to gpio interface. After applying this, the following hint
> will be supported:
>=20
> hint.gpioled.0.at=3D"gpiobus0"
> hint.gpioled.0.pins0=3D"0x00000000" # 41
> hint.gpioled.0.pins1=3D"0x00000200"
This is, at best, awkward. Why not '41' here?
Why not hints.gpioled.0.pins0=3D41?
In general, the gpio stuff is too mask heavy and should be more pin =
oriented. We also need a more generic way to pass around all the GPIO =
pins used for aux functions of embedded devices. which pin is used for =
media status interrupts, write protect detection, vcc power, etc.
Looks a lot like we already keep book internally in pins.
> hint.gpioled.0.pins can still be used when the pin number is lower
> than 32. The addition of pin_getname method is to reuse pin name if
> it is already defined in the parent gpio driver. The maximum of the
> pin number is limited by GPIOBUS_PINS_MAX (currently 128).
>=20
> Another one is a simple GPIO-sysctl bridge driver. Currently it
> supports read operation only, but it is easy to add write one.
I was rather hoping to recast much of the GPIO stuff so we can also =
support interrupts based on pin numbers for any device in the tree. I'd =
like this for a gpiokey generic interface that devices can register =
button presses. How does one configure in vs out for these pins? And =
how does one guard against trying to use the GPIO pins for things like =
ethernet? Again, that may be beyond the scope of what you are trying to =
achieve.
> I confirmed if the both work fine by using several Marvell
> 88F628[12]-based boards.
>=20
> -- Hiroki
> Index: sys/dev/gpio/gpiobus.c
> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
> --- sys/dev/gpio/gpiobus.c (revision 239381)
> +++ sys/dev/gpio/gpiobus.c (working copy)
> @@ -40,6 +40,7 @@
> #include <machine/bus.h>
> #include <sys/rman.h>
> #include <machine/resource.h>
> +#include <machine/_inttypes.h>
>=20
> #include <sys/gpio.h>
> #include <dev/gpio/gpiobusvar.h>
> @@ -47,7 +48,7 @@
> #include "gpiobus_if.h"
>=20
> static void gpiobus_print_pins(struct gpiobus_ivar *);
> -static int gpiobus_parse_pins(struct gpiobus_softc *, device_t, int);
> +static int gpiobus_parse_pins(struct gpiobus_softc *, device_t, int =
*, size_t);
> static int gpiobus_probe(device_t);
> static int gpiobus_attach(device_t);
> static int gpiobus_detach(device_t);
> @@ -69,6 +70,7 @@
> static int gpiobus_pin_setflags(device_t, device_t, uint32_t, =
uint32_t);
> static int gpiobus_pin_getflags(device_t, device_t, uint32_t, =
uint32_t*);
> static int gpiobus_pin_getcaps(device_t, device_t, uint32_t, =
uint32_t*);
> +static int gpiobus_pin_getname(device_t, device_t, uint32_t, char *);
> 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);
> @@ -119,15 +121,18 @@
> }
>=20
> static int
> -gpiobus_parse_pins(struct gpiobus_softc *sc, device_t child, int =
mask)
> +gpiobus_parse_pins(struct gpiobus_softc *sc, device_t child, int =
*mask,
> + size_t masklen)
I'd be tempted to adapt a different specification method for > 32bit =
devices. But that may be beyond the scope of what you are trying to do.
Might not be bad to document the args, but that, sadly, doesn't follow =
the rest of the file...
> {
> struct gpiobus_ivar *devi =3D GPIOBUS_IVAR(child);
> - int i, npins;
> + int i, j, pin, npins;
>=20
> npins =3D 0;
> - for (i =3D 0; i < 32; i++) {
> - if (mask & (1 << i))
> - npins++;
> + for (i =3D 0; i < masklen; i++) {
> + for (j =3D 0; j < sizeof(mask[i]) * 8; j++) {
> + if (mask[i] & (1 << j))
> + npins++;
> + }
> }
>=20
> if (npins =3D=3D 0) {
> @@ -143,27 +148,30 @@
> return (ENOMEM);
>=20
> npins =3D 0;
> - for (i =3D 0; i < 32; i++) {
> + for (i =3D 0; i < masklen; i++) {
> + for (j =3D 0; j < sizeof(mask[i]) * 8; j++) {
> + if ((mask[i] & (1 << j)) =3D=3D 0)
> + continue;
>=20
> - if ((mask & (1 << i)) =3D=3D 0)
> - continue;
> -
> - if (i >=3D sc->sc_npins) {
> - device_printf(child,
> - "invalid pin %d, max: %d\n", i, sc->sc_npins =
- 1);
> - return (EINVAL);
> + pin =3D i * sizeof(mask[i]) * 8 + j;
> + if (pin >=3D sc->sc_npins) {
> + device_printf(child,
> + "invalid pin %d, max: %d\n", pin,
> + sc->sc_npins - 1);
> + return (EINVAL);
> + }
> + devi->pins[npins++] =3D pin;
> + /*
> + * Mark pin as mapped and give warning if it's
> + * already mapped
> + */
> + if (sc->sc_pins_mapped[pin]) {
> + device_printf(child,
> + "warning: pin %d is already =
mapped\n", pin);
> + return (EINVAL);
> + }
> + sc->sc_pins_mapped[pin] =3D 1;
> }
> -
> - devi->pins[npins++] =3D i;
> - /*
> - * Mark pin as mapped and give warning if it's already =
mapped
> - */
> - if (sc->sc_pins_mapped[i]) {
> - device_printf(child,
> - "warning: pin %d is already mapped\n", i);
> - return (EINVAL);
> - }
> - sc->sc_pins_mapped[i] =3D 1;
> }
>=20
> return (0);
> @@ -192,6 +200,8 @@
> * Increase to get number of pins
> */
> sc->sc_npins++;
> + if (bootverbose)
> + device_printf(dev, "number of pins =3D %d\n", =
sc->sc_npins);
>=20
> KASSERT(sc->sc_npins !=3D 0, ("GPIO device with no pins"));
>=20
> @@ -304,19 +314,47 @@
> return (child);
> }
>=20
> +#define GPIOBUS_PINS_MAX 128
> +static int pinmask[(GPIOBUS_PINS_MAX - 1) / (sizeof(int) * 8) + 1];
> +static char pinresname[] =3D "pinsNNN";
> +
> static void
> gpiobus_hinted_child(device_t bus, const char *dname, int dunit)
> {
> struct gpiobus_softc *sc =3D GPIOBUS_SOFTC(bus);
> struct gpiobus_ivar *devi;
> device_t child;
> - int pins;
> + int i, error;
>=20
> + bzero((char *)&pinmask, sizeof(pinmask));
>=20
> child =3D BUS_ADD_CHILD(bus, 0, dname, dunit);
> devi =3D GPIOBUS_IVAR(child);
> - resource_int_value(dname, dunit, "pins", &pins);
> - if (gpiobus_parse_pins(sc, child, pins))
> + if (resource_int_value(dname, dunit, "pins", &pinmask[0]) =3D=3D =
0) {
> + /*
> + * Backward compatibility for 32-pin configuration in a
> + * 32-bit hint:
> + *
> + * hint.devname.%d.pins=3D0x00000000
> + */
> + i =3D 1;
> + } else {
> + /*
> + * A 32-bit hint configures a 32-pin block:
> + *
> + * hint.devname.%d.pins0=3D0x00000000 # 0..31
> + * hint.devname.%d.pins1=3D0x00000000 # 32..63
> + * hint.devname.%d.pins2=3D0x00000000 # 64..91
> + */
> + for (i =3D 0; i < sizeof(pinmask)/sizeof(pinmask[0]); =
i++) {
> + snprintf(pinresname, sizeof(pinresname), =
"pins%d", i);
> + error =3D resource_int_value(dname, dunit, =
pinresname,
> + &pinmask[i]);
> + if (error)
> + break;
> + }
> + }
> + if (gpiobus_parse_pins(sc, child, pinmask, i))
> device_delete_child(bus, child);
> }
>=20
> @@ -409,6 +447,18 @@
> }
>=20
> static int
> +gpiobus_pin_getname(device_t dev, device_t child, uint32_t pin, char =
*name)
> +{
> + struct gpiobus_softc *sc =3D GPIOBUS_SOFTC(dev);
> + struct gpiobus_ivar *devi =3D GPIOBUS_IVAR(child);
> +
> + if (pin >=3D devi->npins)
> + return (EINVAL);
> +
> + return GPIO_PIN_GETNAME(sc->sc_dev, devi->pins[pin], name);
> +}
> +
> +static int
> gpiobus_pin_set(device_t dev, device_t child, uint32_t pin,
> unsigned int value)
> {
> @@ -469,6 +519,7 @@
> DEVMETHOD(gpiobus_release_bus, gpiobus_release_bus),
> DEVMETHOD(gpiobus_pin_getflags, gpiobus_pin_getflags),
> DEVMETHOD(gpiobus_pin_getcaps, gpiobus_pin_getcaps),
> + DEVMETHOD(gpiobus_pin_getname, gpiobus_pin_getname),
> DEVMETHOD(gpiobus_pin_setflags, gpiobus_pin_setflags),
> DEVMETHOD(gpiobus_pin_get, gpiobus_pin_get),
> DEVMETHOD(gpiobus_pin_set, gpiobus_pin_set),
> Index: sys/dev/gpio/gpiobus_if.m
> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
> --- sys/dev/gpio/gpiobus_if.m (revision 239381)
> +++ sys/dev/gpio/gpiobus_if.m (working copy)
> @@ -111,6 +111,16 @@
> };
>=20
> #
> +# Get pin name
> +#
> +METHOD int pin_getname {
> + device_t dev;
> + device_t child;
> + uint32_t pin_num;
> + char *name;
> +};
> +
> +#
> # Set current configuration and capabilities
> #
> METHOD int pin_setflags {
> Index: sys/dev/gpio/gpioled.c
> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
> --- sys/dev/gpio/gpioled.c (revision 239381)
> +++ sys/dev/gpio/gpioled.c (working copy)
> @@ -94,20 +94,25 @@
> {
> struct gpioled_softc *sc;
> const char *name;
> + char nbuf[GPIOMAXNAME];
>=20
> sc =3D device_get_softc(dev);
> sc->sc_dev =3D dev;
> sc->sc_busdev =3D device_get_parent(dev);
> GPIOLED_LOCK_INIT(sc);
> if (resource_string_value(device_get_name(dev),
> - device_get_unit(dev), "name", &name))
> - name =3D NULL;
> -
> + device_get_unit(dev), "name", &name) !=3D 0) {
> + GPIOBUS_PIN_GETNAME(sc->sc_busdev, sc->sc_dev, 0, nbuf);
> + nbuf[sizeof(nbuf) - 1] =3D '\0';
> + if (nbuf[0] !=3D '\0')
> + name =3D nbuf;
> + else
> + name =3D device_get_nameunit(dev);
> + }
> GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, GPIOLED_PIN,
> GPIO_PIN_OUTPUT);
>=20
> - sc->sc_leddev =3D led_create(gpioled_control, sc, name ? name :
> - device_get_nameunit(dev));
> + sc->sc_leddev =3D led_create(gpioled_control, sc, name);
>=20
> return (0);
> }
> Index: sys/conf/files
> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
> --- sys/conf/files (revision 239381)
> +++ sys/conf/files (working copy)
> @@ -1268,6 +1268,7 @@
> dependency "gpio_if.h"
> dev/gpio/gpioiic.c optional gpioiic
> dev/gpio/gpioled.c optional gpioled
> +dev/gpio/gpiosysctl.c optional gpiosysctl
> dev/gpio/gpio_if.m optional gpio
> dev/gpio/gpiobus_if.m optional gpio
> dev/hatm/if_hatm.c optional hatm pci
> Index: sys/dev/gpio/gpiosysctl.c
> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
> --- sys/dev/gpio/gpiosysctl.c (revision 0)
> +++ sys/dev/gpio/gpiosysctl.c (working copy)
> @@ -0,0 +1,197 @@
> +/*-
> + * Copyright (c) 2012 Hiroki Sato <hrs@FreeBSD.org>
> + * 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 <sys/cdefs.h>
> +__FBSDID("$FreeBSD$");
> +
> +#include <sys/param.h>
> +#include <sys/systm.h>
> +#include <sys/kernel.h>
> +#include <sys/module.h>
> +#include <sys/bus.h>
> +#include <sys/sysctl.h>
> +#include <sys/lock.h>
> +#include <sys/mutex.h>
> +
> +#include <machine/fdt.h>
> +#include <dev/fdt/fdt_common.h>
> +#include <dev/ofw/ofw_bus.h>
> +#include <dev/ofw/ofw_bus_subr.h>
> +
> +#include <sys/gpio.h>
> +
> +#include "gpio_if.h"
> +#include "gpiobus_if.h"
> +
> +struct gpiosysctl_softc
> +{
> + device_t sc_dev;
> + device_t sc_busdev;
> + struct mtx sc_mtx;
> +};
> +
> +#define GPIO_SYSCTL_DEVNAME "gpiosysctl"
> +#define GPIO_SYSCTL_LOCK(sc) mtx_lock(&(sc)->sc_mtx)
> +#define GPIO_SYSCTL_UNLOCK(sc) =
mtx_unlock(&(sc)->sc_mtx)
> +#define GPIO_SYSCTL_LOCK_INIT(sc) mtx_init(&(sc)->sc_mtx, =
\
> + =
device_get_nameunit((sc)->sc_dev), \
> + GPIO_SYSCTL_DEVNAME, MTX_DEF)
> +#define GPIO_SYSCTL_LOCK_DESTROY(sc) =
mtx_destroy(&(sc)->sc_mtx)
> +
> +static int gs_probe(device_t);
> +static int gs_attach(device_t);
> +static int gs_detach(device_t);
> +
> +static int
> +gs_probe(device_t dev)
> +{
> +
> + device_set_desc(dev, "GPIO-sysctl bridge driver");
> +
> + return (0);
> +}
> +
> +static int
> +gs_gpio_in(struct gpiosysctl_softc *sc)
> +{
> + int val;
> +
> + GPIO_SYSCTL_LOCK(sc);
> + GPIOBUS_LOCK_BUS(sc->sc_busdev);
> + GPIOBUS_ACQUIRE_BUS(sc->sc_busdev, sc->sc_dev);
> + GPIOBUS_PIN_GET(sc->sc_busdev, sc->sc_dev, 0, &val);
> + GPIOBUS_RELEASE_BUS(sc->sc_busdev, sc->sc_dev);
> + GPIOBUS_UNLOCK_BUS(sc->sc_busdev);
> + GPIO_SYSCTL_UNLOCK(sc);
> +
> + return (val);
> +}
> +
> +static void
> +gs_gpio_out(struct gpiosysctl_softc *sc, int val)
> +{
> + GPIO_SYSCTL_LOCK(sc);
> + GPIOBUS_LOCK_BUS(sc->sc_busdev);
> + GPIOBUS_ACQUIRE_BUS(sc->sc_busdev, sc->sc_dev);
> + GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev, 0,
> + (val =3D=3D 0) ? GPIO_PIN_LOW : GPIO_PIN_HIGH);
> + GPIOBUS_RELEASE_BUS(sc->sc_busdev, sc->sc_dev);
> + GPIOBUS_UNLOCK_BUS(sc->sc_busdev);
> + GPIO_SYSCTL_UNLOCK(sc);
> +}
> +
> +static int
> +gs_sysctl_handler(SYSCTL_HANDLER_ARGS)
> +{
> + device_t dev;
> + struct gpiosysctl_softc *sc;
> + int val, ret;
> +
> + dev =3D (device_t)arg1;
> + sc =3D device_get_softc(dev);
> + if (req->newptr =3D=3D NULL) {
> + val =3D gs_gpio_in(sc);
> + ret =3D sysctl_handle_int(oidp, &val, 0, req);
> + } else {
> + ret =3D sysctl_handle_int(oidp, &val, 0, req);
> + if (ret < 0 || ret > 1) {
> + device_printf(dev, "%d: invalid value.\n", ret);
> + ret =3D 0;
> + }
> + gs_gpio_out(sc, val);
> + ret =3D val;
> + }
> +
> + return (ret);
> +}
> +
> +static int
> +gs_attach(device_t dev)
> +{
> + struct gpiosysctl_softc *sc;
> + struct sysctl_ctx_list *ctx;
> + struct sysctl_oid *oid;
> + device_t pdev;
> + const char *name;
> + char nbuf[GPIOMAXNAME];
> + int flags;
> +
> + sc =3D device_get_softc(dev);
> + sc->sc_dev =3D dev;
> + sc->sc_busdev =3D device_get_parent(dev);
> + GPIO_SYSCTL_LOCK_INIT(sc);
> +
> + if (resource_string_value(device_get_name(dev), =
device_get_unit(dev),
> + "name", &name) !=3D 0) {
> + GPIOBUS_PIN_GETNAME(sc->sc_busdev, sc->sc_dev, 0, nbuf);
> + nbuf[sizeof(nbuf) - 1] =3D '\0';
> + if (nbuf[0] !=3D '\0')
> + name =3D nbuf;
> + else {
> + device_printf(dev, "no valid name.\n");
> + return (ENXIO);
> + }
> + }
> + ctx =3D device_get_sysctl_ctx(dev);
> +
> + pdev =3D device_get_parent(dev);
> + oid =3D device_get_sysctl_tree(pdev);
> + flags =3D CTLTYPE_INT | CTLFLAG_RD;
> + SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, name, =
flags, dev,
> + 0, gs_sysctl_handler, "I", NULL);
> +
> + return (0);
> +}
> +
> +static int
> +gs_detach(device_t dev)
> +{
> + struct gpiosysctl_softc *sc;
> +
> + sc =3D device_get_softc(dev);
> + GPIO_SYSCTL_LOCK_DESTROY(sc);
> +
> + return (0);
> +}
> +
> +static devclass_t gs_devclass;
> +
> +static device_method_t gs_methods[] =3D {
> + /* Device interface */
> + DEVMETHOD(device_probe, gs_probe),
> + DEVMETHOD(device_attach, gs_attach),
> + DEVMETHOD(device_detach, gs_detach),
> + { 0, 0 },
> +};
> +
> +static driver_t gs_driver =3D {
> + GPIO_SYSCTL_DEVNAME,
> + gs_methods,
> + sizeof(struct gpiosysctl_softc),
> +};
> +
> +DRIVER_MODULE(gpiosysctl, gpiobus, gs_driver, gs_devclass, 0, 0);
> +MODULE_VERSION(gpiosysctl, 1);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?8CDAB51C-14A0-42F0-8E16-43A3EABA2703>
