svn commit: r213237 - in head/sys: conf dev/gpio sys

Oleksandr Tymoshenko gonzo at FreeBSD.org
Tue Sep 28 03:24:54 UTC 2010


Author: gonzo
Date: Tue Sep 28 03:24:53 2010
New Revision: 213237
URL: http://svn.freebsd.org/changeset/base/213237

Log:
  Initial GPIO bus support. Includes:
    - GPIO bus controller interface
    - GPIO bus interface
    - Implementation of GPIO led(4) compatible device
    - Implementation of iic(4) bus over GPIO (author: Luiz Otavio O Souza)
  
  Tested by: Luiz Otavio O Souza, Alexandr Rybalko

Added:
  head/sys/dev/gpio/
  head/sys/dev/gpio/gpio_if.m   (contents, props changed)
  head/sys/dev/gpio/gpiobus.c   (contents, props changed)
  head/sys/dev/gpio/gpiobus_if.m   (contents, props changed)
  head/sys/dev/gpio/gpiobusvar.h   (contents, props changed)
  head/sys/dev/gpio/gpioc.c   (contents, props changed)
  head/sys/dev/gpio/gpioiic.c   (contents, props changed)
  head/sys/dev/gpio/gpioled.c   (contents, props changed)
  head/sys/sys/gpio.h   (contents, props changed)
Modified:
  head/sys/conf/files

Modified: head/sys/conf/files
==============================================================================
--- head/sys/conf/files	Tue Sep 28 01:36:01 2010	(r213236)
+++ head/sys/conf/files	Tue Sep 28 03:24:53 2010	(r213237)
@@ -1010,6 +1010,14 @@ dev/fxp/if_fxp.c		optional fxp inet
 dev/gem/if_gem.c		optional gem
 dev/gem/if_gem_pci.c		optional gem pci
 dev/gem/if_gem_sbus.c		optional gem sbus
+dev/gpio/gpiobus.c		optional gpio				\
+	dependency	"gpiobus_if.h"
+dev/gpio/gpioc.c		optional gpio				\
+	dependency	"gpio_if.h"
+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/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

Added: head/sys/dev/gpio/gpio_if.m
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/dev/gpio/gpio_if.m	Tue Sep 28 03:24:53 2010	(r213237)
@@ -0,0 +1,102 @@
+#-
+# Copyright (c) 2009 Oleksandr Tymoshenko <gonzo at 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.
+#
+# $FreeBSD$
+#
+
+#include <sys/bus.h>
+#include <sys/gpio.h>
+
+INTERFACE gpio;
+
+#
+# Get total number of pins
+#
+METHOD int pin_max {
+	device_t dev;
+	int *npins;
+};
+
+#
+# Set value of pin specifed by pin_num 
+#
+METHOD int pin_set {
+	device_t dev;
+	uint32_t pin_num;
+	uint32_t pin_value;
+};
+
+#
+# Get value of pin specifed by pin_num 
+#
+METHOD int pin_get {
+	device_t dev;
+	uint32_t pin_num;
+	uint32_t *pin_value;
+};
+
+#
+# Toggle value of pin specifed by pin_num 
+#
+METHOD int pin_toggle {
+	device_t dev;
+	uint32_t pin_num;
+};
+
+#
+# Get pin capabilities
+#
+METHOD int pin_getcaps {
+	device_t dev;
+	uint32_t pin_num;
+	uint32_t *caps;
+};
+
+#
+# Get pin flags
+#
+METHOD int pin_getflags {
+	device_t dev;
+	uint32_t pin_num;
+	uint32_t *flags;
+};
+
+#
+# Get pin name
+#
+METHOD int pin_getname {
+	device_t dev;
+	uint32_t pin_num;
+	char *name;
+};
+
+#
+# Set current configuration and capabilities
+#
+METHOD int pin_setflags {
+	device_t dev;
+	uint32_t pin_num;
+	uint32_t flags;
+};

Added: head/sys/dev/gpio/gpiobus.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/dev/gpio/gpiobus.c	Tue Sep 28 03:24:53 2010	(r213237)
@@ -0,0 +1,492 @@
+/*-
+ * Copyright (c) 2009 Oleksandr Tymoshenko <gonzo at 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 ``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/systm.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/kernel.h>
+#include <sys/queue.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
+
+#include <sys/bus.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <machine/resource.h>
+
+#include <sys/gpio.h>
+#include <dev/gpio/gpiobusvar.h>
+#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);
+static int gpiobus_detach(device_t);
+static int gpiobus_suspend(device_t);
+static int gpiobus_resume(device_t);
+static int gpiobus_print_child(device_t, device_t);
+static int gpiobus_child_location_str(device_t, device_t, char *, size_t);
+static int gpiobus_child_pnpinfo_str(device_t, device_t, char *, size_t);
+static device_t gpiobus_add_child(device_t, u_int, const char *, int);
+static void gpiobus_hinted_child(device_t, const char *, int);
+
+/*
+ * GPIOBUS interface
+ */
+static void gpiobus_lock_bus(device_t);
+static void gpiobus_unlock_bus(device_t);
+static void gpiobus_acquire_bus(device_t, device_t);
+static void gpiobus_release_bus(device_t, device_t);
+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_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
+gpiobus_print_pins(struct gpiobus_ivar *devi)
+{
+	int range_start, range_stop, need_coma;
+	int i;
+
+	if (devi->npins == 0)
+		return;
+
+	need_coma = 0;
+	range_start = range_stop = devi->pins[0];
+	for (i = 1; i < devi->npins; i++) {
+		if (devi->pins[i] != (range_stop + 1)) {
+			if (need_coma)
+				printf(",");
+			if (range_start != range_stop)
+				printf("%d-%d", range_start, range_stop);
+			else
+				printf("%d", range_start);
+
+			range_start = range_stop = devi->pins[i];
+			need_coma = 1;
+		}
+		else
+			range_stop++;
+	}
+
+	if (need_coma)
+		printf(",");
+	if (range_start != range_stop)
+		printf("%d-%d", range_start, range_stop);
+	else
+		printf("%d", range_start);
+}
+
+static int
+gpiobus_parse_pins(struct gpiobus_softc *sc, device_t child, int mask)
+{
+	struct gpiobus_ivar *devi = GPIOBUS_IVAR(child);
+	int i, npins;
+
+	npins = 0;
+	for (i = 0; i < 32; i++) {
+		if (mask & (1 << i))
+			npins++;
+	}
+
+	if (npins == 0) {
+		device_printf(child, "empty pin mask");
+		return (EINVAL);
+	}
+
+	devi->npins = npins;
+	devi->pins = malloc(sizeof(uint32_t) * devi->npins, M_DEVBUF, 
+	    M_NOWAIT | M_ZERO);
+
+	if (!devi->pins)
+		return (ENOMEM);
+
+	npins = 0;
+	for (i = 0; i < 32; i++) {
+
+		if ((mask & (1 << i)) == 0)
+			continue;
+
+		if (i >= sc->sc_npins) {
+			device_printf(child, 
+			    "invalid pin %d, max: %d\n", i, sc->sc_npins - 1);
+			return (EINVAL);
+		}
+
+		devi->pins[npins++] = 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] = 1;
+	}
+
+	return (0);
+}
+
+static int
+gpiobus_probe(device_t dev)
+{
+	device_set_desc(dev, "GPIO bus");
+	return (0);
+}
+
+static int
+gpiobus_attach(device_t dev)
+{
+	struct gpiobus_softc *sc = GPIOBUS_SOFTC(dev);
+	int res;
+
+	sc->sc_busdev = dev;
+	sc->sc_dev = device_get_parent(dev);
+	res = GPIO_PIN_MAX(sc->sc_dev, &sc->sc_npins);
+	if (res)
+		return (ENXIO);
+
+	/*
+	 * 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);
+
+	if (!sc->sc_pins_mapped)
+		return (ENOMEM);
+
+	/* init bus lock */
+	GPIOBUS_LOCK_INIT(sc);
+
+	/*
+	 * Get parent's pins and mark them as unmapped
+	 */
+	bus_enumerate_hinted_children(dev);
+	return (bus_generic_attach(dev));
+}
+
+/*
+ * Since this is not a self-enumerating bus, and since we always add
+ * children in attach, we have to always delete children here.
+ */
+static int
+gpiobus_detach(device_t dev)
+{
+	struct gpiobus_softc *sc = GPIOBUS_SOFTC(dev);
+	int err, ndevs, i;
+	device_t *devlist;
+
+	KASSERT(mtx_initialized(&sc->sc_mtx),
+	    ("gpiobus mutex not initialized"));
+	GPIOBUS_LOCK_DESTROY(sc);
+
+	if ((err = bus_generic_detach(dev)) != 0)
+		return (err);
+	if ((err = device_get_children(dev, &devlist, &ndevs)) != 0)
+		return (err);
+	for (i = 0; i < ndevs; i++)
+		device_delete_child(dev, devlist[i]);
+
+	if (sc->sc_pins_mapped) {
+		free(sc->sc_pins_mapped, M_DEVBUF);
+		sc->sc_pins_mapped = NULL;
+	}
+	free(devlist, M_TEMP);
+
+	return (0);
+}
+
+static int
+gpiobus_suspend(device_t dev)
+{
+
+	return (bus_generic_suspend(dev));
+}
+
+static int
+gpiobus_resume(device_t dev)
+{
+
+	return (bus_generic_resume(dev));
+}
+
+static int
+gpiobus_print_child(device_t dev, device_t child)
+{
+	struct gpiobus_ivar *devi = GPIOBUS_IVAR(child);
+	int retval = 0;
+
+	retval += bus_print_child_header(dev, child);
+	retval += printf(" at pin(s) ");
+	gpiobus_print_pins(devi);
+	retval += bus_print_child_footer(dev, child);
+
+	return (retval);
+}
+
+static int
+gpiobus_child_location_str(device_t bus, device_t child, char *buf,
+    size_t buflen)
+{
+	// struct gpiobus_ivar *devi = GPIOBUS_IVAR(child);
+
+	snprintf(buf, buflen, "pins=?");
+	return (0);
+}
+
+static int
+gpiobus_child_pnpinfo_str(device_t bus, device_t child, char *buf,
+    size_t buflen)
+{
+
+	*buf = '\0';
+	return (0);
+}
+
+static device_t
+gpiobus_add_child(device_t dev, u_int order, const char *name, int unit)
+{
+	device_t child;
+	struct gpiobus_ivar *devi;
+
+	child = device_add_child_ordered(dev, order, name, unit);
+	if (child == NULL) 
+		return (child);
+	devi = malloc(sizeof(struct gpiobus_ivar), M_DEVBUF, M_NOWAIT | M_ZERO);
+	if (devi == NULL) {
+		device_delete_child(dev, child);
+		return (0);
+	}
+	device_set_ivars(child, devi);
+	return (child);
+}
+
+static void
+gpiobus_hinted_child(device_t bus, const char *dname, int dunit)
+{
+	struct gpiobus_softc *sc = GPIOBUS_SOFTC(bus);
+	struct gpiobus_ivar *devi;
+	device_t child;
+	int pins;
+
+
+	child = BUS_ADD_CHILD(bus, 0, dname, dunit);
+	devi = GPIOBUS_IVAR(child);
+	resource_int_value(dname, dunit, "pins", &pins);
+	if (gpiobus_parse_pins(sc, child, pins))
+		device_delete_child(bus, child);
+}
+
+static void
+gpiobus_lock_bus(device_t busdev)
+{
+	struct gpiobus_softc *sc;
+
+	sc = device_get_softc(busdev);
+	GPIOBUS_ASSERT_UNLOCKED(sc);
+	GPIOBUS_LOCK(sc);
+}
+
+static void
+gpiobus_unlock_bus(device_t busdev)
+{
+	struct gpiobus_softc *sc;
+
+	sc = device_get_softc(busdev);
+	GPIOBUS_ASSERT_LOCKED(sc);
+	GPIOBUS_UNLOCK(sc);
+}
+
+static void
+gpiobus_acquire_bus(device_t busdev, device_t child)
+{
+	struct gpiobus_softc *sc;
+
+	sc = device_get_softc(busdev);
+	GPIOBUS_ASSERT_LOCKED(sc);
+
+	if (sc->sc_owner)
+		panic("rb_cpldbus: cannot serialize the access to device.");
+	sc->sc_owner = child;
+}
+
+static void
+gpiobus_release_bus(device_t busdev, device_t child)
+{
+	struct gpiobus_softc *sc;
+
+	sc = device_get_softc(busdev);
+	GPIOBUS_ASSERT_LOCKED(sc);
+
+	if (!sc->sc_owner)
+		panic("rb_cpldbus: releasing unowned bus.");
+	if (sc->sc_owner != child)
+		panic("rb_cpldbus: you don't own the bus. game over.");
+
+	sc->sc_owner = NULL;
+}
+
+static int
+gpiobus_pin_setflags(device_t dev, device_t child, uint32_t pin, 
+    uint32_t flags)
+{
+	struct gpiobus_softc *sc = GPIOBUS_SOFTC(dev);
+	struct gpiobus_ivar *devi = GPIOBUS_IVAR(child);
+
+	if (pin >= devi->npins)
+		return (EINVAL);
+
+	return GPIO_PIN_SETFLAGS(sc->sc_dev, devi->pins[pin], flags);
+}
+
+static int
+gpiobus_pin_getflags(device_t dev, device_t child, uint32_t pin, 
+    uint32_t *flags)
+{
+	struct gpiobus_softc *sc = GPIOBUS_SOFTC(dev);
+	struct gpiobus_ivar *devi = GPIOBUS_IVAR(child);
+
+	if (pin >= devi->npins)
+		return (EINVAL);
+
+	return GPIO_PIN_GETFLAGS(sc->sc_dev, devi->pins[pin], flags);
+}
+
+static int
+gpiobus_pin_getcaps(device_t dev, device_t child, uint32_t pin, 
+    uint32_t *caps)
+{
+	struct gpiobus_softc *sc = GPIOBUS_SOFTC(dev);
+	struct gpiobus_ivar *devi = GPIOBUS_IVAR(child);
+
+	if (pin >= devi->npins)
+		return (EINVAL);
+
+	return GPIO_PIN_GETCAPS(sc->sc_dev, devi->pins[pin], caps);
+}
+
+static int
+gpiobus_pin_set(device_t dev, device_t child, uint32_t pin, 
+    unsigned int value)
+{
+	struct gpiobus_softc *sc = GPIOBUS_SOFTC(dev);
+	struct gpiobus_ivar *devi = GPIOBUS_IVAR(child);
+
+	if (pin >= devi->npins)
+		return (EINVAL);
+
+	return GPIO_PIN_SET(sc->sc_dev, devi->pins[pin], value);
+}
+
+static int
+gpiobus_pin_get(device_t dev, device_t child, uint32_t pin, 
+    unsigned int *value)
+{
+	struct gpiobus_softc *sc = GPIOBUS_SOFTC(dev);
+	struct gpiobus_ivar *devi = GPIOBUS_IVAR(child);
+
+	if (pin >= devi->npins)
+		return (EINVAL);
+
+	return GPIO_PIN_GET(sc->sc_dev, devi->pins[pin], value);
+}
+
+static int
+gpiobus_pin_toggle(device_t dev, device_t child, uint32_t pin)
+{
+	struct gpiobus_softc *sc = GPIOBUS_SOFTC(dev);
+	struct gpiobus_ivar *devi = GPIOBUS_IVAR(child);
+
+	if (pin >= devi->npins)
+		return (EINVAL);
+
+	return GPIO_PIN_TOGGLE(sc->sc_dev, devi->pins[pin]);
+}
+
+static device_method_t gpiobus_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		gpiobus_probe),
+	DEVMETHOD(device_attach,	gpiobus_attach),
+	DEVMETHOD(device_detach,	gpiobus_detach),
+	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
+	DEVMETHOD(device_suspend,	gpiobus_suspend),
+	DEVMETHOD(device_resume,	gpiobus_resume),
+
+	/* Bus interface */
+	DEVMETHOD(bus_add_child,	gpiobus_add_child),
+	DEVMETHOD(bus_print_child,	gpiobus_print_child),
+	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
+	DEVMETHOD(bus_child_pnpinfo_str, gpiobus_child_pnpinfo_str),
+	DEVMETHOD(bus_child_location_str, gpiobus_child_location_str),
+	DEVMETHOD(bus_hinted_child,	gpiobus_hinted_child),
+
+	/* GPIO protocol */
+	DEVMETHOD(gpiobus_lock_bus,	gpiobus_lock_bus),
+	DEVMETHOD(gpiobus_unlock_bus,	gpiobus_unlock_bus),
+	DEVMETHOD(gpiobus_acquire_bus,	gpiobus_acquire_bus),
+	DEVMETHOD(gpiobus_release_bus,	gpiobus_release_bus),
+	DEVMETHOD(gpiobus_pin_getflags,	gpiobus_pin_getflags),
+	DEVMETHOD(gpiobus_pin_getcaps,	gpiobus_pin_getcaps),
+	DEVMETHOD(gpiobus_pin_setflags,	gpiobus_pin_setflags),
+	DEVMETHOD(gpiobus_pin_get,	gpiobus_pin_get),
+	DEVMETHOD(gpiobus_pin_set,	gpiobus_pin_set),
+	DEVMETHOD(gpiobus_pin_toggle,	gpiobus_pin_toggle),
+
+	{ 0, 0 }
+};
+
+static driver_t gpiobus_driver = {
+	"gpiobus",
+	gpiobus_methods,
+	sizeof(struct gpiobus_softc)
+};
+
+devclass_t	gpiobus_devclass;
+
+DRIVER_MODULE(gpiobus, gpio, gpiobus_driver, gpiobus_devclass, 0, 0);
+MODULE_VERSION(gpiobus, 1);

Added: head/sys/dev/gpio/gpiobus_if.m
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/dev/gpio/gpiobus_if.m	Tue Sep 28 03:24:53 2010	(r213237)
@@ -0,0 +1,121 @@
+#-
+# Copyright (c) 2009 Oleksandr Tymoshenko <gonzo at 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.
+#
+# $FreeBSD$
+#
+
+#include <sys/bus.h>
+#include <sys/gpio.h>
+
+INTERFACE gpiobus;
+
+#
+# Lock the gpio bus
+#
+METHOD void lock_bus {
+	device_t busdev;
+};
+
+#
+# Unlock the gpio bus
+#
+METHOD void unlock_bus {
+	device_t busdev;
+};
+
+#
+# Dedicate the gpio bus control for a child
+#
+METHOD void acquire_bus {
+	device_t busdev;
+	device_t dev;
+};
+
+#
+# Release the bus
+#
+METHOD void release_bus {
+	device_t busdev;
+	device_t dev;
+};
+
+#
+# Set value of pin specifed by pin_num 
+#
+METHOD int pin_set {
+	device_t dev;
+	device_t child;
+	uint32_t pin_num;
+	uint32_t pin_value;
+};
+
+#
+# Get value of pin specifed by pin_num 
+#
+METHOD int pin_get {
+	device_t dev;
+	device_t child;
+	uint32_t pin_num;
+	uint32_t *pin_value;
+};
+
+#
+# Toggle value of pin specifed by pin_num 
+#
+METHOD int pin_toggle {
+	device_t dev;
+	device_t child;
+	uint32_t pin_num;
+};
+
+#
+# Get pin capabilities
+#
+METHOD int pin_getcaps {
+	device_t dev;
+	device_t child;
+	uint32_t pin_num;
+	uint32_t *caps;
+};
+
+#
+# Get pin flags
+#
+METHOD int pin_getflags {
+	device_t dev;
+	device_t child;
+	uint32_t pin_num;
+	uint32_t *flags;
+};
+
+#
+# Set current configuration and capabilities
+#
+METHOD int pin_setflags {
+	device_t dev;
+	device_t child;
+	uint32_t pin_num;
+	uint32_t flags;
+};

Added: head/sys/dev/gpio/gpiobusvar.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/dev/gpio/gpiobusvar.h	Tue Sep 28 03:24:53 2010	(r213237)
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 2009 Oleksandr Tymoshenko <gonzo at 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 ``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.
+ *
+ * $FreeBSD$
+ *
+ */
+
+#ifndef	__GPIOBUS_H__
+#define	__GPIOBUS_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)
+
+struct gpiobus_softc
+{
+	struct mtx	sc_mtx;		/* bus mutex */
+	device_t	sc_busdev;	/* bus device */
+	device_t	sc_owner;	/* bus owner */
+	device_t	sc_dev;		/* driver device */
+	int		sc_npins;	/* total pins on bus */
+	int		*sc_pins_mapped; /* mark mapped pins */
+};
+
+
+struct gpiobus_ivar
+{
+	uint32_t	npins;	/* pins total */
+	uint32_t	*pins;	/* pins map */
+};
+
+#endif	/* __GPIOBUS_H__ */

Added: head/sys/dev/gpio/gpioc.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/dev/gpio/gpioc.c	Tue Sep 28 03:24:53 2010	(r213237)
@@ -0,0 +1,174 @@
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/types.h>
+
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/ioccom.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/queue.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+
+#include <sys/gpio.h>
+#include "gpio_if.h"
+
+#undef GPIOC_DEBUG
+#ifdef GPIOC_DEBUG
+#define dprintf printf
+#else
+#define dprintf(x, arg...)
+#endif
+
+static int gpioc_probe(device_t dev);
+static int gpioc_attach(device_t dev);
+static int gpioc_detach(device_t dev);
+
+static d_ioctl_t	gpioc_ioctl;
+
+static struct cdevsw gpioc_cdevsw = {
+	.d_version	= D_VERSION,
+	.d_ioctl	= gpioc_ioctl,
+	.d_name		= "gpioc",
+#if __FreeBSD_version >= 800039
+	.d_flags	= D_PSEUDO | D_NEEDMINOR
+#endif
+};
+
+struct gpioc_softc {
+	device_t	sc_dev;		/* gpiocX dev */
+	device_t	sc_pdev;	/* gpioX dev */
+	struct cdev	*sc_ctl_dev;	/* controller device */
+	int		sc_unit;
+};
+
+static int
+gpioc_probe(device_t dev)
+{
+	device_set_desc(dev, "GPIO controller");
+	return (0);
+}
+
+static int
+gpioc_attach(device_t dev)
+{
+	struct gpioc_softc *sc = device_get_softc(dev);
+
+	sc->sc_dev = dev;
+	sc->sc_pdev = device_get_parent(dev);
+	sc->sc_unit = device_get_unit(dev);
+	sc->sc_ctl_dev = make_dev(&gpioc_cdevsw, sc->sc_unit,
+	    UID_ROOT, GID_WHEEL, 0600, "gpioc%d", sc->sc_unit);
+	if (!sc->sc_ctl_dev) {
+		printf("Failed to create gpioc%d", sc->sc_unit);
+		return (ENXIO);
+	}
+	sc->sc_ctl_dev->si_drv1 = sc;
+
+	return (0);
+}
+
+static int
+gpioc_detach(device_t dev)
+{
+	struct gpioc_softc *sc = device_get_softc(dev);
+	int err;
+
+	if (sc->sc_ctl_dev);
+		destroy_dev(sc->sc_ctl_dev);
+
+	if ((err = bus_generic_detach(dev)) != 0)
+		return (err);
+
+	return (0);
+}
+
+static int 
+gpioc_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int fflag, 
+    struct thread *td)
+{
+	int max_pin, res;
+	struct gpioc_softc *sc = cdev->si_drv1;
+	struct gpio_pin pin;
+	struct gpio_req req;
+
+	switch (cmd) {
+		case GPIOMAXPIN:
+			max_pin = -1;
+			res = GPIO_PIN_MAX(sc->sc_pdev, &max_pin);
+			bcopy(&max_pin, arg, sizeof(max_pin));
+			break;
+		case GPIOGETCONFIG:
+			bcopy(arg, &pin, sizeof(pin));
+			dprintf("get config pin %d\n", pin.gp_pin);
+			res = GPIO_PIN_GETFLAGS(sc->sc_pdev, pin.gp_pin,
+			    &pin.gp_flags);
+			/* Fail early */
+			if (res)
+				break;
+			GPIO_PIN_GETCAPS(sc->sc_pdev, pin.gp_pin, &pin.gp_caps);
+			GPIO_PIN_GETNAME(sc->sc_pdev, pin.gp_pin, pin.gp_name);
+			bcopy(&pin, arg, sizeof(pin));
+			break;
+		case GPIOSETCONFIG:
+			bcopy(arg, &pin, sizeof(pin));
+			dprintf("set config pin %d\n", pin.gp_pin);
+			res = GPIO_PIN_SETFLAGS(sc->sc_pdev, pin.gp_pin,
+			    pin.gp_flags);
+			break;
+		case GPIOGET:
+			bcopy(arg, &req, sizeof(req));
+			res = GPIO_PIN_GET(sc->sc_pdev, req.gp_pin,
+			    &req.gp_value);
+			dprintf("read pin %d -> %d\n", 
+			    req.gp_pin, req.gp_value);
+			bcopy(&req, arg, sizeof(req));
+			break;
+		case GPIOSET:
+			bcopy(arg, &req, sizeof(req));
+			res = GPIO_PIN_SET(sc->sc_pdev, req.gp_pin, 
+			    req.gp_value);
+			dprintf("write pin %d -> %d\n", 
+			    req.gp_pin, req.gp_value);
+			break;
+		case GPIOTOGGLE:
+			bcopy(arg, &req, sizeof(req));
+			dprintf("toggle pin %d\n", 
+			    req.gp_pin);
+			res = GPIO_PIN_TOGGLE(sc->sc_pdev, req.gp_pin);
+			break;
+		default:
+			return (ENOTTY);
+			break;
+	}
+
+	return (res);
+}
+
+static device_method_t gpioc_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		gpioc_probe),
+	DEVMETHOD(device_attach,	gpioc_attach),
+	DEVMETHOD(device_detach,	gpioc_detach),
+	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
+	DEVMETHOD(device_suspend,	bus_generic_suspend),
+	DEVMETHOD(device_resume,	bus_generic_resume),
+
+	{ 0, 0 }
+};
+
+static driver_t gpioc_driver = {
+	"gpioc",
+	gpioc_methods,
+	sizeof(struct gpioc_softc)
+};
+
+devclass_t	gpioc_devclass;
+
+DRIVER_MODULE(gpioc, gpio, gpioc_driver, gpioc_devclass, 0, 0);
+MODULE_VERSION(gpioc, 1);

Added: head/sys/dev/gpio/gpioiic.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/dev/gpio/gpioiic.c	Tue Sep 28 03:24:53 2010	(r213237)
@@ -0,0 +1,245 @@
+/*-
+ * Copyright (c) 2009 Oleksandr Tymoshenko <gonzo at freebsd.org>
+ * Copyright (c) 2010 Luiz Otavio O Souza
+ * 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 ``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,

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-all mailing list