From owner-svn-src-head@freebsd.org Tue Aug 18 21:05:58 2015 Return-Path: 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 4EBC39BCB3A; Tue, 18 Aug 2015 21:05:58 +0000 (UTC) (envelope-from loos@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2001:1900:2254:2068::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 3CFCF1BC2; Tue, 18 Aug 2015 21:05:58 +0000 (UTC) (envelope-from loos@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.70]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id t7IL5woQ032806; Tue, 18 Aug 2015 21:05:58 GMT (envelope-from loos@FreeBSD.org) Received: (from loos@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id t7IL5v50032802; Tue, 18 Aug 2015 21:05:57 GMT (envelope-from loos@FreeBSD.org) Message-Id: <201508182105.t7IL5v50032802@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: loos set sender to loos@FreeBSD.org using -f From: Luiz Otavio O Souza Date: Tue, 18 Aug 2015 21:05:57 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r286908 - in head: share/man/man4 sys/conf sys/dev/rccgpio sys/modules/rccgpio 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 List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 18 Aug 2015 21:05:58 -0000 Author: loos Date: Tue Aug 18 21:05:56 2015 New Revision: 286908 URL: https://svnweb.freebsd.org/changeset/base/286908 Log: Add the GPIO driver for the ADI Engineering RCC-VE and RCC-DFF/DFFv2. This driver allows read the software reset switch state and control the status LEDs. The GPIO pins have their direction (input/output) locked down to prevent possible short circuits. Note that most people get a reset button that is a hardware reset. The software reset button is available on boards from Netgate. Sponsored by: Rubicon Communications (Netgate) Added: head/share/man/man4/rccgpio.4 (contents, props changed) head/sys/dev/rccgpio/ head/sys/dev/rccgpio/rccgpio.c (contents, props changed) head/sys/modules/rccgpio/ head/sys/modules/rccgpio/Makefile (contents, props changed) Modified: head/sys/conf/files Added: head/share/man/man4/rccgpio.4 ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/share/man/man4/rccgpio.4 Tue Aug 18 21:05:56 2015 (r286908) @@ -0,0 +1,63 @@ +.\" Copyright (c) 2015, Rubicon Communications, LLC (Netgate) +.\" 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$ +.\" +.Dd August 18, 2015 +.Dt RCCGPIO 4 +.Os +.Sh NAME +.Nm rccgpio +.Nd ADI Engineering RCC-VE and RCC-DFF/DFFv2 GPIO controller +.Sh SYNOPSIS +.Cd "device rccgpio" +.Cd "device gpio" +.Cd "device gpioled" +.Sh DESCRIPTION +The +.Nm +provides a simple interface to read the reset switch state and control the +status LEDs. +.Pp +The software controlled reset switch is known to be available on boards from +Netgate. +Most people get a button that is a hardware reset. +.Pp +All the GPIO pins are locked in their intended setup to disallow any harmful +settings (the ones that can cause short circuits). +.Sh SEE ALSO +.Xr gpio 3 , +.Xr gpio 4 , +.Xr gpioled 4 , +.Xr gpioctl 8 +.Sh HISTORY +The +.Nm +manual page first appeared in +.Fx 11.0 . +.Sh AUTHORS +The +.Nm +driver was written by +.An Luiz Otavio O Souza Aq Mt loos@FreeBSD.org . Modified: head/sys/conf/files ============================================================================== --- head/sys/conf/files Tue Aug 18 20:42:08 2015 (r286907) +++ head/sys/conf/files Tue Aug 18 21:05:56 2015 (r286908) @@ -2323,6 +2323,7 @@ dev/random/fortuna.c optional random !r dev/random/hash.c optional random random_yarrow | \ random !random_yarrow !random_loadable dev/rc/rc.c optional rc +dev/rccgpio/rccgpio.c optional rccgpio gpio dev/re/if_re.c optional re dev/rl/if_rl.c optional rl pci dev/rndtest/rndtest.c optional rndtest Added: head/sys/dev/rccgpio/rccgpio.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/dev/rccgpio/rccgpio.c Tue Aug 18 21:05:56 2015 (r286908) @@ -0,0 +1,368 @@ +/*- + * Copyright (c) 2015 Rubicon Communications, LLC (Netgate) + * 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$"); + +/* + * GPIO driver for the ADI Engineering RCC-VE and RCC-DFF/DFFv2. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "gpio_if.h" + +#define RCC_GPIO_BASE 0x500 +#define RCC_GPIO_USE_SEL 0x00 +#define RCC_GPIO_IO_SEL 0x04 +#define RCC_GPIO_GP_LVL 0x08 + +struct rcc_gpio_pin { + uint32_t pin; + const char *name; + uint32_t caps; +}; + +static struct rcc_gpio_pin rcc_pins[] = { + { .pin = 11, .name = "reset switch", .caps = GPIO_PIN_INPUT }, + { .pin = 15, .name = "red LED", .caps = GPIO_PIN_OUTPUT }, + { .pin = 17, .name = "green LED", .caps = GPIO_PIN_OUTPUT }, +#if 0 + { .pin = 16, .name = "HD1 LED", .caps = GPIO_PIN_OUTPUT }, + { .pin = 18, .name = "HD2 LED", .caps = GPIO_PIN_OUTPUT }, +#endif +}; + +struct rcc_gpio_softc { + device_t sc_dev; + device_t sc_busdev; + struct mtx sc_mtx; + struct resource *sc_io_res; + bus_space_tag_t sc_bst; + bus_space_handle_t sc_bsh; + uint32_t sc_output; + int sc_io_rid; + int sc_gpio_npins; +}; + +#define RCC_GPIO_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) +#define RCC_GPIO_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) +#define RCC_WRITE(_sc, _off, _val) \ + bus_space_write_4((_sc)->sc_bst, (_sc)->sc_bsh, _off, _val) +#define RCC_READ(_sc, _off) \ + bus_space_read_4((_sc)->sc_bst, (_sc)->sc_bsh, _off) + +static void +rcc_gpio_modify_bits(struct rcc_gpio_softc *sc, uint32_t reg, uint32_t mask, + uint32_t bit) +{ + uint32_t value; + + RCC_GPIO_LOCK(sc); + value = RCC_READ(sc, reg); + value &= ~(1 << mask); + value |= (1 << bit); + RCC_WRITE(sc, reg, value); + RCC_GPIO_UNLOCK(sc); +} + +static device_t +rcc_gpio_get_bus(device_t dev) +{ + struct rcc_gpio_softc *sc; + + sc = device_get_softc(dev); + + return (sc->sc_busdev); +} + +static int +rcc_gpio_pin_max(device_t dev, int *maxpin) +{ + struct rcc_gpio_softc *sc; + + sc = device_get_softc(dev); + *maxpin = sc->sc_gpio_npins - 1; + + return (0); +} + +static int +rcc_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) +{ + struct rcc_gpio_softc *sc; + + sc = device_get_softc(dev); + if (pin > sc->sc_gpio_npins) + return (EINVAL); + + *caps = rcc_pins[pin].caps; + + return (0); +} + +static int +rcc_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) +{ + struct rcc_gpio_softc *sc; + + sc = device_get_softc(dev); + if (pin > sc->sc_gpio_npins) + return (EINVAL); + + /* Flags cannot be changed. */ + *flags = rcc_pins[pin].caps; + + return (0); +} + +static int +rcc_gpio_pin_getname(device_t dev, uint32_t pin, char *name) +{ + struct rcc_gpio_softc *sc; + + sc = device_get_softc(dev); + if (pin > sc->sc_gpio_npins) + return (EINVAL); + + memcpy(name, rcc_pins[pin].name, GPIOMAXNAME); + + return (0); +} + +static int +rcc_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) +{ + struct rcc_gpio_softc *sc; + + sc = device_get_softc(dev); + if (pin > sc->sc_gpio_npins) + return (EINVAL); + + /* Flags cannot be changed - risk of short-circuit!!! */ + + return (0); +} + +static int +rcc_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value) +{ + struct rcc_gpio_softc *sc; + + sc = device_get_softc(dev); + if (pin > sc->sc_gpio_npins) + return (EINVAL); + + RCC_GPIO_LOCK(sc); + if (value) + sc->sc_output |= (1 << rcc_pins[pin].pin); + else + sc->sc_output &= ~(1 << rcc_pins[pin].pin); + RCC_WRITE(sc, RCC_GPIO_GP_LVL, sc->sc_output); + RCC_GPIO_UNLOCK(sc); + + return (0); +} + +static int +rcc_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val) +{ + struct rcc_gpio_softc *sc; + uint32_t value; + + sc = device_get_softc(dev); + if (pin > sc->sc_gpio_npins) + return (EINVAL); + + RCC_GPIO_LOCK(sc); + if (rcc_pins[pin].caps & GPIO_PIN_INPUT) + value = RCC_READ(sc, RCC_GPIO_GP_LVL); + else + value = sc->sc_output; + RCC_GPIO_UNLOCK(sc); + *val = (value & (1 << rcc_pins[pin].pin)) ? 1 : 0; + + return (0); +} + +static int +rcc_gpio_pin_toggle(device_t dev, uint32_t pin) +{ + struct rcc_gpio_softc *sc; + + sc = device_get_softc(dev); + if (pin > sc->sc_gpio_npins) + return (EINVAL); + + RCC_GPIO_LOCK(sc); + if ((sc->sc_output & (1 << rcc_pins[pin].pin)) == 0) + sc->sc_output |= (1 << rcc_pins[pin].pin); + else + sc->sc_output &= ~(1 << rcc_pins[pin].pin); + RCC_WRITE(sc, RCC_GPIO_GP_LVL, sc->sc_output); + RCC_GPIO_UNLOCK(sc); + + return (0); +} + +static int +rcc_gpio_probe(device_t dev) +{ + char *prod; + int port; + + /* + * We don't know of any PnP ID's for this GPIO controller. + */ + if (isa_get_logicalid(dev) != 0) + return (ENXIO); + + /* + * We have to have an IO port hint that is valid. + */ + port = isa_get_port(dev); + if (port != RCC_GPIO_BASE) + return (ENXIO); + + prod = kern_getenv("smbios.system.product"); + if (prod == NULL || + (strcmp(prod, "RCC-VE") != 0 && strcmp(prod, "RCC-DFF") != 0)) + return (ENXIO); + + device_set_desc(dev, "RCC-VE/DFF GPIO controller"); + + return (BUS_PROBE_DEFAULT); +} + +static int +rcc_gpio_attach(device_t dev) +{ + int i; + struct rcc_gpio_softc *sc; + + sc = device_get_softc(dev); + sc->sc_dev = dev; + + /* Allocate IO resources. */ + sc->sc_io_rid = 0; + sc->sc_io_res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, + &sc->sc_io_rid, RF_ACTIVE); + if (sc->sc_io_res == NULL) { + device_printf(dev, "cannot allocate memory window\n"); + return (ENXIO); + } + sc->sc_bst = rman_get_bustag(sc->sc_io_res); + sc->sc_bsh = rman_get_bushandle(sc->sc_io_res); + mtx_init(&sc->sc_mtx, "rcc-gpio", "gpio", MTX_DEF); + + /* Initialize the pins. */ + sc->sc_gpio_npins = nitems(rcc_pins); + for (i = 0; i < sc->sc_gpio_npins; i++) { + /* Enable it for GPIO. */ + rcc_gpio_modify_bits(sc, RCC_GPIO_USE_SEL, 0, rcc_pins[i].pin); + /* Set the pin as input or output. */ + if (rcc_pins[i].caps & GPIO_PIN_OUTPUT) + rcc_gpio_modify_bits(sc, RCC_GPIO_IO_SEL, + rcc_pins[i].pin, 0); + else + rcc_gpio_modify_bits(sc, RCC_GPIO_IO_SEL, + 0, rcc_pins[i].pin); + } + RCC_WRITE(sc, RCC_GPIO_GP_LVL, sc->sc_output); + + /* Attach the gpiobus. */ + sc->sc_busdev = gpiobus_attach_bus(dev); + if (sc->sc_busdev == NULL) { + bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_io_rid, + sc->sc_io_res); + mtx_destroy(&sc->sc_mtx); + return (ENXIO); + } + + return (0); +} + +static int +rcc_gpio_detach(device_t dev) +{ + int i; + struct rcc_gpio_softc *sc; + + sc = device_get_softc(dev); + gpiobus_detach_bus(dev); + + /* Disable the GPIO function. */ + for (i = 0; i < sc->sc_gpio_npins; i++) + rcc_gpio_modify_bits(sc, RCC_GPIO_USE_SEL, rcc_pins[i].pin, 0); + + if (sc->sc_io_res != NULL) + bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_io_rid, + sc->sc_io_res); + mtx_destroy(&sc->sc_mtx); + + return (0); +} + +static device_method_t rcc_gpio_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, rcc_gpio_probe), + DEVMETHOD(device_attach, rcc_gpio_attach), + DEVMETHOD(device_detach, rcc_gpio_detach), + + /* GPIO protocol */ + DEVMETHOD(gpio_get_bus, rcc_gpio_get_bus), + DEVMETHOD(gpio_pin_max, rcc_gpio_pin_max), + DEVMETHOD(gpio_pin_getname, rcc_gpio_pin_getname), + DEVMETHOD(gpio_pin_getflags, rcc_gpio_pin_getflags), + DEVMETHOD(gpio_pin_getcaps, rcc_gpio_pin_getcaps), + DEVMETHOD(gpio_pin_setflags, rcc_gpio_pin_setflags), + DEVMETHOD(gpio_pin_get, rcc_gpio_pin_get), + DEVMETHOD(gpio_pin_set, rcc_gpio_pin_set), + DEVMETHOD(gpio_pin_toggle, rcc_gpio_pin_toggle), + + DEVMETHOD_END +}; + +static devclass_t rcc_gpio_devclass; + +static driver_t rcc_gpio_driver = { + "gpio", + rcc_gpio_methods, + sizeof(struct rcc_gpio_softc), +}; + +DRIVER_MODULE(rcc_gpio, isa, rcc_gpio_driver, rcc_gpio_devclass, 0, 0); +MODULE_DEPEND(rcc_gpio, gpiobus, 1, 1, 1); Added: head/sys/modules/rccgpio/Makefile ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/modules/rccgpio/Makefile Tue Aug 18 21:05:56 2015 (r286908) @@ -0,0 +1,8 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../dev/rccgpio +KMOD= rccgpio +SRCS= rccgpio.c +SRCS+= device_if.h bus_if.h isa_if.h gpio_if.h opt_platform.h + +.include