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