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