1213239Sgonzo/*- 2213239Sgonzo * Copyright (c) 2009, Oleksandr Tymoshenko <gonzo@FreeBSD.org> 3213239Sgonzo * Copyright (c) 2009, Luiz Otavio O Souza. 4213239Sgonzo * All rights reserved. 5213239Sgonzo * 6213239Sgonzo * Redistribution and use in source and binary forms, with or without 7213239Sgonzo * modification, are permitted provided that the following conditions 8213239Sgonzo * are met: 9213239Sgonzo * 1. Redistributions of source code must retain the above copyright 10213239Sgonzo * notice unmodified, this list of conditions, and the following 11213239Sgonzo * disclaimer. 12213239Sgonzo * 2. Redistributions in binary form must reproduce the above copyright 13213239Sgonzo * notice, this list of conditions and the following disclaimer in the 14213239Sgonzo * documentation and/or other materials provided with the distribution. 15213239Sgonzo * 16213239Sgonzo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17213239Sgonzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18213239Sgonzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19213239Sgonzo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20213239Sgonzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21213239Sgonzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22213239Sgonzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23213239Sgonzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24213239Sgonzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25213239Sgonzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26213239Sgonzo * SUCH DAMAGE. 27213239Sgonzo */ 28213239Sgonzo 29213239Sgonzo/* 30213239Sgonzo * GPIO driver for AR71xx 31213239Sgonzo */ 32213239Sgonzo 33213239Sgonzo#include <sys/cdefs.h> 34213239Sgonzo__FBSDID("$FreeBSD: releng/10.3/sys/mips/atheros/ar71xx_gpio.c 278786 2015-02-14 21:16:19Z loos $"); 35213239Sgonzo 36213239Sgonzo#include <sys/param.h> 37213239Sgonzo#include <sys/systm.h> 38213239Sgonzo#include <sys/bus.h> 39213239Sgonzo 40213239Sgonzo#include <sys/kernel.h> 41213239Sgonzo#include <sys/module.h> 42213239Sgonzo#include <sys/rman.h> 43213239Sgonzo#include <sys/lock.h> 44255335Sloos#include <sys/malloc.h> 45213239Sgonzo#include <sys/mutex.h> 46213239Sgonzo#include <sys/gpio.h> 47213239Sgonzo 48213239Sgonzo#include <machine/bus.h> 49213239Sgonzo#include <machine/resource.h> 50213239Sgonzo#include <mips/atheros/ar71xxreg.h> 51221518Sadrian#include <mips/atheros/ar71xx_setup.h> 52213239Sgonzo#include <mips/atheros/ar71xx_gpiovar.h> 53250165Sadrian#include <mips/atheros/ar933xreg.h> 54253510Sadrian#include <mips/atheros/ar934xreg.h> 55213239Sgonzo 56213239Sgonzo#include "gpio_if.h" 57213239Sgonzo 58213239Sgonzo#define DEFAULT_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT) 59213239Sgonzo 60213239Sgonzo/* 61213239Sgonzo * Helpers 62213239Sgonzo */ 63213239Sgonzostatic void ar71xx_gpio_function_enable(struct ar71xx_gpio_softc *sc, 64213239Sgonzo uint32_t mask); 65213239Sgonzostatic void ar71xx_gpio_function_disable(struct ar71xx_gpio_softc *sc, 66213239Sgonzo uint32_t mask); 67213239Sgonzostatic void ar71xx_gpio_pin_configure(struct ar71xx_gpio_softc *sc, 68213239Sgonzo struct gpio_pin *pin, uint32_t flags); 69213239Sgonzo 70213239Sgonzo/* 71213239Sgonzo * Driver stuff 72213239Sgonzo */ 73213239Sgonzostatic int ar71xx_gpio_probe(device_t dev); 74213239Sgonzostatic int ar71xx_gpio_attach(device_t dev); 75213239Sgonzostatic int ar71xx_gpio_detach(device_t dev); 76213239Sgonzostatic int ar71xx_gpio_filter(void *arg); 77213239Sgonzostatic void ar71xx_gpio_intr(void *arg); 78213239Sgonzo 79213239Sgonzo/* 80213239Sgonzo * GPIO interface 81213239Sgonzo */ 82213239Sgonzostatic int ar71xx_gpio_pin_max(device_t dev, int *maxpin); 83213239Sgonzostatic int ar71xx_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps); 84213239Sgonzostatic int ar71xx_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t 85213239Sgonzo *flags); 86213239Sgonzostatic int ar71xx_gpio_pin_getname(device_t dev, uint32_t pin, char *name); 87213239Sgonzostatic int ar71xx_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags); 88213239Sgonzostatic int ar71xx_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value); 89213239Sgonzostatic int ar71xx_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val); 90213239Sgonzostatic int ar71xx_gpio_pin_toggle(device_t dev, uint32_t pin); 91213239Sgonzo 92213239Sgonzostatic void 93213239Sgonzoar71xx_gpio_function_enable(struct ar71xx_gpio_softc *sc, uint32_t mask) 94213239Sgonzo{ 95253510Sadrian if (ar71xx_soc == AR71XX_SOC_AR9341 || 96253510Sadrian ar71xx_soc == AR71XX_SOC_AR9342 || 97253510Sadrian ar71xx_soc == AR71XX_SOC_AR9344) 98253510Sadrian GPIO_SET_BITS(sc, AR934X_GPIO_REG_FUNC, mask); 99253510Sadrian else 100253510Sadrian GPIO_SET_BITS(sc, AR71XX_GPIO_FUNCTION, mask); 101213239Sgonzo} 102213239Sgonzo 103213239Sgonzostatic void 104213239Sgonzoar71xx_gpio_function_disable(struct ar71xx_gpio_softc *sc, uint32_t mask) 105213239Sgonzo{ 106253510Sadrian if (ar71xx_soc == AR71XX_SOC_AR9341 || 107253510Sadrian ar71xx_soc == AR71XX_SOC_AR9342 || 108253510Sadrian ar71xx_soc == AR71XX_SOC_AR9344) 109253510Sadrian GPIO_CLEAR_BITS(sc, AR934X_GPIO_REG_FUNC, mask); 110253510Sadrian else 111253510Sadrian GPIO_CLEAR_BITS(sc, AR71XX_GPIO_FUNCTION, mask); 112213239Sgonzo} 113213239Sgonzo 114213239Sgonzostatic void 115213239Sgonzoar71xx_gpio_pin_configure(struct ar71xx_gpio_softc *sc, struct gpio_pin *pin, 116213239Sgonzo unsigned int flags) 117213239Sgonzo{ 118213239Sgonzo uint32_t mask; 119213239Sgonzo 120213239Sgonzo mask = 1 << pin->gp_pin; 121213239Sgonzo 122213239Sgonzo /* 123213239Sgonzo * Manage input/output 124213239Sgonzo */ 125213239Sgonzo if (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) { 126213239Sgonzo pin->gp_flags &= ~(GPIO_PIN_INPUT|GPIO_PIN_OUTPUT); 127213239Sgonzo if (flags & GPIO_PIN_OUTPUT) { 128213239Sgonzo pin->gp_flags |= GPIO_PIN_OUTPUT; 129213239Sgonzo GPIO_SET_BITS(sc, AR71XX_GPIO_OE, mask); 130213239Sgonzo } 131213239Sgonzo else { 132213239Sgonzo pin->gp_flags |= GPIO_PIN_INPUT; 133213239Sgonzo GPIO_CLEAR_BITS(sc, AR71XX_GPIO_OE, mask); 134213239Sgonzo } 135213239Sgonzo } 136213239Sgonzo} 137213239Sgonzo 138213239Sgonzostatic int 139213239Sgonzoar71xx_gpio_pin_max(device_t dev, int *maxpin) 140213239Sgonzo{ 141213239Sgonzo 142221518Sadrian switch (ar71xx_soc) { 143221518Sadrian case AR71XX_SOC_AR9130: 144221518Sadrian case AR71XX_SOC_AR9132: 145221518Sadrian *maxpin = AR91XX_GPIO_PINS - 1; 146221518Sadrian break; 147221518Sadrian case AR71XX_SOC_AR7240: 148221518Sadrian case AR71XX_SOC_AR7241: 149221518Sadrian case AR71XX_SOC_AR7242: 150221518Sadrian *maxpin = AR724X_GPIO_PINS - 1; 151221518Sadrian break; 152250165Sadrian case AR71XX_SOC_AR9330: 153250165Sadrian case AR71XX_SOC_AR9331: 154250165Sadrian *maxpin = AR933X_GPIO_COUNT - 1; 155250165Sadrian break; 156253510Sadrian case AR71XX_SOC_AR9341: 157253510Sadrian case AR71XX_SOC_AR9342: 158253510Sadrian case AR71XX_SOC_AR9344: 159253510Sadrian *maxpin = AR934X_GPIO_COUNT - 1; 160254234Sadrian break; 161221518Sadrian default: 162221518Sadrian *maxpin = AR71XX_GPIO_PINS - 1; 163221518Sadrian } 164213239Sgonzo return (0); 165213239Sgonzo} 166213239Sgonzo 167213239Sgonzostatic int 168213239Sgonzoar71xx_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) 169213239Sgonzo{ 170213239Sgonzo struct ar71xx_gpio_softc *sc = device_get_softc(dev); 171213239Sgonzo int i; 172213239Sgonzo 173213239Sgonzo for (i = 0; i < sc->gpio_npins; i++) { 174213239Sgonzo if (sc->gpio_pins[i].gp_pin == pin) 175213239Sgonzo break; 176213239Sgonzo } 177213239Sgonzo 178213239Sgonzo if (i >= sc->gpio_npins) 179213239Sgonzo return (EINVAL); 180213239Sgonzo 181213239Sgonzo GPIO_LOCK(sc); 182213239Sgonzo *caps = sc->gpio_pins[i].gp_caps; 183213239Sgonzo GPIO_UNLOCK(sc); 184213239Sgonzo 185213239Sgonzo return (0); 186213239Sgonzo} 187213239Sgonzo 188213239Sgonzostatic int 189213239Sgonzoar71xx_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) 190213239Sgonzo{ 191213239Sgonzo struct ar71xx_gpio_softc *sc = device_get_softc(dev); 192213239Sgonzo int i; 193213239Sgonzo 194213239Sgonzo for (i = 0; i < sc->gpio_npins; i++) { 195213239Sgonzo if (sc->gpio_pins[i].gp_pin == pin) 196213239Sgonzo break; 197213239Sgonzo } 198213239Sgonzo 199213239Sgonzo if (i >= sc->gpio_npins) 200213239Sgonzo return (EINVAL); 201213239Sgonzo 202213239Sgonzo GPIO_LOCK(sc); 203213239Sgonzo *flags = sc->gpio_pins[i].gp_flags; 204213239Sgonzo GPIO_UNLOCK(sc); 205213239Sgonzo 206213239Sgonzo return (0); 207213239Sgonzo} 208213239Sgonzo 209213239Sgonzostatic int 210213239Sgonzoar71xx_gpio_pin_getname(device_t dev, uint32_t pin, char *name) 211213239Sgonzo{ 212213239Sgonzo struct ar71xx_gpio_softc *sc = device_get_softc(dev); 213213239Sgonzo int i; 214213239Sgonzo 215213239Sgonzo for (i = 0; i < sc->gpio_npins; i++) { 216213239Sgonzo if (sc->gpio_pins[i].gp_pin == pin) 217213239Sgonzo break; 218213239Sgonzo } 219213239Sgonzo 220213239Sgonzo if (i >= sc->gpio_npins) 221213239Sgonzo return (EINVAL); 222213239Sgonzo 223213239Sgonzo GPIO_LOCK(sc); 224213239Sgonzo memcpy(name, sc->gpio_pins[i].gp_name, GPIOMAXNAME); 225213239Sgonzo GPIO_UNLOCK(sc); 226213239Sgonzo 227213239Sgonzo return (0); 228213239Sgonzo} 229213239Sgonzo 230213239Sgonzostatic int 231213239Sgonzoar71xx_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) 232213239Sgonzo{ 233213239Sgonzo int i; 234213239Sgonzo struct ar71xx_gpio_softc *sc = device_get_softc(dev); 235213239Sgonzo 236213239Sgonzo for (i = 0; i < sc->gpio_npins; i++) { 237213239Sgonzo if (sc->gpio_pins[i].gp_pin == pin) 238213239Sgonzo break; 239213239Sgonzo } 240213239Sgonzo 241213239Sgonzo if (i >= sc->gpio_npins) 242213239Sgonzo return (EINVAL); 243213239Sgonzo 244278786Sloos ar71xx_gpio_pin_configure(sc, &sc->gpio_pins[i], flags); 245213239Sgonzo 246213239Sgonzo return (0); 247213239Sgonzo} 248213239Sgonzo 249213239Sgonzostatic int 250213239Sgonzoar71xx_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value) 251213239Sgonzo{ 252213239Sgonzo struct ar71xx_gpio_softc *sc = device_get_softc(dev); 253213239Sgonzo int i; 254213239Sgonzo 255213239Sgonzo for (i = 0; i < sc->gpio_npins; i++) { 256213239Sgonzo if (sc->gpio_pins[i].gp_pin == pin) 257213239Sgonzo break; 258213239Sgonzo } 259213239Sgonzo 260213239Sgonzo if (i >= sc->gpio_npins) 261213239Sgonzo return (EINVAL); 262213239Sgonzo 263213239Sgonzo if (value) 264213239Sgonzo GPIO_WRITE(sc, AR71XX_GPIO_SET, (1 << pin)); 265213239Sgonzo else 266213239Sgonzo GPIO_WRITE(sc, AR71XX_GPIO_CLEAR, (1 << pin)); 267213239Sgonzo 268213239Sgonzo return (0); 269213239Sgonzo} 270213239Sgonzo 271213239Sgonzostatic int 272213239Sgonzoar71xx_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val) 273213239Sgonzo{ 274213239Sgonzo struct ar71xx_gpio_softc *sc = device_get_softc(dev); 275213239Sgonzo int i; 276213239Sgonzo 277213239Sgonzo for (i = 0; i < sc->gpio_npins; i++) { 278213239Sgonzo if (sc->gpio_pins[i].gp_pin == pin) 279213239Sgonzo break; 280213239Sgonzo } 281213239Sgonzo 282213239Sgonzo if (i >= sc->gpio_npins) 283213239Sgonzo return (EINVAL); 284213239Sgonzo 285213239Sgonzo *val = (GPIO_READ(sc, AR71XX_GPIO_IN) & (1 << pin)) ? 1 : 0; 286213239Sgonzo 287213239Sgonzo return (0); 288213239Sgonzo} 289213239Sgonzo 290213239Sgonzostatic int 291213239Sgonzoar71xx_gpio_pin_toggle(device_t dev, uint32_t pin) 292213239Sgonzo{ 293213239Sgonzo int res, i; 294213239Sgonzo struct ar71xx_gpio_softc *sc = device_get_softc(dev); 295213239Sgonzo 296213239Sgonzo for (i = 0; i < sc->gpio_npins; i++) { 297213239Sgonzo if (sc->gpio_pins[i].gp_pin == pin) 298213239Sgonzo break; 299213239Sgonzo } 300213239Sgonzo 301213239Sgonzo if (i >= sc->gpio_npins) 302213239Sgonzo return (EINVAL); 303213239Sgonzo 304213239Sgonzo res = (GPIO_READ(sc, AR71XX_GPIO_IN) & (1 << pin)) ? 1 : 0; 305213239Sgonzo if (res) 306213239Sgonzo GPIO_WRITE(sc, AR71XX_GPIO_CLEAR, (1 << pin)); 307213239Sgonzo else 308213239Sgonzo GPIO_WRITE(sc, AR71XX_GPIO_SET, (1 << pin)); 309213239Sgonzo 310213239Sgonzo return (0); 311213239Sgonzo} 312213239Sgonzo 313213239Sgonzostatic int 314213239Sgonzoar71xx_gpio_filter(void *arg) 315213239Sgonzo{ 316213239Sgonzo 317213239Sgonzo /* TODO: something useful */ 318213239Sgonzo return (FILTER_STRAY); 319213239Sgonzo} 320213239Sgonzo 321213239Sgonzo 322213239Sgonzo 323213239Sgonzostatic void 324213239Sgonzoar71xx_gpio_intr(void *arg) 325213239Sgonzo{ 326213239Sgonzo struct ar71xx_gpio_softc *sc = arg; 327213239Sgonzo GPIO_LOCK(sc); 328213239Sgonzo /* TODO: something useful */ 329213239Sgonzo GPIO_UNLOCK(sc); 330213239Sgonzo} 331213239Sgonzo 332213239Sgonzostatic int 333213239Sgonzoar71xx_gpio_probe(device_t dev) 334213239Sgonzo{ 335213239Sgonzo 336213239Sgonzo device_set_desc(dev, "Atheros AR71XX GPIO driver"); 337213239Sgonzo return (0); 338213239Sgonzo} 339213239Sgonzo 340213239Sgonzostatic int 341213239Sgonzoar71xx_gpio_attach(device_t dev) 342213239Sgonzo{ 343213239Sgonzo struct ar71xx_gpio_softc *sc = device_get_softc(dev); 344213239Sgonzo int error = 0; 345228518Sadrian int i, j, maxpin; 346234515Sadrian int mask, pinon; 347228518Sadrian int old = 0; 348213239Sgonzo 349213239Sgonzo KASSERT((device_get_unit(dev) == 0), 350213239Sgonzo ("ar71xx_gpio: Only one gpio module supported")); 351213239Sgonzo 352239351Srpaulo mtx_init(&sc->gpio_mtx, device_get_nameunit(dev), NULL, MTX_DEF); 353213239Sgonzo 354213239Sgonzo /* Map control/status registers. */ 355213239Sgonzo sc->gpio_mem_rid = 0; 356213239Sgonzo sc->gpio_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 357213239Sgonzo &sc->gpio_mem_rid, RF_ACTIVE); 358213239Sgonzo 359213239Sgonzo if (sc->gpio_mem_res == NULL) { 360213239Sgonzo device_printf(dev, "couldn't map memory\n"); 361213239Sgonzo error = ENXIO; 362213239Sgonzo ar71xx_gpio_detach(dev); 363213239Sgonzo return(error); 364213239Sgonzo } 365213239Sgonzo 366213239Sgonzo if ((sc->gpio_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 367213239Sgonzo &sc->gpio_irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) { 368213239Sgonzo device_printf(dev, "unable to allocate IRQ resource\n"); 369213239Sgonzo return (ENXIO); 370213239Sgonzo } 371213239Sgonzo 372213239Sgonzo if ((bus_setup_intr(dev, sc->gpio_irq_res, INTR_TYPE_MISC, 373213239Sgonzo ar71xx_gpio_filter, ar71xx_gpio_intr, sc, &sc->gpio_ih))) { 374213239Sgonzo device_printf(dev, 375213239Sgonzo "WARNING: unable to register interrupt handler\n"); 376213239Sgonzo return (ENXIO); 377213239Sgonzo } 378213239Sgonzo 379213239Sgonzo sc->dev = dev; 380228518Sadrian 381228518Sadrian /* Enable function bits that are required */ 382228518Sadrian if (resource_int_value(device_get_name(dev), device_get_unit(dev), 383228518Sadrian "function_set", &mask) == 0) { 384228518Sadrian device_printf(dev, "function_set: 0x%x\n", mask); 385228518Sadrian ar71xx_gpio_function_enable(sc, mask); 386228518Sadrian old = 1; 387228518Sadrian } 388228518Sadrian /* Disable function bits that are required */ 389228518Sadrian if (resource_int_value(device_get_name(dev), device_get_unit(dev), 390228518Sadrian "function_clear", &mask) == 0) { 391228518Sadrian device_printf(dev, "function_clear: 0x%x\n", mask); 392228518Sadrian ar71xx_gpio_function_disable(sc, mask); 393228518Sadrian old = 1; 394228518Sadrian } 395228518Sadrian /* Handle previous behaviour */ 396228518Sadrian if (old == 0) { 397228518Sadrian ar71xx_gpio_function_enable(sc, GPIO_FUNC_SPI_CS1_EN); 398228518Sadrian ar71xx_gpio_function_enable(sc, GPIO_FUNC_SPI_CS2_EN); 399228518Sadrian } 400228518Sadrian 401213239Sgonzo /* Configure all pins as input */ 402213239Sgonzo /* disable interrupts for all pins */ 403213239Sgonzo GPIO_WRITE(sc, AR71XX_GPIO_INT_MASK, 0); 404228518Sadrian 405228518Sadrian /* Initialise all pins specified in the mask, up to the pin count */ 406228518Sadrian (void) ar71xx_gpio_pin_max(dev, &maxpin); 407228518Sadrian if (resource_int_value(device_get_name(dev), device_get_unit(dev), 408228518Sadrian "pinmask", &mask) != 0) 409228518Sadrian mask = 0; 410234515Sadrian if (resource_int_value(device_get_name(dev), device_get_unit(dev), 411234515Sadrian "pinon", &pinon) != 0) 412234515Sadrian pinon = 0; 413228518Sadrian device_printf(dev, "gpio pinmask=0x%x\n", mask); 414255335Sloos for (j = 0; j <= maxpin; j++) { 415255335Sloos if ((mask & (1 << j)) == 0) 416255335Sloos continue; 417255335Sloos sc->gpio_npins++; 418255335Sloos } 419255335Sloos sc->gpio_pins = malloc(sizeof(*sc->gpio_pins) * sc->gpio_npins, 420255335Sloos M_DEVBUF, M_WAITOK | M_ZERO); 421255334Sloos for (i = 0, j = 0; j <= maxpin; j++) { 422228518Sadrian if ((mask & (1 << j)) == 0) 423228518Sadrian continue; 424228518Sadrian snprintf(sc->gpio_pins[i].gp_name, GPIOMAXNAME, 425228518Sadrian "pin %d", j); 426228518Sadrian sc->gpio_pins[i].gp_pin = j; 427213239Sgonzo sc->gpio_pins[i].gp_caps = DEFAULT_CAPS; 428213239Sgonzo sc->gpio_pins[i].gp_flags = 0; 429228518Sadrian ar71xx_gpio_pin_configure(sc, &sc->gpio_pins[i], DEFAULT_CAPS); 430213239Sgonzo i++; 431213239Sgonzo } 432234515Sadrian for (i = 0; i < sc->gpio_npins; i++) { 433234515Sadrian j = sc->gpio_pins[i].gp_pin; 434234515Sadrian if ((pinon & (1 << j)) != 0) 435234515Sadrian ar71xx_gpio_pin_set(dev, j, 1); 436234515Sadrian } 437278782Sloos device_add_child(dev, "gpioc", -1); 438278782Sloos device_add_child(dev, "gpiobus", -1); 439278782Sloos 440213239Sgonzo return (bus_generic_attach(dev)); 441213239Sgonzo} 442213239Sgonzo 443213239Sgonzostatic int 444213239Sgonzoar71xx_gpio_detach(device_t dev) 445213239Sgonzo{ 446213239Sgonzo struct ar71xx_gpio_softc *sc = device_get_softc(dev); 447213239Sgonzo 448213239Sgonzo KASSERT(mtx_initialized(&sc->gpio_mtx), ("gpio mutex not initialized")); 449213239Sgonzo 450213286Sgonzo ar71xx_gpio_function_disable(sc, GPIO_FUNC_SPI_CS1_EN); 451213286Sgonzo ar71xx_gpio_function_disable(sc, GPIO_FUNC_SPI_CS2_EN); 452213239Sgonzo bus_generic_detach(dev); 453213239Sgonzo 454213239Sgonzo if (sc->gpio_mem_res) 455213239Sgonzo bus_release_resource(dev, SYS_RES_MEMORY, sc->gpio_mem_rid, 456213239Sgonzo sc->gpio_mem_res); 457213239Sgonzo 458255335Sloos free(sc->gpio_pins, M_DEVBUF); 459213239Sgonzo mtx_destroy(&sc->gpio_mtx); 460213239Sgonzo 461213239Sgonzo return(0); 462213239Sgonzo} 463213239Sgonzo 464213239Sgonzostatic device_method_t ar71xx_gpio_methods[] = { 465213239Sgonzo DEVMETHOD(device_probe, ar71xx_gpio_probe), 466213239Sgonzo DEVMETHOD(device_attach, ar71xx_gpio_attach), 467213239Sgonzo DEVMETHOD(device_detach, ar71xx_gpio_detach), 468213239Sgonzo 469213239Sgonzo /* GPIO protocol */ 470213239Sgonzo DEVMETHOD(gpio_pin_max, ar71xx_gpio_pin_max), 471213239Sgonzo DEVMETHOD(gpio_pin_getname, ar71xx_gpio_pin_getname), 472213239Sgonzo DEVMETHOD(gpio_pin_getflags, ar71xx_gpio_pin_getflags), 473213239Sgonzo DEVMETHOD(gpio_pin_getcaps, ar71xx_gpio_pin_getcaps), 474213239Sgonzo DEVMETHOD(gpio_pin_setflags, ar71xx_gpio_pin_setflags), 475213239Sgonzo DEVMETHOD(gpio_pin_get, ar71xx_gpio_pin_get), 476213239Sgonzo DEVMETHOD(gpio_pin_set, ar71xx_gpio_pin_set), 477213239Sgonzo DEVMETHOD(gpio_pin_toggle, ar71xx_gpio_pin_toggle), 478213239Sgonzo {0, 0}, 479213239Sgonzo}; 480213239Sgonzo 481213239Sgonzostatic driver_t ar71xx_gpio_driver = { 482213239Sgonzo "gpio", 483213239Sgonzo ar71xx_gpio_methods, 484213239Sgonzo sizeof(struct ar71xx_gpio_softc), 485213239Sgonzo}; 486213239Sgonzostatic devclass_t ar71xx_gpio_devclass; 487213239Sgonzo 488213239SgonzoDRIVER_MODULE(ar71xx_gpio, apb, ar71xx_gpio_driver, ar71xx_gpio_devclass, 0, 0); 489