ar71xx_gpio.c revision 249449
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: head/sys/mips/atheros/ar71xx_gpio.c 249449 2013-04-13 21:21:13Z dim $"); 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> 44213239Sgonzo#include <sys/mutex.h> 45213239Sgonzo#include <sys/gpio.h> 46213239Sgonzo 47213239Sgonzo#include <machine/bus.h> 48213239Sgonzo#include <machine/resource.h> 49213239Sgonzo#include <mips/atheros/ar71xxreg.h> 50221518Sadrian#include <mips/atheros/ar71xx_setup.h> 51213239Sgonzo#include <mips/atheros/ar71xx_gpiovar.h> 52213239Sgonzo 53213239Sgonzo#include "gpio_if.h" 54213239Sgonzo 55213239Sgonzo#define DEFAULT_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT) 56213239Sgonzo 57213239Sgonzo/* 58213239Sgonzo * Helpers 59213239Sgonzo */ 60213239Sgonzostatic void ar71xx_gpio_function_enable(struct ar71xx_gpio_softc *sc, 61213239Sgonzo uint32_t mask); 62213239Sgonzostatic void ar71xx_gpio_function_disable(struct ar71xx_gpio_softc *sc, 63213239Sgonzo uint32_t mask); 64213239Sgonzostatic void ar71xx_gpio_pin_configure(struct ar71xx_gpio_softc *sc, 65213239Sgonzo struct gpio_pin *pin, uint32_t flags); 66213239Sgonzo 67213239Sgonzo/* 68213239Sgonzo * Driver stuff 69213239Sgonzo */ 70213239Sgonzostatic int ar71xx_gpio_probe(device_t dev); 71213239Sgonzostatic int ar71xx_gpio_attach(device_t dev); 72213239Sgonzostatic int ar71xx_gpio_detach(device_t dev); 73213239Sgonzostatic int ar71xx_gpio_filter(void *arg); 74213239Sgonzostatic void ar71xx_gpio_intr(void *arg); 75213239Sgonzo 76213239Sgonzo/* 77213239Sgonzo * GPIO interface 78213239Sgonzo */ 79213239Sgonzostatic int ar71xx_gpio_pin_max(device_t dev, int *maxpin); 80213239Sgonzostatic int ar71xx_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps); 81213239Sgonzostatic int ar71xx_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t 82213239Sgonzo *flags); 83213239Sgonzostatic int ar71xx_gpio_pin_getname(device_t dev, uint32_t pin, char *name); 84213239Sgonzostatic int ar71xx_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags); 85213239Sgonzostatic int ar71xx_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value); 86213239Sgonzostatic int ar71xx_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val); 87213239Sgonzostatic int ar71xx_gpio_pin_toggle(device_t dev, uint32_t pin); 88213239Sgonzo 89213239Sgonzostatic void 90213239Sgonzoar71xx_gpio_function_enable(struct ar71xx_gpio_softc *sc, uint32_t mask) 91213239Sgonzo{ 92213239Sgonzo GPIO_SET_BITS(sc, AR71XX_GPIO_FUNCTION, mask); 93213239Sgonzo} 94213239Sgonzo 95213239Sgonzostatic void 96213239Sgonzoar71xx_gpio_function_disable(struct ar71xx_gpio_softc *sc, uint32_t mask) 97213239Sgonzo{ 98213239Sgonzo GPIO_CLEAR_BITS(sc, AR71XX_GPIO_FUNCTION, mask); 99213239Sgonzo} 100213239Sgonzo 101213239Sgonzostatic void 102213239Sgonzoar71xx_gpio_pin_configure(struct ar71xx_gpio_softc *sc, struct gpio_pin *pin, 103213239Sgonzo unsigned int flags) 104213239Sgonzo{ 105213239Sgonzo uint32_t mask; 106213239Sgonzo 107213239Sgonzo mask = 1 << pin->gp_pin; 108213239Sgonzo 109213239Sgonzo /* 110213239Sgonzo * Manage input/output 111213239Sgonzo */ 112213239Sgonzo if (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) { 113213239Sgonzo pin->gp_flags &= ~(GPIO_PIN_INPUT|GPIO_PIN_OUTPUT); 114213239Sgonzo if (flags & GPIO_PIN_OUTPUT) { 115213239Sgonzo pin->gp_flags |= GPIO_PIN_OUTPUT; 116213239Sgonzo GPIO_SET_BITS(sc, AR71XX_GPIO_OE, mask); 117213239Sgonzo } 118213239Sgonzo else { 119213239Sgonzo pin->gp_flags |= GPIO_PIN_INPUT; 120213239Sgonzo GPIO_CLEAR_BITS(sc, AR71XX_GPIO_OE, mask); 121213239Sgonzo } 122213239Sgonzo } 123213239Sgonzo} 124213239Sgonzo 125213239Sgonzostatic int 126213239Sgonzoar71xx_gpio_pin_max(device_t dev, int *maxpin) 127213239Sgonzo{ 128213239Sgonzo 129221518Sadrian switch (ar71xx_soc) { 130221518Sadrian case AR71XX_SOC_AR9130: 131221518Sadrian case AR71XX_SOC_AR9132: 132221518Sadrian *maxpin = AR91XX_GPIO_PINS - 1; 133221518Sadrian break; 134221518Sadrian case AR71XX_SOC_AR7240: 135221518Sadrian case AR71XX_SOC_AR7241: 136221518Sadrian case AR71XX_SOC_AR7242: 137221518Sadrian *maxpin = AR724X_GPIO_PINS - 1; 138221518Sadrian break; 139221518Sadrian default: 140221518Sadrian *maxpin = AR71XX_GPIO_PINS - 1; 141221518Sadrian } 142213239Sgonzo return (0); 143213239Sgonzo} 144213239Sgonzo 145213239Sgonzostatic int 146213239Sgonzoar71xx_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) 147213239Sgonzo{ 148213239Sgonzo struct ar71xx_gpio_softc *sc = device_get_softc(dev); 149213239Sgonzo int i; 150213239Sgonzo 151213239Sgonzo for (i = 0; i < sc->gpio_npins; i++) { 152213239Sgonzo if (sc->gpio_pins[i].gp_pin == pin) 153213239Sgonzo break; 154213239Sgonzo } 155213239Sgonzo 156213239Sgonzo if (i >= sc->gpio_npins) 157213239Sgonzo return (EINVAL); 158213239Sgonzo 159213239Sgonzo GPIO_LOCK(sc); 160213239Sgonzo *caps = sc->gpio_pins[i].gp_caps; 161213239Sgonzo GPIO_UNLOCK(sc); 162213239Sgonzo 163213239Sgonzo return (0); 164213239Sgonzo} 165213239Sgonzo 166213239Sgonzostatic int 167213239Sgonzoar71xx_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) 168213239Sgonzo{ 169213239Sgonzo struct ar71xx_gpio_softc *sc = device_get_softc(dev); 170213239Sgonzo int i; 171213239Sgonzo 172213239Sgonzo for (i = 0; i < sc->gpio_npins; i++) { 173213239Sgonzo if (sc->gpio_pins[i].gp_pin == pin) 174213239Sgonzo break; 175213239Sgonzo } 176213239Sgonzo 177213239Sgonzo if (i >= sc->gpio_npins) 178213239Sgonzo return (EINVAL); 179213239Sgonzo 180213239Sgonzo GPIO_LOCK(sc); 181213239Sgonzo *flags = sc->gpio_pins[i].gp_flags; 182213239Sgonzo GPIO_UNLOCK(sc); 183213239Sgonzo 184213239Sgonzo return (0); 185213239Sgonzo} 186213239Sgonzo 187213239Sgonzostatic int 188213239Sgonzoar71xx_gpio_pin_getname(device_t dev, uint32_t pin, char *name) 189213239Sgonzo{ 190213239Sgonzo struct ar71xx_gpio_softc *sc = device_get_softc(dev); 191213239Sgonzo int i; 192213239Sgonzo 193213239Sgonzo for (i = 0; i < sc->gpio_npins; i++) { 194213239Sgonzo if (sc->gpio_pins[i].gp_pin == pin) 195213239Sgonzo break; 196213239Sgonzo } 197213239Sgonzo 198213239Sgonzo if (i >= sc->gpio_npins) 199213239Sgonzo return (EINVAL); 200213239Sgonzo 201213239Sgonzo GPIO_LOCK(sc); 202213239Sgonzo memcpy(name, sc->gpio_pins[i].gp_name, GPIOMAXNAME); 203213239Sgonzo GPIO_UNLOCK(sc); 204213239Sgonzo 205213239Sgonzo return (0); 206213239Sgonzo} 207213239Sgonzo 208213239Sgonzostatic int 209213239Sgonzoar71xx_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) 210213239Sgonzo{ 211213239Sgonzo int i; 212213239Sgonzo struct ar71xx_gpio_softc *sc = device_get_softc(dev); 213213239Sgonzo 214213239Sgonzo for (i = 0; i < sc->gpio_npins; i++) { 215213239Sgonzo if (sc->gpio_pins[i].gp_pin == pin) 216213239Sgonzo break; 217213239Sgonzo } 218213239Sgonzo 219213239Sgonzo if (i >= sc->gpio_npins) 220213239Sgonzo return (EINVAL); 221213239Sgonzo 222249449Sdim /* Check for unwanted flags. */ 223249449Sdim if ((flags & sc->gpio_pins[i].gp_caps) != flags) 224213239Sgonzo return (EINVAL); 225213239Sgonzo 226213239Sgonzo /* Can't mix input/output together */ 227213239Sgonzo if ((flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) == 228213239Sgonzo (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) 229213239Sgonzo return (EINVAL); 230213239Sgonzo 231213239Sgonzo ar71xx_gpio_pin_configure(sc, &sc->gpio_pins[i], flags); 232213239Sgonzo return (0); 233213239Sgonzo} 234213239Sgonzo 235213239Sgonzostatic int 236213239Sgonzoar71xx_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value) 237213239Sgonzo{ 238213239Sgonzo struct ar71xx_gpio_softc *sc = device_get_softc(dev); 239213239Sgonzo int i; 240213239Sgonzo 241213239Sgonzo for (i = 0; i < sc->gpio_npins; i++) { 242213239Sgonzo if (sc->gpio_pins[i].gp_pin == pin) 243213239Sgonzo break; 244213239Sgonzo } 245213239Sgonzo 246213239Sgonzo if (i >= sc->gpio_npins) 247213239Sgonzo return (EINVAL); 248213239Sgonzo 249213239Sgonzo if (value) 250213239Sgonzo GPIO_WRITE(sc, AR71XX_GPIO_SET, (1 << pin)); 251213239Sgonzo else 252213239Sgonzo GPIO_WRITE(sc, AR71XX_GPIO_CLEAR, (1 << pin)); 253213239Sgonzo 254213239Sgonzo return (0); 255213239Sgonzo} 256213239Sgonzo 257213239Sgonzostatic int 258213239Sgonzoar71xx_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val) 259213239Sgonzo{ 260213239Sgonzo struct ar71xx_gpio_softc *sc = device_get_softc(dev); 261213239Sgonzo int i; 262213239Sgonzo 263213239Sgonzo for (i = 0; i < sc->gpio_npins; i++) { 264213239Sgonzo if (sc->gpio_pins[i].gp_pin == pin) 265213239Sgonzo break; 266213239Sgonzo } 267213239Sgonzo 268213239Sgonzo if (i >= sc->gpio_npins) 269213239Sgonzo return (EINVAL); 270213239Sgonzo 271213239Sgonzo *val = (GPIO_READ(sc, AR71XX_GPIO_IN) & (1 << pin)) ? 1 : 0; 272213239Sgonzo 273213239Sgonzo return (0); 274213239Sgonzo} 275213239Sgonzo 276213239Sgonzostatic int 277213239Sgonzoar71xx_gpio_pin_toggle(device_t dev, uint32_t pin) 278213239Sgonzo{ 279213239Sgonzo int res, i; 280213239Sgonzo struct ar71xx_gpio_softc *sc = device_get_softc(dev); 281213239Sgonzo 282213239Sgonzo for (i = 0; i < sc->gpio_npins; i++) { 283213239Sgonzo if (sc->gpio_pins[i].gp_pin == pin) 284213239Sgonzo break; 285213239Sgonzo } 286213239Sgonzo 287213239Sgonzo if (i >= sc->gpio_npins) 288213239Sgonzo return (EINVAL); 289213239Sgonzo 290213239Sgonzo res = (GPIO_READ(sc, AR71XX_GPIO_IN) & (1 << pin)) ? 1 : 0; 291213239Sgonzo if (res) 292213239Sgonzo GPIO_WRITE(sc, AR71XX_GPIO_CLEAR, (1 << pin)); 293213239Sgonzo else 294213239Sgonzo GPIO_WRITE(sc, AR71XX_GPIO_SET, (1 << pin)); 295213239Sgonzo 296213239Sgonzo return (0); 297213239Sgonzo} 298213239Sgonzo 299213239Sgonzostatic int 300213239Sgonzoar71xx_gpio_filter(void *arg) 301213239Sgonzo{ 302213239Sgonzo 303213239Sgonzo /* TODO: something useful */ 304213239Sgonzo return (FILTER_STRAY); 305213239Sgonzo} 306213239Sgonzo 307213239Sgonzo 308213239Sgonzo 309213239Sgonzostatic void 310213239Sgonzoar71xx_gpio_intr(void *arg) 311213239Sgonzo{ 312213239Sgonzo struct ar71xx_gpio_softc *sc = arg; 313213239Sgonzo GPIO_LOCK(sc); 314213239Sgonzo /* TODO: something useful */ 315213239Sgonzo GPIO_UNLOCK(sc); 316213239Sgonzo} 317213239Sgonzo 318213239Sgonzostatic int 319213239Sgonzoar71xx_gpio_probe(device_t dev) 320213239Sgonzo{ 321213239Sgonzo 322213239Sgonzo device_set_desc(dev, "Atheros AR71XX GPIO driver"); 323213239Sgonzo return (0); 324213239Sgonzo} 325213239Sgonzo 326213239Sgonzostatic int 327213239Sgonzoar71xx_gpio_attach(device_t dev) 328213239Sgonzo{ 329213239Sgonzo struct ar71xx_gpio_softc *sc = device_get_softc(dev); 330213239Sgonzo int error = 0; 331228518Sadrian int i, j, maxpin; 332234515Sadrian int mask, pinon; 333228518Sadrian int old = 0; 334213239Sgonzo 335213239Sgonzo KASSERT((device_get_unit(dev) == 0), 336213239Sgonzo ("ar71xx_gpio: Only one gpio module supported")); 337213239Sgonzo 338239351Srpaulo mtx_init(&sc->gpio_mtx, device_get_nameunit(dev), NULL, MTX_DEF); 339213239Sgonzo 340213239Sgonzo /* Map control/status registers. */ 341213239Sgonzo sc->gpio_mem_rid = 0; 342213239Sgonzo sc->gpio_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 343213239Sgonzo &sc->gpio_mem_rid, RF_ACTIVE); 344213239Sgonzo 345213239Sgonzo if (sc->gpio_mem_res == NULL) { 346213239Sgonzo device_printf(dev, "couldn't map memory\n"); 347213239Sgonzo error = ENXIO; 348213239Sgonzo ar71xx_gpio_detach(dev); 349213239Sgonzo return(error); 350213239Sgonzo } 351213239Sgonzo 352213239Sgonzo if ((sc->gpio_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 353213239Sgonzo &sc->gpio_irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) { 354213239Sgonzo device_printf(dev, "unable to allocate IRQ resource\n"); 355213239Sgonzo return (ENXIO); 356213239Sgonzo } 357213239Sgonzo 358213239Sgonzo if ((bus_setup_intr(dev, sc->gpio_irq_res, INTR_TYPE_MISC, 359213239Sgonzo ar71xx_gpio_filter, ar71xx_gpio_intr, sc, &sc->gpio_ih))) { 360213239Sgonzo device_printf(dev, 361213239Sgonzo "WARNING: unable to register interrupt handler\n"); 362213239Sgonzo return (ENXIO); 363213239Sgonzo } 364213239Sgonzo 365213239Sgonzo sc->dev = dev; 366228518Sadrian 367228518Sadrian /* Enable function bits that are required */ 368228518Sadrian if (resource_int_value(device_get_name(dev), device_get_unit(dev), 369228518Sadrian "function_set", &mask) == 0) { 370228518Sadrian device_printf(dev, "function_set: 0x%x\n", mask); 371228518Sadrian ar71xx_gpio_function_enable(sc, mask); 372228518Sadrian old = 1; 373228518Sadrian } 374228518Sadrian /* Disable function bits that are required */ 375228518Sadrian if (resource_int_value(device_get_name(dev), device_get_unit(dev), 376228518Sadrian "function_clear", &mask) == 0) { 377228518Sadrian device_printf(dev, "function_clear: 0x%x\n", mask); 378228518Sadrian ar71xx_gpio_function_disable(sc, mask); 379228518Sadrian old = 1; 380228518Sadrian } 381228518Sadrian /* Handle previous behaviour */ 382228518Sadrian if (old == 0) { 383228518Sadrian ar71xx_gpio_function_enable(sc, GPIO_FUNC_SPI_CS1_EN); 384228518Sadrian ar71xx_gpio_function_enable(sc, GPIO_FUNC_SPI_CS2_EN); 385228518Sadrian } 386228518Sadrian 387213239Sgonzo /* Configure all pins as input */ 388213239Sgonzo /* disable interrupts for all pins */ 389213239Sgonzo GPIO_WRITE(sc, AR71XX_GPIO_INT_MASK, 0); 390228518Sadrian 391228518Sadrian /* Initialise all pins specified in the mask, up to the pin count */ 392228518Sadrian (void) ar71xx_gpio_pin_max(dev, &maxpin); 393228518Sadrian if (resource_int_value(device_get_name(dev), device_get_unit(dev), 394228518Sadrian "pinmask", &mask) != 0) 395228518Sadrian mask = 0; 396234515Sadrian if (resource_int_value(device_get_name(dev), device_get_unit(dev), 397234515Sadrian "pinon", &pinon) != 0) 398234515Sadrian pinon = 0; 399228518Sadrian device_printf(dev, "gpio pinmask=0x%x\n", mask); 400228518Sadrian for (i = 0, j = 0; j < maxpin; j++) { 401228518Sadrian if ((mask & (1 << j)) == 0) 402228518Sadrian continue; 403228518Sadrian snprintf(sc->gpio_pins[i].gp_name, GPIOMAXNAME, 404228518Sadrian "pin %d", j); 405228518Sadrian sc->gpio_pins[i].gp_pin = j; 406213239Sgonzo sc->gpio_pins[i].gp_caps = DEFAULT_CAPS; 407213239Sgonzo sc->gpio_pins[i].gp_flags = 0; 408228518Sadrian ar71xx_gpio_pin_configure(sc, &sc->gpio_pins[i], DEFAULT_CAPS); 409213239Sgonzo i++; 410213239Sgonzo } 411213239Sgonzo sc->gpio_npins = i; 412234515Sadrian for (i = 0; i < sc->gpio_npins; i++) { 413234515Sadrian j = sc->gpio_pins[i].gp_pin; 414234515Sadrian if ((pinon & (1 << j)) != 0) 415234515Sadrian ar71xx_gpio_pin_set(dev, j, 1); 416234515Sadrian } 417213239Sgonzo device_add_child(dev, "gpioc", device_get_unit(dev)); 418213239Sgonzo device_add_child(dev, "gpiobus", device_get_unit(dev)); 419213239Sgonzo return (bus_generic_attach(dev)); 420213239Sgonzo} 421213239Sgonzo 422213239Sgonzostatic int 423213239Sgonzoar71xx_gpio_detach(device_t dev) 424213239Sgonzo{ 425213239Sgonzo struct ar71xx_gpio_softc *sc = device_get_softc(dev); 426213239Sgonzo 427213239Sgonzo KASSERT(mtx_initialized(&sc->gpio_mtx), ("gpio mutex not initialized")); 428213239Sgonzo 429213286Sgonzo ar71xx_gpio_function_disable(sc, GPIO_FUNC_SPI_CS1_EN); 430213286Sgonzo ar71xx_gpio_function_disable(sc, GPIO_FUNC_SPI_CS2_EN); 431213239Sgonzo bus_generic_detach(dev); 432213239Sgonzo 433213239Sgonzo if (sc->gpio_mem_res) 434213239Sgonzo bus_release_resource(dev, SYS_RES_MEMORY, sc->gpio_mem_rid, 435213239Sgonzo sc->gpio_mem_res); 436213239Sgonzo 437213239Sgonzo mtx_destroy(&sc->gpio_mtx); 438213239Sgonzo 439213239Sgonzo return(0); 440213239Sgonzo} 441213239Sgonzo 442213239Sgonzostatic device_method_t ar71xx_gpio_methods[] = { 443213239Sgonzo DEVMETHOD(device_probe, ar71xx_gpio_probe), 444213239Sgonzo DEVMETHOD(device_attach, ar71xx_gpio_attach), 445213239Sgonzo DEVMETHOD(device_detach, ar71xx_gpio_detach), 446213239Sgonzo 447213239Sgonzo /* GPIO protocol */ 448213239Sgonzo DEVMETHOD(gpio_pin_max, ar71xx_gpio_pin_max), 449213239Sgonzo DEVMETHOD(gpio_pin_getname, ar71xx_gpio_pin_getname), 450213239Sgonzo DEVMETHOD(gpio_pin_getflags, ar71xx_gpio_pin_getflags), 451213239Sgonzo DEVMETHOD(gpio_pin_getcaps, ar71xx_gpio_pin_getcaps), 452213239Sgonzo DEVMETHOD(gpio_pin_setflags, ar71xx_gpio_pin_setflags), 453213239Sgonzo DEVMETHOD(gpio_pin_get, ar71xx_gpio_pin_get), 454213239Sgonzo DEVMETHOD(gpio_pin_set, ar71xx_gpio_pin_set), 455213239Sgonzo DEVMETHOD(gpio_pin_toggle, ar71xx_gpio_pin_toggle), 456213239Sgonzo {0, 0}, 457213239Sgonzo}; 458213239Sgonzo 459213239Sgonzostatic driver_t ar71xx_gpio_driver = { 460213239Sgonzo "gpio", 461213239Sgonzo ar71xx_gpio_methods, 462213239Sgonzo sizeof(struct ar71xx_gpio_softc), 463213239Sgonzo}; 464213239Sgonzostatic devclass_t ar71xx_gpio_devclass; 465213239Sgonzo 466213239SgonzoDRIVER_MODULE(ar71xx_gpio, apb, ar71xx_gpio_driver, ar71xx_gpio_devclass, 0, 0); 467