From owner-svn-src-all@FreeBSD.ORG Tue Sep 28 03:24:53 2010 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id DD2991065674; Tue, 28 Sep 2010 03:24:53 +0000 (UTC) (envelope-from gonzo@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id CA8F88FC14; Tue, 28 Sep 2010 03:24:53 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id o8S3OrVw058055; Tue, 28 Sep 2010 03:24:53 GMT (envelope-from gonzo@svn.freebsd.org) Received: (from gonzo@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id o8S3OrV9058046; Tue, 28 Sep 2010 03:24:53 GMT (envelope-from gonzo@svn.freebsd.org) Message-Id: <201009280324.o8S3OrV9058046@svn.freebsd.org> From: Oleksandr Tymoshenko Date: Tue, 28 Sep 2010 03:24:53 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r213237 - in head/sys: conf dev/gpio sys X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 28 Sep 2010 03:24:54 -0000 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 +# 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 +#include + +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 + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#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 +# 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 +#include + +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 + * 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 +#include +#include + +#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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#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 + * 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 ***