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 l...@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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * GPIO driver for the ADI Engineering RCC-VE and RCC-DFF/DFFv2.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/gpio.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+
+#include <machine/bus.h>
+
+#include <dev/gpio/gpiobusvar.h>
+#include <isa/isavar.h>
+
+#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 <bsd.kmod.mk>
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to