1b47e5c5dSJessica Clarke /*- 2b47e5c5dSJessica Clarke * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3b47e5c5dSJessica Clarke * 4b47e5c5dSJessica Clarke * Copyright (c) 2021 Jessica Clarke <jrtc27@FreeBSD.org> 5b47e5c5dSJessica Clarke * 6b47e5c5dSJessica Clarke * Redistribution and use in source and binary forms, with or without 7b47e5c5dSJessica Clarke * modification, are permitted provided that the following conditions 8b47e5c5dSJessica Clarke * are met: 9b47e5c5dSJessica Clarke * 1. Redistributions of source code must retain the above copyright 10b47e5c5dSJessica Clarke * notice, this list of conditions and the following disclaimer. 11b47e5c5dSJessica Clarke * 2. Redistributions in binary form must reproduce the above copyright 12b47e5c5dSJessica Clarke * notice, this list of conditions and the following disclaimer in the 13b47e5c5dSJessica Clarke * documentation and/or other materials provided with the distribution. 14b47e5c5dSJessica Clarke * 15b47e5c5dSJessica Clarke * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16b47e5c5dSJessica Clarke * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17b47e5c5dSJessica Clarke * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18b47e5c5dSJessica Clarke * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19b47e5c5dSJessica Clarke * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20b47e5c5dSJessica Clarke * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21b47e5c5dSJessica Clarke * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22b47e5c5dSJessica Clarke * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23b47e5c5dSJessica Clarke * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24b47e5c5dSJessica Clarke * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25b47e5c5dSJessica Clarke * SUCH DAMAGE. 26b47e5c5dSJessica Clarke * 27b47e5c5dSJessica Clarke */ 28b47e5c5dSJessica Clarke 29b47e5c5dSJessica Clarke /* TODO: Provide interrupt controller interface */ 30b47e5c5dSJessica Clarke 31b47e5c5dSJessica Clarke #include <sys/cdefs.h> 32b47e5c5dSJessica Clarke __FBSDID("$FreeBSD$"); 33b47e5c5dSJessica Clarke 34b47e5c5dSJessica Clarke #include <sys/param.h> 35b47e5c5dSJessica Clarke #include <sys/systm.h> 36b47e5c5dSJessica Clarke #include <sys/bus.h> 37b47e5c5dSJessica Clarke #include <sys/kernel.h> 38b47e5c5dSJessica Clarke #include <sys/module.h> 39b47e5c5dSJessica Clarke #include <sys/rman.h> 40b47e5c5dSJessica Clarke #include <sys/lock.h> 41b47e5c5dSJessica Clarke #include <sys/mutex.h> 42b47e5c5dSJessica Clarke #include <sys/gpio.h> 43b47e5c5dSJessica Clarke 44b47e5c5dSJessica Clarke #include <dev/gpio/gpiobusvar.h> 45b47e5c5dSJessica Clarke #include <dev/ofw/ofw_bus.h> 46b47e5c5dSJessica Clarke #include <dev/ofw/ofw_bus_subr.h> 47b47e5c5dSJessica Clarke 48b47e5c5dSJessica Clarke #include <machine/bus.h> 49b47e5c5dSJessica Clarke 50b47e5c5dSJessica Clarke /* Registers are 32-bit so can only fit 32 pins */ 51b47e5c5dSJessica Clarke #define SFGPIO_MAX_PINS 32 52b47e5c5dSJessica Clarke 53b47e5c5dSJessica Clarke #define SFGPIO_DEFAULT_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT) 54b47e5c5dSJessica Clarke 55b47e5c5dSJessica Clarke #define SFGPIO_INPUT_VAL 0x0 56b47e5c5dSJessica Clarke #define SFGPIO_INPUT_EN 0x4 57b47e5c5dSJessica Clarke #define SFGPIO_OUTPUT_EN 0x8 58b47e5c5dSJessica Clarke #define SFGPIO_OUTPUT_VAL 0xc 59b47e5c5dSJessica Clarke #define SFGPIO_RISE_IE 0x18 60b47e5c5dSJessica Clarke #define SFGPIO_RISE_IP 0x1c 61b47e5c5dSJessica Clarke #define SFGPIO_FALL_IE 0x20 62b47e5c5dSJessica Clarke #define SFGPIO_FALL_IP 0x24 63b47e5c5dSJessica Clarke #define SFGPIO_HIGH_IE 0x28 64b47e5c5dSJessica Clarke #define SFGPIO_HIGH_IP 0x2c 65b47e5c5dSJessica Clarke #define SFGPIO_LOW_IE 0x30 66b47e5c5dSJessica Clarke #define SFGPIO_LOW_IP 0x34 67b47e5c5dSJessica Clarke 68b47e5c5dSJessica Clarke struct sfgpio_softc { 69b47e5c5dSJessica Clarke device_t dev; 70b47e5c5dSJessica Clarke device_t busdev; 71b47e5c5dSJessica Clarke struct mtx mtx; 72b47e5c5dSJessica Clarke struct resource *mem_res; 73b47e5c5dSJessica Clarke int mem_rid; 74b47e5c5dSJessica Clarke struct resource *irq_res; 75b47e5c5dSJessica Clarke int irq_rid; 76b47e5c5dSJessica Clarke int npins; 77b47e5c5dSJessica Clarke struct gpio_pin gpio_pins[SFGPIO_MAX_PINS]; 78b47e5c5dSJessica Clarke }; 79b47e5c5dSJessica Clarke 80b47e5c5dSJessica Clarke #define SFGPIO_LOCK(_sc) mtx_lock(&(_sc)->mtx) 81b47e5c5dSJessica Clarke #define SFGPIO_UNLOCK(_sc) mtx_unlock(&(_sc)->mtx) 82b47e5c5dSJessica Clarke 83b47e5c5dSJessica Clarke #define SFGPIO_READ(_sc, _off) \ 84b47e5c5dSJessica Clarke bus_read_4((_sc)->mem_res, (_off)) 85b47e5c5dSJessica Clarke #define SFGPIO_WRITE(_sc, _off, _val) \ 86b47e5c5dSJessica Clarke bus_write_4((_sc)->mem_res, (_off), (_val)) 87b47e5c5dSJessica Clarke 88b47e5c5dSJessica Clarke static struct ofw_compat_data compat_data[] = { 89b47e5c5dSJessica Clarke { "sifive,gpio0", 1 }, 90b47e5c5dSJessica Clarke { NULL, 0 }, 91b47e5c5dSJessica Clarke }; 92b47e5c5dSJessica Clarke 93b47e5c5dSJessica Clarke static int 94b47e5c5dSJessica Clarke sfgpio_probe(device_t dev) 95b47e5c5dSJessica Clarke { 96b47e5c5dSJessica Clarke if (!ofw_bus_status_okay(dev)) 97b47e5c5dSJessica Clarke return (ENXIO); 98b47e5c5dSJessica Clarke 99b47e5c5dSJessica Clarke if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) 100b47e5c5dSJessica Clarke return (ENXIO); 101b47e5c5dSJessica Clarke 102b47e5c5dSJessica Clarke device_set_desc(dev, "SiFive GPIO Controller"); 103b47e5c5dSJessica Clarke 104b47e5c5dSJessica Clarke return (BUS_PROBE_DEFAULT); 105b47e5c5dSJessica Clarke } 106b47e5c5dSJessica Clarke 107b47e5c5dSJessica Clarke static int 108b47e5c5dSJessica Clarke sfgpio_attach(device_t dev) 109b47e5c5dSJessica Clarke { 110b47e5c5dSJessica Clarke struct sfgpio_softc *sc; 111b47e5c5dSJessica Clarke phandle_t node; 112b47e5c5dSJessica Clarke int error, i; 113b47e5c5dSJessica Clarke pcell_t npins; 114b47e5c5dSJessica Clarke uint32_t input_en, output_en; 115b47e5c5dSJessica Clarke 116b47e5c5dSJessica Clarke sc = device_get_softc(dev); 117b47e5c5dSJessica Clarke sc->dev = dev; 118b47e5c5dSJessica Clarke 119b47e5c5dSJessica Clarke node = ofw_bus_get_node(dev); 120b47e5c5dSJessica Clarke 121b47e5c5dSJessica Clarke mtx_init(&sc->mtx, device_get_nameunit(sc->dev), NULL, MTX_DEF); 122b47e5c5dSJessica Clarke 123b47e5c5dSJessica Clarke sc->mem_rid = 0; 124b47e5c5dSJessica Clarke sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 125b47e5c5dSJessica Clarke &sc->mem_rid, RF_ACTIVE); 126b47e5c5dSJessica Clarke if (sc->mem_res == NULL) { 127b47e5c5dSJessica Clarke device_printf(dev, "Cannot allocate memory resource\n"); 128b47e5c5dSJessica Clarke error = ENXIO; 129b47e5c5dSJessica Clarke goto fail; 130b47e5c5dSJessica Clarke } 131b47e5c5dSJessica Clarke 132b47e5c5dSJessica Clarke if (OF_getencprop(node, "ngpios", &npins, sizeof(npins)) <= 0) { 133b47e5c5dSJessica Clarke /* Optional; defaults to 16 */ 134b47e5c5dSJessica Clarke npins = 16; 135b47e5c5dSJessica Clarke } else if (npins > SFGPIO_MAX_PINS) { 136b47e5c5dSJessica Clarke device_printf(dev, "Too many pins: %d\n", npins); 137b47e5c5dSJessica Clarke error = ENXIO; 138b47e5c5dSJessica Clarke goto fail; 139b47e5c5dSJessica Clarke } 140b47e5c5dSJessica Clarke sc->npins = npins; 141b47e5c5dSJessica Clarke 142b47e5c5dSJessica Clarke sc->irq_rid = 0; 143b47e5c5dSJessica Clarke sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid, 144b47e5c5dSJessica Clarke RF_ACTIVE); 145b47e5c5dSJessica Clarke if (sc->irq_res == NULL) { 146b47e5c5dSJessica Clarke device_printf(dev, "Cannot allocate IRQ resource\n"); 147b47e5c5dSJessica Clarke error = ENXIO; 148b47e5c5dSJessica Clarke goto fail; 149b47e5c5dSJessica Clarke } 150b47e5c5dSJessica Clarke 151b47e5c5dSJessica Clarke input_en = SFGPIO_READ(sc, SFGPIO_INPUT_EN); 152b47e5c5dSJessica Clarke output_en = SFGPIO_READ(sc, SFGPIO_OUTPUT_EN); 153b47e5c5dSJessica Clarke for (i = 0; i < sc->npins; ++i) { 154b47e5c5dSJessica Clarke sc->gpio_pins[i].gp_pin = i; 155b47e5c5dSJessica Clarke sc->gpio_pins[i].gp_caps = SFGPIO_DEFAULT_CAPS; 156b47e5c5dSJessica Clarke sc->gpio_pins[i].gp_flags = 157b47e5c5dSJessica Clarke ((input_en & (1u << i)) ? GPIO_PIN_INPUT : 0) | 158b47e5c5dSJessica Clarke ((output_en & (1u << i)) ? GPIO_PIN_OUTPUT : 0); 159b47e5c5dSJessica Clarke snprintf(sc->gpio_pins[i].gp_name, GPIOMAXNAME, "GPIO%d", i); 160b47e5c5dSJessica Clarke sc->gpio_pins[i].gp_name[GPIOMAXNAME - 1] = '\0'; 161b47e5c5dSJessica Clarke } 162b47e5c5dSJessica Clarke 163b47e5c5dSJessica Clarke sc->busdev = gpiobus_attach_bus(dev); 164b47e5c5dSJessica Clarke if (sc->busdev == NULL) { 165b47e5c5dSJessica Clarke device_printf(dev, "Cannot attach gpiobus\n"); 166b47e5c5dSJessica Clarke error = ENXIO; 167b47e5c5dSJessica Clarke goto fail; 168b47e5c5dSJessica Clarke } 169b47e5c5dSJessica Clarke 170b47e5c5dSJessica Clarke return (0); 171b47e5c5dSJessica Clarke 172b47e5c5dSJessica Clarke fail: 173b47e5c5dSJessica Clarke if (sc->busdev != NULL) 174b47e5c5dSJessica Clarke gpiobus_detach_bus(dev); 175b47e5c5dSJessica Clarke if (sc->irq_res != NULL) 176b47e5c5dSJessica Clarke bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, 177b47e5c5dSJessica Clarke sc->irq_res); 178b47e5c5dSJessica Clarke if (sc->mem_res != NULL) 179b47e5c5dSJessica Clarke bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, 180b47e5c5dSJessica Clarke sc->mem_res); 181b47e5c5dSJessica Clarke mtx_destroy(&sc->mtx); 182b47e5c5dSJessica Clarke return (error); 183b47e5c5dSJessica Clarke } 184b47e5c5dSJessica Clarke 185b47e5c5dSJessica Clarke static device_t 186b47e5c5dSJessica Clarke sfgpio_get_bus(device_t dev) 187b47e5c5dSJessica Clarke { 188b47e5c5dSJessica Clarke struct sfgpio_softc *sc; 189b47e5c5dSJessica Clarke 190b47e5c5dSJessica Clarke sc = device_get_softc(dev); 191b47e5c5dSJessica Clarke 192b47e5c5dSJessica Clarke return (sc->busdev); 193b47e5c5dSJessica Clarke } 194b47e5c5dSJessica Clarke 195b47e5c5dSJessica Clarke static int 196b47e5c5dSJessica Clarke sfgpio_pin_max(device_t dev, int *maxpin) 197b47e5c5dSJessica Clarke { 198b47e5c5dSJessica Clarke struct sfgpio_softc *sc; 199b47e5c5dSJessica Clarke 200b47e5c5dSJessica Clarke sc = device_get_softc(dev); 201b47e5c5dSJessica Clarke 202b47e5c5dSJessica Clarke *maxpin = sc->npins - 1; 203b47e5c5dSJessica Clarke 204b47e5c5dSJessica Clarke return (0); 205b47e5c5dSJessica Clarke } 206b47e5c5dSJessica Clarke 207b47e5c5dSJessica Clarke static int 208b47e5c5dSJessica Clarke sfgpio_pin_set(device_t dev, uint32_t pin, unsigned int val) 209b47e5c5dSJessica Clarke { 210b47e5c5dSJessica Clarke struct sfgpio_softc *sc; 211b47e5c5dSJessica Clarke uint32_t reg; 212b47e5c5dSJessica Clarke 213b47e5c5dSJessica Clarke sc = device_get_softc(dev); 214b47e5c5dSJessica Clarke 215b47e5c5dSJessica Clarke if (pin >= sc->npins) 216b47e5c5dSJessica Clarke return (EINVAL); 217b47e5c5dSJessica Clarke 218b47e5c5dSJessica Clarke SFGPIO_LOCK(sc); 219b47e5c5dSJessica Clarke reg = SFGPIO_READ(sc, SFGPIO_OUTPUT_VAL); 220b47e5c5dSJessica Clarke if (val) 221b47e5c5dSJessica Clarke reg |= (1u << pin); 222b47e5c5dSJessica Clarke else 223b47e5c5dSJessica Clarke reg &= ~(1u << pin); 224b47e5c5dSJessica Clarke SFGPIO_WRITE(sc, SFGPIO_OUTPUT_VAL, reg); 225b47e5c5dSJessica Clarke SFGPIO_UNLOCK(sc); 226b47e5c5dSJessica Clarke 227b47e5c5dSJessica Clarke return (0); 228b47e5c5dSJessica Clarke } 229b47e5c5dSJessica Clarke 230b47e5c5dSJessica Clarke static int 231b47e5c5dSJessica Clarke sfgpio_pin_get(device_t dev, uint32_t pin, unsigned int *val) 232b47e5c5dSJessica Clarke { 233b47e5c5dSJessica Clarke struct sfgpio_softc *sc; 234b47e5c5dSJessica Clarke uint32_t reg; 235b47e5c5dSJessica Clarke 236b47e5c5dSJessica Clarke sc = device_get_softc(dev); 237b47e5c5dSJessica Clarke 238b47e5c5dSJessica Clarke if (pin >= sc->npins) 239b47e5c5dSJessica Clarke return (EINVAL); 240b47e5c5dSJessica Clarke 241b47e5c5dSJessica Clarke SFGPIO_LOCK(sc); 242b47e5c5dSJessica Clarke if (sc->gpio_pins[pin].gp_flags & GPIO_PIN_OUTPUT) 243b47e5c5dSJessica Clarke reg = SFGPIO_READ(sc, SFGPIO_OUTPUT_VAL); 244b47e5c5dSJessica Clarke else 245b47e5c5dSJessica Clarke reg = SFGPIO_READ(sc, SFGPIO_INPUT_VAL); 246b47e5c5dSJessica Clarke *val = (reg & (1u << pin)) ? 1 : 0; 247b47e5c5dSJessica Clarke SFGPIO_UNLOCK(sc); 248b47e5c5dSJessica Clarke 249b47e5c5dSJessica Clarke return (0); 250b47e5c5dSJessica Clarke } 251b47e5c5dSJessica Clarke 252b47e5c5dSJessica Clarke static int 253b47e5c5dSJessica Clarke sfgpio_pin_toggle(device_t dev, uint32_t pin) 254b47e5c5dSJessica Clarke { 255b47e5c5dSJessica Clarke struct sfgpio_softc *sc; 256b47e5c5dSJessica Clarke uint32_t reg; 257b47e5c5dSJessica Clarke 258b47e5c5dSJessica Clarke sc = device_get_softc(dev); 259b47e5c5dSJessica Clarke 260b47e5c5dSJessica Clarke if (pin >= sc->npins) 261b47e5c5dSJessica Clarke return (EINVAL); 262b47e5c5dSJessica Clarke 263b47e5c5dSJessica Clarke SFGPIO_LOCK(sc); 264b47e5c5dSJessica Clarke reg = SFGPIO_READ(sc, SFGPIO_OUTPUT_VAL); 265b47e5c5dSJessica Clarke reg ^= (1u << pin); 266b47e5c5dSJessica Clarke SFGPIO_WRITE(sc, SFGPIO_OUTPUT_VAL, reg); 267b47e5c5dSJessica Clarke SFGPIO_UNLOCK(sc); 268b47e5c5dSJessica Clarke 269b47e5c5dSJessica Clarke return (0); 270b47e5c5dSJessica Clarke } 271b47e5c5dSJessica Clarke 272b47e5c5dSJessica Clarke static int 273b47e5c5dSJessica Clarke sfgpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) 274b47e5c5dSJessica Clarke { 275b47e5c5dSJessica Clarke struct sfgpio_softc *sc; 276b47e5c5dSJessica Clarke 277b47e5c5dSJessica Clarke sc = device_get_softc(dev); 278b47e5c5dSJessica Clarke 279b47e5c5dSJessica Clarke if (pin >= sc->npins) 280b47e5c5dSJessica Clarke return (EINVAL); 281b47e5c5dSJessica Clarke 282b47e5c5dSJessica Clarke SFGPIO_LOCK(sc); 283b47e5c5dSJessica Clarke *caps = sc->gpio_pins[pin].gp_caps; 284b47e5c5dSJessica Clarke SFGPIO_UNLOCK(sc); 285b47e5c5dSJessica Clarke 286b47e5c5dSJessica Clarke return (0); 287b47e5c5dSJessica Clarke } 288b47e5c5dSJessica Clarke 289b47e5c5dSJessica Clarke static int 290b47e5c5dSJessica Clarke sfgpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) 291b47e5c5dSJessica Clarke { 292b47e5c5dSJessica Clarke struct sfgpio_softc *sc; 293b47e5c5dSJessica Clarke 294b47e5c5dSJessica Clarke sc = device_get_softc(dev); 295b47e5c5dSJessica Clarke 296b47e5c5dSJessica Clarke if (pin >= sc->npins) 297b47e5c5dSJessica Clarke return (EINVAL); 298b47e5c5dSJessica Clarke 299b47e5c5dSJessica Clarke SFGPIO_LOCK(sc); 300b47e5c5dSJessica Clarke *flags = sc->gpio_pins[pin].gp_flags; 301b47e5c5dSJessica Clarke SFGPIO_UNLOCK(sc); 302b47e5c5dSJessica Clarke 303b47e5c5dSJessica Clarke return (0); 304b47e5c5dSJessica Clarke } 305b47e5c5dSJessica Clarke 306b47e5c5dSJessica Clarke static int 307b47e5c5dSJessica Clarke sfgpio_pin_getname(device_t dev, uint32_t pin, char *name) 308b47e5c5dSJessica Clarke { 309b47e5c5dSJessica Clarke struct sfgpio_softc *sc; 310b47e5c5dSJessica Clarke 311b47e5c5dSJessica Clarke sc = device_get_softc(dev); 312b47e5c5dSJessica Clarke 313b47e5c5dSJessica Clarke if (pin >= sc->npins) 314b47e5c5dSJessica Clarke return (EINVAL); 315b47e5c5dSJessica Clarke 316b47e5c5dSJessica Clarke SFGPIO_LOCK(sc); 317b47e5c5dSJessica Clarke memcpy(name, sc->gpio_pins[pin].gp_name, GPIOMAXNAME); 318b47e5c5dSJessica Clarke SFGPIO_UNLOCK(sc); 319b47e5c5dSJessica Clarke 320b47e5c5dSJessica Clarke return (0); 321b47e5c5dSJessica Clarke } 322b47e5c5dSJessica Clarke 323b47e5c5dSJessica Clarke static int 324b47e5c5dSJessica Clarke sfgpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) 325b47e5c5dSJessica Clarke { 326b47e5c5dSJessica Clarke struct sfgpio_softc *sc; 327b47e5c5dSJessica Clarke uint32_t reg; 328b47e5c5dSJessica Clarke 329b47e5c5dSJessica Clarke sc = device_get_softc(dev); 330b47e5c5dSJessica Clarke 331b47e5c5dSJessica Clarke if (pin >= sc->npins) 332b47e5c5dSJessica Clarke return (EINVAL); 333b47e5c5dSJessica Clarke 334b47e5c5dSJessica Clarke SFGPIO_LOCK(sc); 335b47e5c5dSJessica Clarke 336b47e5c5dSJessica Clarke reg = SFGPIO_READ(sc, SFGPIO_INPUT_EN); 337b47e5c5dSJessica Clarke if (flags & GPIO_PIN_INPUT) { 338b47e5c5dSJessica Clarke reg |= (1u << pin); 339b47e5c5dSJessica Clarke sc->gpio_pins[pin].gp_flags |= GPIO_PIN_INPUT; 340b47e5c5dSJessica Clarke } else { 341b47e5c5dSJessica Clarke reg &= ~(1u << pin); 342b47e5c5dSJessica Clarke sc->gpio_pins[pin].gp_flags &= ~GPIO_PIN_INPUT; 343b47e5c5dSJessica Clarke } 344b47e5c5dSJessica Clarke SFGPIO_WRITE(sc, SFGPIO_INPUT_EN, reg); 345b47e5c5dSJessica Clarke 346b47e5c5dSJessica Clarke reg = SFGPIO_READ(sc, SFGPIO_OUTPUT_EN); 347b47e5c5dSJessica Clarke if (flags & GPIO_PIN_OUTPUT) { 348b47e5c5dSJessica Clarke reg |= (1u << pin); 349b47e5c5dSJessica Clarke sc->gpio_pins[pin].gp_flags |= GPIO_PIN_OUTPUT; 350b47e5c5dSJessica Clarke } else { 351b47e5c5dSJessica Clarke reg &= ~(1u << pin); 352b47e5c5dSJessica Clarke sc->gpio_pins[pin].gp_flags &= ~GPIO_PIN_OUTPUT; 353b47e5c5dSJessica Clarke } 354b47e5c5dSJessica Clarke SFGPIO_WRITE(sc, SFGPIO_OUTPUT_EN, reg); 355b47e5c5dSJessica Clarke 356b47e5c5dSJessica Clarke SFGPIO_UNLOCK(sc); 357b47e5c5dSJessica Clarke 358b47e5c5dSJessica Clarke return (0); 359b47e5c5dSJessica Clarke } 360b47e5c5dSJessica Clarke 361b47e5c5dSJessica Clarke static int 362b47e5c5dSJessica Clarke sfgpio_pin_access_32(device_t dev, uint32_t first_pin, uint32_t clear_pins, 363b47e5c5dSJessica Clarke uint32_t change_pins, uint32_t *orig_pins) 364b47e5c5dSJessica Clarke { 365b47e5c5dSJessica Clarke struct sfgpio_softc *sc; 366b47e5c5dSJessica Clarke uint32_t reg; 367b47e5c5dSJessica Clarke 368b47e5c5dSJessica Clarke if (first_pin != 0) 369b47e5c5dSJessica Clarke return (EINVAL); 370b47e5c5dSJessica Clarke 371b47e5c5dSJessica Clarke sc = device_get_softc(dev); 372b47e5c5dSJessica Clarke 373b47e5c5dSJessica Clarke SFGPIO_LOCK(sc); 374b47e5c5dSJessica Clarke 375b47e5c5dSJessica Clarke reg = SFGPIO_READ(sc, SFGPIO_OUTPUT_VAL); 376b47e5c5dSJessica Clarke 377b47e5c5dSJessica Clarke if (orig_pins != NULL) 378b47e5c5dSJessica Clarke /* Only input_val is implicitly masked by input_en */ 379b47e5c5dSJessica Clarke *orig_pins = SFGPIO_READ(sc, SFGPIO_INPUT_VAL) | 380b47e5c5dSJessica Clarke (reg & SFGPIO_READ(sc, SFGPIO_OUTPUT_EN)); 381b47e5c5dSJessica Clarke 382b47e5c5dSJessica Clarke if ((clear_pins | change_pins) != 0) 383b47e5c5dSJessica Clarke SFGPIO_WRITE(sc, SFGPIO_OUTPUT_VAL, 384b47e5c5dSJessica Clarke (reg & ~clear_pins) ^ change_pins); 385b47e5c5dSJessica Clarke 386b47e5c5dSJessica Clarke SFGPIO_UNLOCK(sc); 387b47e5c5dSJessica Clarke 388b47e5c5dSJessica Clarke return (0); 389b47e5c5dSJessica Clarke } 390b47e5c5dSJessica Clarke 391b47e5c5dSJessica Clarke static int 392b47e5c5dSJessica Clarke sfgpio_pin_config_32(device_t dev, uint32_t first_pin, uint32_t num_pins, 393b47e5c5dSJessica Clarke uint32_t *pin_flags) 394b47e5c5dSJessica Clarke { 395b47e5c5dSJessica Clarke struct sfgpio_softc *sc; 396b47e5c5dSJessica Clarke uint32_t ireg, oreg; 397b47e5c5dSJessica Clarke int i; 398b47e5c5dSJessica Clarke 399b47e5c5dSJessica Clarke sc = device_get_softc(dev); 400b47e5c5dSJessica Clarke 401b47e5c5dSJessica Clarke if (first_pin != 0 || num_pins > sc->npins) 402b47e5c5dSJessica Clarke return (EINVAL); 403b47e5c5dSJessica Clarke 404b47e5c5dSJessica Clarke SFGPIO_LOCK(sc); 405b47e5c5dSJessica Clarke 406b47e5c5dSJessica Clarke ireg = SFGPIO_READ(sc, SFGPIO_INPUT_EN); 407b47e5c5dSJessica Clarke oreg = SFGPIO_READ(sc, SFGPIO_OUTPUT_EN); 408b47e5c5dSJessica Clarke for (i = 0; i < num_pins; ++i) { 409b47e5c5dSJessica Clarke if (pin_flags[i] & GPIO_PIN_INPUT) { 410b47e5c5dSJessica Clarke ireg |= (1u << i); 411b47e5c5dSJessica Clarke oreg &= ~(1u << i); 412b47e5c5dSJessica Clarke sc->gpio_pins[i].gp_flags |= GPIO_PIN_INPUT; 413b47e5c5dSJessica Clarke sc->gpio_pins[i].gp_flags &= ~GPIO_PIN_OUTPUT; 414b47e5c5dSJessica Clarke } else if (pin_flags[i] & GPIO_PIN_OUTPUT) { 415b47e5c5dSJessica Clarke ireg &= ~(1u << i); 416b47e5c5dSJessica Clarke oreg |= (1u << i); 417b47e5c5dSJessica Clarke sc->gpio_pins[i].gp_flags &= ~GPIO_PIN_INPUT; 418b47e5c5dSJessica Clarke sc->gpio_pins[i].gp_flags |= GPIO_PIN_OUTPUT; 419b47e5c5dSJessica Clarke } 420b47e5c5dSJessica Clarke } 421b47e5c5dSJessica Clarke SFGPIO_WRITE(sc, SFGPIO_INPUT_EN, ireg); 422b47e5c5dSJessica Clarke SFGPIO_WRITE(sc, SFGPIO_OUTPUT_EN, oreg); 423b47e5c5dSJessica Clarke 424b47e5c5dSJessica Clarke SFGPIO_UNLOCK(sc); 425b47e5c5dSJessica Clarke 426b47e5c5dSJessica Clarke return (0); 427b47e5c5dSJessica Clarke } 428b47e5c5dSJessica Clarke 429b47e5c5dSJessica Clarke static phandle_t 430b47e5c5dSJessica Clarke sfgpio_get_node(device_t bus, device_t dev) 431b47e5c5dSJessica Clarke { 432b47e5c5dSJessica Clarke return (ofw_bus_get_node(bus)); 433b47e5c5dSJessica Clarke } 434b47e5c5dSJessica Clarke 435b47e5c5dSJessica Clarke static device_method_t sfgpio_methods[] = { 436b47e5c5dSJessica Clarke /* Device interface */ 437b47e5c5dSJessica Clarke DEVMETHOD(device_probe, sfgpio_probe), 438b47e5c5dSJessica Clarke DEVMETHOD(device_attach, sfgpio_attach), 439b47e5c5dSJessica Clarke 440b47e5c5dSJessica Clarke /* GPIO protocol */ 441b47e5c5dSJessica Clarke DEVMETHOD(gpio_get_bus, sfgpio_get_bus), 442b47e5c5dSJessica Clarke DEVMETHOD(gpio_pin_max, sfgpio_pin_max), 443b47e5c5dSJessica Clarke DEVMETHOD(gpio_pin_set, sfgpio_pin_set), 444b47e5c5dSJessica Clarke DEVMETHOD(gpio_pin_get, sfgpio_pin_get), 445b47e5c5dSJessica Clarke DEVMETHOD(gpio_pin_toggle, sfgpio_pin_toggle), 446b47e5c5dSJessica Clarke DEVMETHOD(gpio_pin_getcaps, sfgpio_pin_getcaps), 447b47e5c5dSJessica Clarke DEVMETHOD(gpio_pin_getflags, sfgpio_pin_getflags), 448b47e5c5dSJessica Clarke DEVMETHOD(gpio_pin_getname, sfgpio_pin_getname), 449b47e5c5dSJessica Clarke DEVMETHOD(gpio_pin_setflags, sfgpio_pin_setflags), 450b47e5c5dSJessica Clarke DEVMETHOD(gpio_pin_access_32, sfgpio_pin_access_32), 451b47e5c5dSJessica Clarke DEVMETHOD(gpio_pin_config_32, sfgpio_pin_config_32), 452b47e5c5dSJessica Clarke 453b47e5c5dSJessica Clarke /* ofw_bus interface */ 454b47e5c5dSJessica Clarke DEVMETHOD(ofw_bus_get_node, sfgpio_get_node), 455b47e5c5dSJessica Clarke 456b47e5c5dSJessica Clarke DEVMETHOD_END 457b47e5c5dSJessica Clarke }; 458b47e5c5dSJessica Clarke 459b47e5c5dSJessica Clarke DEFINE_CLASS_0(gpio, sfgpio_driver, sfgpio_methods, 460b47e5c5dSJessica Clarke sizeof(struct sfgpio_softc)); 461*bb32809bSJohn Baldwin EARLY_DRIVER_MODULE(gpio, simplebus, sfgpio_driver, 0, 0, 462b47e5c5dSJessica Clarke BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE); 463b47e5c5dSJessica Clarke MODULE_DEPEND(sfgpio, gpiobus, 1, 1, 1); 464