1*3706af42SArnaud Ysmal /*- 2*3706af42SArnaud Ysmal * Copyright (c) 2018 Stormshield 3*3706af42SArnaud Ysmal * All rights reserved. 4*3706af42SArnaud Ysmal * 5*3706af42SArnaud Ysmal * Redistribution and use in source and binary forms, with or without 6*3706af42SArnaud Ysmal * modification, are permitted provided that the following conditions 7*3706af42SArnaud Ysmal * are met: 8*3706af42SArnaud Ysmal * 1. Redistributions of source code must retain the above copyright 9*3706af42SArnaud Ysmal * notice, this list of conditions and the following disclaimer. 10*3706af42SArnaud Ysmal * 2. Redistributions in binary form must reproduce the above copyright 11*3706af42SArnaud Ysmal * notice, this list of conditions and the following disclaimer in the 12*3706af42SArnaud Ysmal * documentation and/or other materials provided with the distribution. 13*3706af42SArnaud Ysmal * 14*3706af42SArnaud Ysmal * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15*3706af42SArnaud Ysmal * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16*3706af42SArnaud Ysmal * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17*3706af42SArnaud Ysmal * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18*3706af42SArnaud Ysmal * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19*3706af42SArnaud Ysmal * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20*3706af42SArnaud Ysmal * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21*3706af42SArnaud Ysmal * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22*3706af42SArnaud Ysmal * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23*3706af42SArnaud Ysmal * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24*3706af42SArnaud Ysmal * SUCH DAMAGE. 25*3706af42SArnaud Ysmal */ 26*3706af42SArnaud Ysmal 27*3706af42SArnaud Ysmal #include <sys/param.h> /* defines used in kernel.h */ 28*3706af42SArnaud Ysmal #include <sys/module.h> 29*3706af42SArnaud Ysmal #include <sys/systm.h> 30*3706af42SArnaud Ysmal #include <sys/errno.h> 31*3706af42SArnaud Ysmal #include <sys/kernel.h> /* types used in module initialization */ 32*3706af42SArnaud Ysmal #include <sys/conf.h> /* cdevsw struct */ 33*3706af42SArnaud Ysmal #include <sys/uio.h> /* uio struct */ 34*3706af42SArnaud Ysmal #include <sys/malloc.h> 35*3706af42SArnaud Ysmal #include <sys/bus.h> /* structs, prototypes for pci bus stuff and DEVMETHOD macros! */ 36*3706af42SArnaud Ysmal #include <sys/gpio.h> 37*3706af42SArnaud Ysmal 38*3706af42SArnaud Ysmal #include <machine/bus.h> 39*3706af42SArnaud Ysmal #include <sys/rman.h> 40*3706af42SArnaud Ysmal #include <machine/resource.h> 41*3706af42SArnaud Ysmal 42*3706af42SArnaud Ysmal #include <dev/gpio/gpiobusvar.h> 43*3706af42SArnaud Ysmal 44*3706af42SArnaud Ysmal #include "gpio_if.h" 45*3706af42SArnaud Ysmal 46*3706af42SArnaud Ysmal #include "lewisburg_gpiocm.h" 47*3706af42SArnaud Ysmal 48*3706af42SArnaud Ysmal #define P2SB_GROUP_GPIO_MAX_PINS 24 49*3706af42SArnaud Ysmal struct lbggpio_softc 50*3706af42SArnaud Ysmal { 51*3706af42SArnaud Ysmal device_t sc_busdev; 52*3706af42SArnaud Ysmal int groupid; 53*3706af42SArnaud Ysmal int pins_off; 54*3706af42SArnaud Ysmal int npins; 55*3706af42SArnaud Ysmal char grpname; 56*3706af42SArnaud Ysmal struct gpio_pin gpio_setup[P2SB_GROUP_GPIO_MAX_PINS]; 57*3706af42SArnaud Ysmal }; 58*3706af42SArnaud Ysmal 59*3706af42SArnaud Ysmal static device_t 60*3706af42SArnaud Ysmal lbggpio_get_bus(device_t dev) 61*3706af42SArnaud Ysmal { 62*3706af42SArnaud Ysmal struct lbggpio_softc *sc; 63*3706af42SArnaud Ysmal 64*3706af42SArnaud Ysmal sc = device_get_softc(dev); 65*3706af42SArnaud Ysmal 66*3706af42SArnaud Ysmal return (sc->sc_busdev); 67*3706af42SArnaud Ysmal } 68*3706af42SArnaud Ysmal 69*3706af42SArnaud Ysmal static int 70*3706af42SArnaud Ysmal lbggpio_pin_max(device_t dev, int *maxpin) 71*3706af42SArnaud Ysmal { 72*3706af42SArnaud Ysmal struct lbggpio_softc *sc; 73*3706af42SArnaud Ysmal 74*3706af42SArnaud Ysmal if (maxpin == NULL) 75*3706af42SArnaud Ysmal return (EINVAL); 76*3706af42SArnaud Ysmal 77*3706af42SArnaud Ysmal sc = device_get_softc(dev); 78*3706af42SArnaud Ysmal 79*3706af42SArnaud Ysmal *maxpin = sc->npins - 1; 80*3706af42SArnaud Ysmal 81*3706af42SArnaud Ysmal return (0); 82*3706af42SArnaud Ysmal } 83*3706af42SArnaud Ysmal 84*3706af42SArnaud Ysmal static int 85*3706af42SArnaud Ysmal lbggpio_pin_getname(device_t dev, uint32_t pin, char *name) 86*3706af42SArnaud Ysmal { 87*3706af42SArnaud Ysmal struct lbggpio_softc *sc = device_get_softc(dev); 88*3706af42SArnaud Ysmal 89*3706af42SArnaud Ysmal if (name == NULL) 90*3706af42SArnaud Ysmal return (EINVAL); 91*3706af42SArnaud Ysmal 92*3706af42SArnaud Ysmal if (pin >= sc->npins) 93*3706af42SArnaud Ysmal return (EINVAL); 94*3706af42SArnaud Ysmal 95*3706af42SArnaud Ysmal strlcpy(name, sc->gpio_setup[pin].gp_name, GPIOMAXNAME); 96*3706af42SArnaud Ysmal 97*3706af42SArnaud Ysmal return (0); 98*3706af42SArnaud Ysmal } 99*3706af42SArnaud Ysmal 100*3706af42SArnaud Ysmal static int 101*3706af42SArnaud Ysmal lbggpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) 102*3706af42SArnaud Ysmal { 103*3706af42SArnaud Ysmal struct lbggpio_softc *sc = device_get_softc(dev); 104*3706af42SArnaud Ysmal 105*3706af42SArnaud Ysmal if (flags == NULL) 106*3706af42SArnaud Ysmal return (EINVAL); 107*3706af42SArnaud Ysmal 108*3706af42SArnaud Ysmal if (pin >= sc->npins) 109*3706af42SArnaud Ysmal return (EINVAL); 110*3706af42SArnaud Ysmal 111*3706af42SArnaud Ysmal *flags = sc->gpio_setup[pin].gp_flags; 112*3706af42SArnaud Ysmal 113*3706af42SArnaud Ysmal return (0); 114*3706af42SArnaud Ysmal } 115*3706af42SArnaud Ysmal 116*3706af42SArnaud Ysmal static int 117*3706af42SArnaud Ysmal lbggpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) 118*3706af42SArnaud Ysmal { 119*3706af42SArnaud Ysmal struct lbggpio_softc *sc = device_get_softc(dev); 120*3706af42SArnaud Ysmal 121*3706af42SArnaud Ysmal if (caps == NULL) 122*3706af42SArnaud Ysmal return (EINVAL); 123*3706af42SArnaud Ysmal 124*3706af42SArnaud Ysmal if (pin >= sc->npins) 125*3706af42SArnaud Ysmal return (EINVAL); 126*3706af42SArnaud Ysmal 127*3706af42SArnaud Ysmal *caps = sc->gpio_setup[pin].gp_caps; 128*3706af42SArnaud Ysmal 129*3706af42SArnaud Ysmal return (0); 130*3706af42SArnaud Ysmal } 131*3706af42SArnaud Ysmal 132*3706af42SArnaud Ysmal static int 133*3706af42SArnaud Ysmal lbggpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) 134*3706af42SArnaud Ysmal { 135*3706af42SArnaud Ysmal struct lbggpio_softc *sc = device_get_softc(dev); 136*3706af42SArnaud Ysmal 137*3706af42SArnaud Ysmal if (pin >= sc->npins) 138*3706af42SArnaud Ysmal return (EINVAL); 139*3706af42SArnaud Ysmal 140*3706af42SArnaud Ysmal /* Check for unwanted flags. */ 141*3706af42SArnaud Ysmal if ((flags & sc->gpio_setup[pin].gp_caps) != flags) 142*3706af42SArnaud Ysmal return (EINVAL); 143*3706af42SArnaud Ysmal 144*3706af42SArnaud Ysmal lbggpiocm_pin_setflags(device_get_parent(dev), dev, pin, flags); 145*3706af42SArnaud Ysmal sc->gpio_setup[pin].gp_flags = flags; 146*3706af42SArnaud Ysmal 147*3706af42SArnaud Ysmal return (0); 148*3706af42SArnaud Ysmal } 149*3706af42SArnaud Ysmal 150*3706af42SArnaud Ysmal static int 151*3706af42SArnaud Ysmal lbggpio_pin_get(device_t dev, uint32_t pin, uint32_t *value) 152*3706af42SArnaud Ysmal { 153*3706af42SArnaud Ysmal struct lbggpio_softc *sc = device_get_softc(dev); 154*3706af42SArnaud Ysmal 155*3706af42SArnaud Ysmal if (value == NULL) 156*3706af42SArnaud Ysmal return (EINVAL); 157*3706af42SArnaud Ysmal 158*3706af42SArnaud Ysmal if (pin >= sc->npins) 159*3706af42SArnaud Ysmal return (EINVAL); 160*3706af42SArnaud Ysmal 161*3706af42SArnaud Ysmal return (lbggpiocm_pin_get(device_get_parent(dev), dev, pin, value)); 162*3706af42SArnaud Ysmal } 163*3706af42SArnaud Ysmal 164*3706af42SArnaud Ysmal static int 165*3706af42SArnaud Ysmal lbggpio_pin_set(device_t dev, uint32_t pin, uint32_t value) 166*3706af42SArnaud Ysmal { 167*3706af42SArnaud Ysmal struct lbggpio_softc *sc = device_get_softc(dev); 168*3706af42SArnaud Ysmal 169*3706af42SArnaud Ysmal if (pin >= sc->npins) 170*3706af42SArnaud Ysmal return (EINVAL); 171*3706af42SArnaud Ysmal 172*3706af42SArnaud Ysmal return (lbggpiocm_pin_set(device_get_parent(dev), dev, pin, value)); 173*3706af42SArnaud Ysmal } 174*3706af42SArnaud Ysmal 175*3706af42SArnaud Ysmal static int 176*3706af42SArnaud Ysmal lbggpio_pin_toggle(device_t dev, uint32_t pin) 177*3706af42SArnaud Ysmal { 178*3706af42SArnaud Ysmal struct lbggpio_softc *sc = device_get_softc(dev); 179*3706af42SArnaud Ysmal 180*3706af42SArnaud Ysmal if (pin >= sc->npins) 181*3706af42SArnaud Ysmal return (EINVAL); 182*3706af42SArnaud Ysmal 183*3706af42SArnaud Ysmal return (lbggpiocm_pin_toggle(device_get_parent(dev), dev, pin)); 184*3706af42SArnaud Ysmal } 185*3706af42SArnaud Ysmal 186*3706af42SArnaud Ysmal static int 187*3706af42SArnaud Ysmal lbggpio_probe(device_t dev) 188*3706af42SArnaud Ysmal { 189*3706af42SArnaud Ysmal struct lbggpio_softc *sc = device_get_softc(dev); 190*3706af42SArnaud Ysmal /* X is a placeholder for the actual one letter group name. */ 191*3706af42SArnaud Ysmal static char desc[] = "LewisBurg GPIO Group X"; 192*3706af42SArnaud Ysmal 193*3706af42SArnaud Ysmal sc->npins = lbggpiocm_get_group_npins(device_get_parent(dev), dev); 194*3706af42SArnaud Ysmal sc->grpname = lbggpiocm_get_group_name(device_get_parent(dev), dev); 195*3706af42SArnaud Ysmal if (sc->npins <= 0) 196*3706af42SArnaud Ysmal return (ENXIO); 197*3706af42SArnaud Ysmal 198*3706af42SArnaud Ysmal desc[sizeof(desc)-2] = sc->grpname; 199*3706af42SArnaud Ysmal device_set_desc_copy(dev, desc); 200*3706af42SArnaud Ysmal return (BUS_PROBE_DEFAULT); 201*3706af42SArnaud Ysmal } 202*3706af42SArnaud Ysmal 203*3706af42SArnaud Ysmal static int 204*3706af42SArnaud Ysmal lbggpio_attach(device_t dev) 205*3706af42SArnaud Ysmal { 206*3706af42SArnaud Ysmal uint32_t i; 207*3706af42SArnaud Ysmal struct lbggpio_softc *sc; 208*3706af42SArnaud Ysmal 209*3706af42SArnaud Ysmal sc = device_get_softc(dev); 210*3706af42SArnaud Ysmal /* GPIO config */ 211*3706af42SArnaud Ysmal for (i = 0; i < sc->npins; ++i) { 212*3706af42SArnaud Ysmal sc->gpio_setup[i].gp_pin = i; 213*3706af42SArnaud Ysmal snprintf(sc->gpio_setup[i].gp_name, 214*3706af42SArnaud Ysmal sizeof(sc->gpio_setup[i].gp_name), 215*3706af42SArnaud Ysmal "GPIO %c%u", sc->grpname, i); 216*3706af42SArnaud Ysmal sc->gpio_setup[i].gp_caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT; 217*3706af42SArnaud Ysmal } 218*3706af42SArnaud Ysmal 219*3706af42SArnaud Ysmal /* support gpio */ 220*3706af42SArnaud Ysmal sc->sc_busdev = gpiobus_attach_bus(dev); 221*3706af42SArnaud Ysmal if (sc->sc_busdev == NULL) 222*3706af42SArnaud Ysmal return (ENXIO); 223*3706af42SArnaud Ysmal 224*3706af42SArnaud Ysmal return (0); 225*3706af42SArnaud Ysmal } 226*3706af42SArnaud Ysmal 227*3706af42SArnaud Ysmal static int 228*3706af42SArnaud Ysmal lbggpio_detach(device_t dev) 229*3706af42SArnaud Ysmal { 230*3706af42SArnaud Ysmal struct lbggpio_softc *sc; 231*3706af42SArnaud Ysmal 232*3706af42SArnaud Ysmal sc = device_get_softc(dev); 233*3706af42SArnaud Ysmal 234*3706af42SArnaud Ysmal if (sc->sc_busdev) 235*3706af42SArnaud Ysmal gpiobus_detach_bus(dev); 236*3706af42SArnaud Ysmal 237*3706af42SArnaud Ysmal return (0); 238*3706af42SArnaud Ysmal } 239*3706af42SArnaud Ysmal 240*3706af42SArnaud Ysmal static device_method_t lbggpio_methods[] = { 241*3706af42SArnaud Ysmal /* Device interface */ 242*3706af42SArnaud Ysmal DEVMETHOD(device_probe, lbggpio_probe), 243*3706af42SArnaud Ysmal DEVMETHOD(device_attach, lbggpio_attach), 244*3706af42SArnaud Ysmal DEVMETHOD(device_detach, lbggpio_detach), 245*3706af42SArnaud Ysmal 246*3706af42SArnaud Ysmal /* GPIO protocol */ 247*3706af42SArnaud Ysmal DEVMETHOD(gpio_get_bus, lbggpio_get_bus), 248*3706af42SArnaud Ysmal DEVMETHOD(gpio_pin_max, lbggpio_pin_max), 249*3706af42SArnaud Ysmal DEVMETHOD(gpio_pin_getcaps, lbggpio_pin_getcaps), 250*3706af42SArnaud Ysmal DEVMETHOD(gpio_pin_getflags, lbggpio_pin_getflags), 251*3706af42SArnaud Ysmal DEVMETHOD(gpio_pin_setflags, lbggpio_pin_setflags), 252*3706af42SArnaud Ysmal DEVMETHOD(gpio_pin_getname, lbggpio_pin_getname), 253*3706af42SArnaud Ysmal DEVMETHOD(gpio_pin_set, lbggpio_pin_set), 254*3706af42SArnaud Ysmal DEVMETHOD(gpio_pin_get, lbggpio_pin_get), 255*3706af42SArnaud Ysmal DEVMETHOD(gpio_pin_toggle, lbggpio_pin_toggle), 256*3706af42SArnaud Ysmal 257*3706af42SArnaud Ysmal DEVMETHOD_END 258*3706af42SArnaud Ysmal }; 259*3706af42SArnaud Ysmal 260*3706af42SArnaud Ysmal static driver_t lbggpio_driver = { 261*3706af42SArnaud Ysmal "gpio", 262*3706af42SArnaud Ysmal lbggpio_methods, 263*3706af42SArnaud Ysmal sizeof(struct lbggpio_softc) 264*3706af42SArnaud Ysmal }; 265*3706af42SArnaud Ysmal 266*3706af42SArnaud Ysmal static devclass_t lbggpio_devclass; 267*3706af42SArnaud Ysmal 268*3706af42SArnaud Ysmal DRIVER_MODULE(lbggpio, lbggpiocm, lbggpio_driver, lbggpio_devclass, NULL, NULL); 269*3706af42SArnaud Ysmal MODULE_DEPEND(lbggpio, gpiobus, 1, 1, 1); 270