13706af42SArnaud Ysmal /*-
23706af42SArnaud Ysmal * Copyright (c) 2018 Stormshield
33706af42SArnaud Ysmal * All rights reserved.
43706af42SArnaud Ysmal *
53706af42SArnaud Ysmal * Redistribution and use in source and binary forms, with or without
63706af42SArnaud Ysmal * modification, are permitted provided that the following conditions
73706af42SArnaud Ysmal * are met:
83706af42SArnaud Ysmal * 1. Redistributions of source code must retain the above copyright
93706af42SArnaud Ysmal * notice, this list of conditions and the following disclaimer.
103706af42SArnaud Ysmal * 2. Redistributions in binary form must reproduce the above copyright
113706af42SArnaud Ysmal * notice, this list of conditions and the following disclaimer in the
123706af42SArnaud Ysmal * documentation and/or other materials provided with the distribution.
133706af42SArnaud Ysmal *
143706af42SArnaud Ysmal * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
153706af42SArnaud Ysmal * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
163706af42SArnaud Ysmal * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
173706af42SArnaud Ysmal * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
183706af42SArnaud Ysmal * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
193706af42SArnaud Ysmal * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
203706af42SArnaud Ysmal * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
213706af42SArnaud Ysmal * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
223706af42SArnaud Ysmal * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
233706af42SArnaud Ysmal * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
243706af42SArnaud Ysmal * SUCH DAMAGE.
253706af42SArnaud Ysmal */
263706af42SArnaud Ysmal
273706af42SArnaud Ysmal #include <sys/param.h> /* defines used in kernel.h */
283706af42SArnaud Ysmal #include <sys/module.h>
293706af42SArnaud Ysmal #include <sys/systm.h>
303706af42SArnaud Ysmal #include <sys/errno.h>
313706af42SArnaud Ysmal #include <sys/kernel.h> /* types used in module initialization */
323706af42SArnaud Ysmal #include <sys/conf.h> /* cdevsw struct */
333706af42SArnaud Ysmal #include <sys/uio.h> /* uio struct */
343706af42SArnaud Ysmal #include <sys/malloc.h>
353706af42SArnaud Ysmal #include <sys/bus.h> /* structs, prototypes for pci bus stuff and DEVMETHOD macros! */
363706af42SArnaud Ysmal #include <sys/gpio.h>
373706af42SArnaud Ysmal
383706af42SArnaud Ysmal #include <machine/bus.h>
393706af42SArnaud Ysmal #include <sys/rman.h>
403706af42SArnaud Ysmal #include <machine/resource.h>
413706af42SArnaud Ysmal
423706af42SArnaud Ysmal #include <dev/gpio/gpiobusvar.h>
433706af42SArnaud Ysmal
443706af42SArnaud Ysmal #include "gpio_if.h"
453706af42SArnaud Ysmal
463706af42SArnaud Ysmal #include "lewisburg_gpiocm.h"
473706af42SArnaud Ysmal
483706af42SArnaud Ysmal #define P2SB_GROUP_GPIO_MAX_PINS 24
493706af42SArnaud Ysmal struct lbggpio_softc
503706af42SArnaud Ysmal {
513706af42SArnaud Ysmal device_t sc_busdev;
523706af42SArnaud Ysmal int groupid;
533706af42SArnaud Ysmal int pins_off;
543706af42SArnaud Ysmal int npins;
553706af42SArnaud Ysmal char grpname;
563706af42SArnaud Ysmal struct gpio_pin gpio_setup[P2SB_GROUP_GPIO_MAX_PINS];
573706af42SArnaud Ysmal };
583706af42SArnaud Ysmal
593706af42SArnaud Ysmal static device_t
lbggpio_get_bus(device_t dev)603706af42SArnaud Ysmal lbggpio_get_bus(device_t dev)
613706af42SArnaud Ysmal {
623706af42SArnaud Ysmal struct lbggpio_softc *sc;
633706af42SArnaud Ysmal
643706af42SArnaud Ysmal sc = device_get_softc(dev);
653706af42SArnaud Ysmal
663706af42SArnaud Ysmal return (sc->sc_busdev);
673706af42SArnaud Ysmal }
683706af42SArnaud Ysmal
693706af42SArnaud Ysmal static int
lbggpio_pin_max(device_t dev,int * maxpin)703706af42SArnaud Ysmal lbggpio_pin_max(device_t dev, int *maxpin)
713706af42SArnaud Ysmal {
723706af42SArnaud Ysmal struct lbggpio_softc *sc;
733706af42SArnaud Ysmal
743706af42SArnaud Ysmal if (maxpin == NULL)
753706af42SArnaud Ysmal return (EINVAL);
763706af42SArnaud Ysmal
773706af42SArnaud Ysmal sc = device_get_softc(dev);
783706af42SArnaud Ysmal
793706af42SArnaud Ysmal *maxpin = sc->npins - 1;
803706af42SArnaud Ysmal
813706af42SArnaud Ysmal return (0);
823706af42SArnaud Ysmal }
833706af42SArnaud Ysmal
843706af42SArnaud Ysmal static int
lbggpio_pin_getname(device_t dev,uint32_t pin,char * name)853706af42SArnaud Ysmal lbggpio_pin_getname(device_t dev, uint32_t pin, char *name)
863706af42SArnaud Ysmal {
873706af42SArnaud Ysmal struct lbggpio_softc *sc = device_get_softc(dev);
883706af42SArnaud Ysmal
893706af42SArnaud Ysmal if (name == NULL)
903706af42SArnaud Ysmal return (EINVAL);
913706af42SArnaud Ysmal
923706af42SArnaud Ysmal if (pin >= sc->npins)
933706af42SArnaud Ysmal return (EINVAL);
943706af42SArnaud Ysmal
953706af42SArnaud Ysmal strlcpy(name, sc->gpio_setup[pin].gp_name, GPIOMAXNAME);
963706af42SArnaud Ysmal
973706af42SArnaud Ysmal return (0);
983706af42SArnaud Ysmal }
993706af42SArnaud Ysmal
1003706af42SArnaud Ysmal static int
lbggpio_pin_getflags(device_t dev,uint32_t pin,uint32_t * flags)1013706af42SArnaud Ysmal lbggpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
1023706af42SArnaud Ysmal {
1033706af42SArnaud Ysmal struct lbggpio_softc *sc = device_get_softc(dev);
1043706af42SArnaud Ysmal
1053706af42SArnaud Ysmal if (flags == NULL)
1063706af42SArnaud Ysmal return (EINVAL);
1073706af42SArnaud Ysmal
1083706af42SArnaud Ysmal if (pin >= sc->npins)
1093706af42SArnaud Ysmal return (EINVAL);
1103706af42SArnaud Ysmal
1113706af42SArnaud Ysmal *flags = sc->gpio_setup[pin].gp_flags;
1123706af42SArnaud Ysmal
1133706af42SArnaud Ysmal return (0);
1143706af42SArnaud Ysmal }
1153706af42SArnaud Ysmal
1163706af42SArnaud Ysmal static int
lbggpio_pin_getcaps(device_t dev,uint32_t pin,uint32_t * caps)1173706af42SArnaud Ysmal lbggpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
1183706af42SArnaud Ysmal {
1193706af42SArnaud Ysmal struct lbggpio_softc *sc = device_get_softc(dev);
1203706af42SArnaud Ysmal
1213706af42SArnaud Ysmal if (caps == NULL)
1223706af42SArnaud Ysmal return (EINVAL);
1233706af42SArnaud Ysmal
1243706af42SArnaud Ysmal if (pin >= sc->npins)
1253706af42SArnaud Ysmal return (EINVAL);
1263706af42SArnaud Ysmal
1273706af42SArnaud Ysmal *caps = sc->gpio_setup[pin].gp_caps;
1283706af42SArnaud Ysmal
1293706af42SArnaud Ysmal return (0);
1303706af42SArnaud Ysmal }
1313706af42SArnaud Ysmal
1323706af42SArnaud Ysmal static int
lbggpio_pin_setflags(device_t dev,uint32_t pin,uint32_t flags)1333706af42SArnaud Ysmal lbggpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
1343706af42SArnaud Ysmal {
1353706af42SArnaud Ysmal struct lbggpio_softc *sc = device_get_softc(dev);
1363706af42SArnaud Ysmal
1373706af42SArnaud Ysmal if (pin >= sc->npins)
1383706af42SArnaud Ysmal return (EINVAL);
1393706af42SArnaud Ysmal
1403706af42SArnaud Ysmal /* Check for unwanted flags. */
1413706af42SArnaud Ysmal if ((flags & sc->gpio_setup[pin].gp_caps) != flags)
1423706af42SArnaud Ysmal return (EINVAL);
1433706af42SArnaud Ysmal
1443706af42SArnaud Ysmal lbggpiocm_pin_setflags(device_get_parent(dev), dev, pin, flags);
1453706af42SArnaud Ysmal sc->gpio_setup[pin].gp_flags = flags;
1463706af42SArnaud Ysmal
1473706af42SArnaud Ysmal return (0);
1483706af42SArnaud Ysmal }
1493706af42SArnaud Ysmal
1503706af42SArnaud Ysmal static int
lbggpio_pin_get(device_t dev,uint32_t pin,uint32_t * value)1513706af42SArnaud Ysmal lbggpio_pin_get(device_t dev, uint32_t pin, uint32_t *value)
1523706af42SArnaud Ysmal {
1533706af42SArnaud Ysmal struct lbggpio_softc *sc = device_get_softc(dev);
1543706af42SArnaud Ysmal
1553706af42SArnaud Ysmal if (value == NULL)
1563706af42SArnaud Ysmal return (EINVAL);
1573706af42SArnaud Ysmal
1583706af42SArnaud Ysmal if (pin >= sc->npins)
1593706af42SArnaud Ysmal return (EINVAL);
1603706af42SArnaud Ysmal
1613706af42SArnaud Ysmal return (lbggpiocm_pin_get(device_get_parent(dev), dev, pin, value));
1623706af42SArnaud Ysmal }
1633706af42SArnaud Ysmal
1643706af42SArnaud Ysmal static int
lbggpio_pin_set(device_t dev,uint32_t pin,uint32_t value)1653706af42SArnaud Ysmal lbggpio_pin_set(device_t dev, uint32_t pin, uint32_t value)
1663706af42SArnaud Ysmal {
1673706af42SArnaud Ysmal struct lbggpio_softc *sc = device_get_softc(dev);
1683706af42SArnaud Ysmal
1693706af42SArnaud Ysmal if (pin >= sc->npins)
1703706af42SArnaud Ysmal return (EINVAL);
1713706af42SArnaud Ysmal
1723706af42SArnaud Ysmal return (lbggpiocm_pin_set(device_get_parent(dev), dev, pin, value));
1733706af42SArnaud Ysmal }
1743706af42SArnaud Ysmal
1753706af42SArnaud Ysmal static int
lbggpio_pin_toggle(device_t dev,uint32_t pin)1763706af42SArnaud Ysmal lbggpio_pin_toggle(device_t dev, uint32_t pin)
1773706af42SArnaud Ysmal {
1783706af42SArnaud Ysmal struct lbggpio_softc *sc = device_get_softc(dev);
1793706af42SArnaud Ysmal
1803706af42SArnaud Ysmal if (pin >= sc->npins)
1813706af42SArnaud Ysmal return (EINVAL);
1823706af42SArnaud Ysmal
1833706af42SArnaud Ysmal return (lbggpiocm_pin_toggle(device_get_parent(dev), dev, pin));
1843706af42SArnaud Ysmal }
1853706af42SArnaud Ysmal
1863706af42SArnaud Ysmal static int
lbggpio_probe(device_t dev)1873706af42SArnaud Ysmal lbggpio_probe(device_t dev)
1883706af42SArnaud Ysmal {
1893706af42SArnaud Ysmal struct lbggpio_softc *sc = device_get_softc(dev);
1903706af42SArnaud Ysmal /* X is a placeholder for the actual one letter group name. */
1913706af42SArnaud Ysmal static char desc[] = "LewisBurg GPIO Group X";
1923706af42SArnaud Ysmal
1933706af42SArnaud Ysmal sc->npins = lbggpiocm_get_group_npins(device_get_parent(dev), dev);
1943706af42SArnaud Ysmal sc->grpname = lbggpiocm_get_group_name(device_get_parent(dev), dev);
1953706af42SArnaud Ysmal if (sc->npins <= 0)
1963706af42SArnaud Ysmal return (ENXIO);
1973706af42SArnaud Ysmal
1983706af42SArnaud Ysmal desc[sizeof(desc)-2] = sc->grpname;
1993706af42SArnaud Ysmal device_set_desc_copy(dev, desc);
2003706af42SArnaud Ysmal return (BUS_PROBE_DEFAULT);
2013706af42SArnaud Ysmal }
2023706af42SArnaud Ysmal
2033706af42SArnaud Ysmal static int
lbggpio_attach(device_t dev)2043706af42SArnaud Ysmal lbggpio_attach(device_t dev)
2053706af42SArnaud Ysmal {
2063706af42SArnaud Ysmal uint32_t i;
2073706af42SArnaud Ysmal struct lbggpio_softc *sc;
2083706af42SArnaud Ysmal
2093706af42SArnaud Ysmal sc = device_get_softc(dev);
2103706af42SArnaud Ysmal /* GPIO config */
2113706af42SArnaud Ysmal for (i = 0; i < sc->npins; ++i) {
2123706af42SArnaud Ysmal sc->gpio_setup[i].gp_pin = i;
2133706af42SArnaud Ysmal snprintf(sc->gpio_setup[i].gp_name,
2143706af42SArnaud Ysmal sizeof(sc->gpio_setup[i].gp_name),
2153706af42SArnaud Ysmal "GPIO %c%u", sc->grpname, i);
2163706af42SArnaud Ysmal sc->gpio_setup[i].gp_caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT;
2173706af42SArnaud Ysmal }
2183706af42SArnaud Ysmal
2193706af42SArnaud Ysmal /* support gpio */
2203706af42SArnaud Ysmal sc->sc_busdev = gpiobus_attach_bus(dev);
2213706af42SArnaud Ysmal if (sc->sc_busdev == NULL)
2223706af42SArnaud Ysmal return (ENXIO);
2233706af42SArnaud Ysmal
2243706af42SArnaud Ysmal return (0);
2253706af42SArnaud Ysmal }
2263706af42SArnaud Ysmal
2273706af42SArnaud Ysmal static int
lbggpio_detach(device_t dev)2283706af42SArnaud Ysmal lbggpio_detach(device_t dev)
2293706af42SArnaud Ysmal {
2303706af42SArnaud Ysmal struct lbggpio_softc *sc;
2313706af42SArnaud Ysmal
2323706af42SArnaud Ysmal sc = device_get_softc(dev);
2333706af42SArnaud Ysmal
2343706af42SArnaud Ysmal if (sc->sc_busdev)
2353706af42SArnaud Ysmal gpiobus_detach_bus(dev);
2363706af42SArnaud Ysmal
2373706af42SArnaud Ysmal return (0);
2383706af42SArnaud Ysmal }
2393706af42SArnaud Ysmal
2403706af42SArnaud Ysmal static device_method_t lbggpio_methods[] = {
2413706af42SArnaud Ysmal /* Device interface */
2423706af42SArnaud Ysmal DEVMETHOD(device_probe, lbggpio_probe),
2433706af42SArnaud Ysmal DEVMETHOD(device_attach, lbggpio_attach),
2443706af42SArnaud Ysmal DEVMETHOD(device_detach, lbggpio_detach),
2453706af42SArnaud Ysmal
2463706af42SArnaud Ysmal /* GPIO protocol */
2473706af42SArnaud Ysmal DEVMETHOD(gpio_get_bus, lbggpio_get_bus),
2483706af42SArnaud Ysmal DEVMETHOD(gpio_pin_max, lbggpio_pin_max),
2493706af42SArnaud Ysmal DEVMETHOD(gpio_pin_getcaps, lbggpio_pin_getcaps),
2503706af42SArnaud Ysmal DEVMETHOD(gpio_pin_getflags, lbggpio_pin_getflags),
2513706af42SArnaud Ysmal DEVMETHOD(gpio_pin_setflags, lbggpio_pin_setflags),
2523706af42SArnaud Ysmal DEVMETHOD(gpio_pin_getname, lbggpio_pin_getname),
2533706af42SArnaud Ysmal DEVMETHOD(gpio_pin_set, lbggpio_pin_set),
2543706af42SArnaud Ysmal DEVMETHOD(gpio_pin_get, lbggpio_pin_get),
2553706af42SArnaud Ysmal DEVMETHOD(gpio_pin_toggle, lbggpio_pin_toggle),
2563706af42SArnaud Ysmal
2573706af42SArnaud Ysmal DEVMETHOD_END
2583706af42SArnaud Ysmal };
2593706af42SArnaud Ysmal
2603706af42SArnaud Ysmal static driver_t lbggpio_driver = {
2613706af42SArnaud Ysmal "gpio",
2623706af42SArnaud Ysmal lbggpio_methods,
2633706af42SArnaud Ysmal sizeof(struct lbggpio_softc)
2643706af42SArnaud Ysmal };
2653706af42SArnaud Ysmal
266*ba58fd66SJohn Baldwin DRIVER_MODULE(lbggpio, lbggpiocm, lbggpio_driver, NULL, NULL);
2673706af42SArnaud Ysmal MODULE_DEPEND(lbggpio, gpiobus, 1, 1, 1);
268