ar71xx_gpio.c revision 253510
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 253510 2013-07-21 03:55:18Z adrian $"); 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> 52250165Sadrian#include <mips/atheros/ar933xreg.h> 53253510Sadrian#include <mips/atheros/ar934xreg.h> 54213239Sgonzo 55213239Sgonzo#include "gpio_if.h" 56213239Sgonzo 57213239Sgonzo#define DEFAULT_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT) 58213239Sgonzo 59213239Sgonzo/* 60213239Sgonzo * Helpers 61213239Sgonzo */ 62213239Sgonzostatic void ar71xx_gpio_function_enable(struct ar71xx_gpio_softc *sc, 63213239Sgonzo uint32_t mask); 64213239Sgonzostatic void ar71xx_gpio_function_disable(struct ar71xx_gpio_softc *sc, 65213239Sgonzo uint32_t mask); 66213239Sgonzostatic void ar71xx_gpio_pin_configure(struct ar71xx_gpio_softc *sc, 67213239Sgonzo struct gpio_pin *pin, uint32_t flags); 68213239Sgonzo 69213239Sgonzo/* 70213239Sgonzo * Driver stuff 71213239Sgonzo */ 72213239Sgonzostatic int ar71xx_gpio_probe(device_t dev); 73213239Sgonzostatic int ar71xx_gpio_attach(device_t dev); 74213239Sgonzostatic int ar71xx_gpio_detach(device_t dev); 75213239Sgonzostatic int ar71xx_gpio_filter(void *arg); 76213239Sgonzostatic void ar71xx_gpio_intr(void *arg); 77213239Sgonzo 78213239Sgonzo/* 79213239Sgonzo * GPIO interface 80213239Sgonzo */ 81213239Sgonzostatic int ar71xx_gpio_pin_max(device_t dev, int *maxpin); 82213239Sgonzostatic int ar71xx_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps); 83213239Sgonzostatic int ar71xx_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t 84213239Sgonzo *flags); 85213239Sgonzostatic int ar71xx_gpio_pin_getname(device_t dev, uint32_t pin, char *name); 86213239Sgonzostatic int ar71xx_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags); 87213239Sgonzostatic int ar71xx_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value); 88213239Sgonzostatic int ar71xx_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val); 89213239Sgonzostatic int ar71xx_gpio_pin_toggle(device_t dev, uint32_t pin); 90213239Sgonzo 91213239Sgonzostatic void 92213239Sgonzoar71xx_gpio_function_enable(struct ar71xx_gpio_softc *sc, uint32_t mask) 93213239Sgonzo{ 94253510Sadrian if (ar71xx_soc == AR71XX_SOC_AR9341 || 95253510Sadrian ar71xx_soc == AR71XX_SOC_AR9342 || 96253510Sadrian ar71xx_soc == AR71XX_SOC_AR9344) 97253510Sadrian GPIO_SET_BITS(sc, AR934X_GPIO_REG_FUNC, mask); 98253510Sadrian else 99253510Sadrian GPIO_SET_BITS(sc, AR71XX_GPIO_FUNCTION, mask); 100213239Sgonzo} 101213239Sgonzo 102213239Sgonzostatic void 103213239Sgonzoar71xx_gpio_function_disable(struct ar71xx_gpio_softc *sc, uint32_t mask) 104213239Sgonzo{ 105253510Sadrian if (ar71xx_soc == AR71XX_SOC_AR9341 || 106253510Sadrian ar71xx_soc == AR71XX_SOC_AR9342 || 107253510Sadrian ar71xx_soc == AR71XX_SOC_AR9344) 108253510Sadrian GPIO_CLEAR_BITS(sc, AR934X_GPIO_REG_FUNC, mask); 109253510Sadrian else 110253510Sadrian GPIO_CLEAR_BITS(sc, AR71XX_GPIO_FUNCTION, mask); 111213239Sgonzo} 112213239Sgonzo 113213239Sgonzostatic void 114213239Sgonzoar71xx_gpio_pin_configure(struct ar71xx_gpio_softc *sc, struct gpio_pin *pin, 115213239Sgonzo unsigned int flags) 116213239Sgonzo{ 117213239Sgonzo uint32_t mask; 118213239Sgonzo 119213239Sgonzo mask = 1 << pin->gp_pin; 120213239Sgonzo 121213239Sgonzo /* 122213239Sgonzo * Manage input/output 123213239Sgonzo */ 124213239Sgonzo if (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) { 125213239Sgonzo pin->gp_flags &= ~(GPIO_PIN_INPUT|GPIO_PIN_OUTPUT); 126213239Sgonzo if (flags & GPIO_PIN_OUTPUT) { 127213239Sgonzo pin->gp_flags |= GPIO_PIN_OUTPUT; 128213239Sgonzo GPIO_SET_BITS(sc, AR71XX_GPIO_OE, mask); 129213239Sgonzo } 130213239Sgonzo else { 131213239Sgonzo pin->gp_flags |= GPIO_PIN_INPUT; 132213239Sgonzo GPIO_CLEAR_BITS(sc, AR71XX_GPIO_OE, mask); 133213239Sgonzo } 134213239Sgonzo } 135213239Sgonzo} 136213239Sgonzo 137213239Sgonzostatic int 138213239Sgonzoar71xx_gpio_pin_max(device_t dev, int *maxpin) 139213239Sgonzo{ 140213239Sgonzo 141221518Sadrian switch (ar71xx_soc) { 142221518Sadrian case AR71XX_SOC_AR9130: 143221518Sadrian case AR71XX_SOC_AR9132: 144221518Sadrian *maxpin = AR91XX_GPIO_PINS - 1; 145221518Sadrian break; 146221518Sadrian case AR71XX_SOC_AR7240: 147221518Sadrian case AR71XX_SOC_AR7241: 148221518Sadrian case AR71XX_SOC_AR7242: 149221518Sadrian *maxpin = AR724X_GPIO_PINS - 1; 150221518Sadrian break; 151250165Sadrian case AR71XX_SOC_AR9330: 152250165Sadrian case AR71XX_SOC_AR9331: 153250165Sadrian *maxpin = AR933X_GPIO_COUNT - 1; 154250165Sadrian break; 155253510Sadrian case AR71XX_SOC_AR9341: 156253510Sadrian case AR71XX_SOC_AR9342: 157253510Sadrian case AR71XX_SOC_AR9344: 158253510Sadrian *maxpin = AR934X_GPIO_COUNT - 1; 159221518Sadrian default: 160221518Sadrian *maxpin = AR71XX_GPIO_PINS - 1; 161221518Sadrian } 162213239Sgonzo return (0); 163213239Sgonzo} 164213239Sgonzo 165213239Sgonzostatic int 166213239Sgonzoar71xx_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) 167213239Sgonzo{ 168213239Sgonzo struct ar71xx_gpio_softc *sc = device_get_softc(dev); 169213239Sgonzo int i; 170213239Sgonzo 171213239Sgonzo for (i = 0; i < sc->gpio_npins; i++) { 172213239Sgonzo if (sc->gpio_pins[i].gp_pin == pin) 173213239Sgonzo break; 174213239Sgonzo } 175213239Sgonzo 176213239Sgonzo if (i >= sc->gpio_npins) 177213239Sgonzo return (EINVAL); 178213239Sgonzo 179213239Sgonzo GPIO_LOCK(sc); 180213239Sgonzo *caps = sc->gpio_pins[i].gp_caps; 181213239Sgonzo GPIO_UNLOCK(sc); 182213239Sgonzo 183213239Sgonzo return (0); 184213239Sgonzo} 185213239Sgonzo 186213239Sgonzostatic int 187213239Sgonzoar71xx_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) 188213239Sgonzo{ 189213239Sgonzo struct ar71xx_gpio_softc *sc = device_get_softc(dev); 190213239Sgonzo int i; 191213239Sgonzo 192213239Sgonzo for (i = 0; i < sc->gpio_npins; i++) { 193213239Sgonzo if (sc->gpio_pins[i].gp_pin == pin) 194213239Sgonzo break; 195213239Sgonzo } 196213239Sgonzo 197213239Sgonzo if (i >= sc->gpio_npins) 198213239Sgonzo return (EINVAL); 199213239Sgonzo 200213239Sgonzo GPIO_LOCK(sc); 201213239Sgonzo *flags = sc->gpio_pins[i].gp_flags; 202213239Sgonzo GPIO_UNLOCK(sc); 203213239Sgonzo 204213239Sgonzo return (0); 205213239Sgonzo} 206213239Sgonzo 207213239Sgonzostatic int 208213239Sgonzoar71xx_gpio_pin_getname(device_t dev, uint32_t pin, char *name) 209213239Sgonzo{ 210213239Sgonzo struct ar71xx_gpio_softc *sc = device_get_softc(dev); 211213239Sgonzo int i; 212213239Sgonzo 213213239Sgonzo for (i = 0; i < sc->gpio_npins; i++) { 214213239Sgonzo if (sc->gpio_pins[i].gp_pin == pin) 215213239Sgonzo break; 216213239Sgonzo } 217213239Sgonzo 218213239Sgonzo if (i >= sc->gpio_npins) 219213239Sgonzo return (EINVAL); 220213239Sgonzo 221213239Sgonzo GPIO_LOCK(sc); 222213239Sgonzo memcpy(name, sc->gpio_pins[i].gp_name, GPIOMAXNAME); 223213239Sgonzo GPIO_UNLOCK(sc); 224213239Sgonzo 225213239Sgonzo return (0); 226213239Sgonzo} 227213239Sgonzo 228213239Sgonzostatic int 229213239Sgonzoar71xx_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) 230213239Sgonzo{ 231213239Sgonzo int i; 232213239Sgonzo struct ar71xx_gpio_softc *sc = device_get_softc(dev); 233213239Sgonzo 234213239Sgonzo for (i = 0; i < sc->gpio_npins; i++) { 235213239Sgonzo if (sc->gpio_pins[i].gp_pin == pin) 236213239Sgonzo break; 237213239Sgonzo } 238213239Sgonzo 239213239Sgonzo if (i >= sc->gpio_npins) 240213239Sgonzo return (EINVAL); 241213239Sgonzo 242249449Sdim /* Check for unwanted flags. */ 243249449Sdim if ((flags & sc->gpio_pins[i].gp_caps) != flags) 244213239Sgonzo return (EINVAL); 245213239Sgonzo 246213239Sgonzo /* Can't mix input/output together */ 247213239Sgonzo if ((flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) == 248213239Sgonzo (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) 249213239Sgonzo return (EINVAL); 250213239Sgonzo 251213239Sgonzo ar71xx_gpio_pin_configure(sc, &sc->gpio_pins[i], flags); 252213239Sgonzo return (0); 253213239Sgonzo} 254213239Sgonzo 255213239Sgonzostatic int 256213239Sgonzoar71xx_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value) 257213239Sgonzo{ 258213239Sgonzo struct ar71xx_gpio_softc *sc = device_get_softc(dev); 259213239Sgonzo int i; 260213239Sgonzo 261213239Sgonzo for (i = 0; i < sc->gpio_npins; i++) { 262213239Sgonzo if (sc->gpio_pins[i].gp_pin == pin) 263213239Sgonzo break; 264213239Sgonzo } 265213239Sgonzo 266213239Sgonzo if (i >= sc->gpio_npins) 267213239Sgonzo return (EINVAL); 268213239Sgonzo 269213239Sgonzo if (value) 270213239Sgonzo GPIO_WRITE(sc, AR71XX_GPIO_SET, (1 << pin)); 271213239Sgonzo else 272213239Sgonzo GPIO_WRITE(sc, AR71XX_GPIO_CLEAR, (1 << pin)); 273213239Sgonzo 274213239Sgonzo return (0); 275213239Sgonzo} 276213239Sgonzo 277213239Sgonzostatic int 278213239Sgonzoar71xx_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val) 279213239Sgonzo{ 280213239Sgonzo struct ar71xx_gpio_softc *sc = device_get_softc(dev); 281213239Sgonzo int i; 282213239Sgonzo 283213239Sgonzo for (i = 0; i < sc->gpio_npins; i++) { 284213239Sgonzo if (sc->gpio_pins[i].gp_pin == pin) 285213239Sgonzo break; 286213239Sgonzo } 287213239Sgonzo 288213239Sgonzo if (i >= sc->gpio_npins) 289213239Sgonzo return (EINVAL); 290213239Sgonzo 291213239Sgonzo *val = (GPIO_READ(sc, AR71XX_GPIO_IN) & (1 << pin)) ? 1 : 0; 292213239Sgonzo 293213239Sgonzo return (0); 294213239Sgonzo} 295213239Sgonzo 296213239Sgonzostatic int 297213239Sgonzoar71xx_gpio_pin_toggle(device_t dev, uint32_t pin) 298213239Sgonzo{ 299213239Sgonzo int res, i; 300213239Sgonzo struct ar71xx_gpio_softc *sc = device_get_softc(dev); 301213239Sgonzo 302213239Sgonzo for (i = 0; i < sc->gpio_npins; i++) { 303213239Sgonzo if (sc->gpio_pins[i].gp_pin == pin) 304213239Sgonzo break; 305213239Sgonzo } 306213239Sgonzo 307213239Sgonzo if (i >= sc->gpio_npins) 308213239Sgonzo return (EINVAL); 309213239Sgonzo 310213239Sgonzo res = (GPIO_READ(sc, AR71XX_GPIO_IN) & (1 << pin)) ? 1 : 0; 311213239Sgonzo if (res) 312213239Sgonzo GPIO_WRITE(sc, AR71XX_GPIO_CLEAR, (1 << pin)); 313213239Sgonzo else 314213239Sgonzo GPIO_WRITE(sc, AR71XX_GPIO_SET, (1 << pin)); 315213239Sgonzo 316213239Sgonzo return (0); 317213239Sgonzo} 318213239Sgonzo 319213239Sgonzostatic int 320213239Sgonzoar71xx_gpio_filter(void *arg) 321213239Sgonzo{ 322213239Sgonzo 323213239Sgonzo /* TODO: something useful */ 324213239Sgonzo return (FILTER_STRAY); 325213239Sgonzo} 326213239Sgonzo 327213239Sgonzo 328213239Sgonzo 329213239Sgonzostatic void 330213239Sgonzoar71xx_gpio_intr(void *arg) 331213239Sgonzo{ 332213239Sgonzo struct ar71xx_gpio_softc *sc = arg; 333213239Sgonzo GPIO_LOCK(sc); 334213239Sgonzo /* TODO: something useful */ 335213239Sgonzo GPIO_UNLOCK(sc); 336213239Sgonzo} 337213239Sgonzo 338213239Sgonzostatic int 339213239Sgonzoar71xx_gpio_probe(device_t dev) 340213239Sgonzo{ 341213239Sgonzo 342213239Sgonzo device_set_desc(dev, "Atheros AR71XX GPIO driver"); 343213239Sgonzo return (0); 344213239Sgonzo} 345213239Sgonzo 346213239Sgonzostatic int 347213239Sgonzoar71xx_gpio_attach(device_t dev) 348213239Sgonzo{ 349213239Sgonzo struct ar71xx_gpio_softc *sc = device_get_softc(dev); 350213239Sgonzo int error = 0; 351228518Sadrian int i, j, maxpin; 352234515Sadrian int mask, pinon; 353228518Sadrian int old = 0; 354213239Sgonzo 355213239Sgonzo KASSERT((device_get_unit(dev) == 0), 356213239Sgonzo ("ar71xx_gpio: Only one gpio module supported")); 357213239Sgonzo 358239351Srpaulo mtx_init(&sc->gpio_mtx, device_get_nameunit(dev), NULL, MTX_DEF); 359213239Sgonzo 360213239Sgonzo /* Map control/status registers. */ 361213239Sgonzo sc->gpio_mem_rid = 0; 362213239Sgonzo sc->gpio_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 363213239Sgonzo &sc->gpio_mem_rid, RF_ACTIVE); 364213239Sgonzo 365213239Sgonzo if (sc->gpio_mem_res == NULL) { 366213239Sgonzo device_printf(dev, "couldn't map memory\n"); 367213239Sgonzo error = ENXIO; 368213239Sgonzo ar71xx_gpio_detach(dev); 369213239Sgonzo return(error); 370213239Sgonzo } 371213239Sgonzo 372213239Sgonzo if ((sc->gpio_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 373213239Sgonzo &sc->gpio_irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) { 374213239Sgonzo device_printf(dev, "unable to allocate IRQ resource\n"); 375213239Sgonzo return (ENXIO); 376213239Sgonzo } 377213239Sgonzo 378213239Sgonzo if ((bus_setup_intr(dev, sc->gpio_irq_res, INTR_TYPE_MISC, 379213239Sgonzo ar71xx_gpio_filter, ar71xx_gpio_intr, sc, &sc->gpio_ih))) { 380213239Sgonzo device_printf(dev, 381213239Sgonzo "WARNING: unable to register interrupt handler\n"); 382213239Sgonzo return (ENXIO); 383213239Sgonzo } 384213239Sgonzo 385213239Sgonzo sc->dev = dev; 386228518Sadrian 387228518Sadrian /* Enable function bits that are required */ 388228518Sadrian if (resource_int_value(device_get_name(dev), device_get_unit(dev), 389228518Sadrian "function_set", &mask) == 0) { 390228518Sadrian device_printf(dev, "function_set: 0x%x\n", mask); 391228518Sadrian ar71xx_gpio_function_enable(sc, mask); 392228518Sadrian old = 1; 393228518Sadrian } 394228518Sadrian /* Disable function bits that are required */ 395228518Sadrian if (resource_int_value(device_get_name(dev), device_get_unit(dev), 396228518Sadrian "function_clear", &mask) == 0) { 397228518Sadrian device_printf(dev, "function_clear: 0x%x\n", mask); 398228518Sadrian ar71xx_gpio_function_disable(sc, mask); 399228518Sadrian old = 1; 400228518Sadrian } 401228518Sadrian /* Handle previous behaviour */ 402228518Sadrian if (old == 0) { 403228518Sadrian ar71xx_gpio_function_enable(sc, GPIO_FUNC_SPI_CS1_EN); 404228518Sadrian ar71xx_gpio_function_enable(sc, GPIO_FUNC_SPI_CS2_EN); 405228518Sadrian } 406228518Sadrian 407213239Sgonzo /* Configure all pins as input */ 408213239Sgonzo /* disable interrupts for all pins */ 409213239Sgonzo GPIO_WRITE(sc, AR71XX_GPIO_INT_MASK, 0); 410228518Sadrian 411228518Sadrian /* Initialise all pins specified in the mask, up to the pin count */ 412228518Sadrian (void) ar71xx_gpio_pin_max(dev, &maxpin); 413228518Sadrian if (resource_int_value(device_get_name(dev), device_get_unit(dev), 414228518Sadrian "pinmask", &mask) != 0) 415228518Sadrian mask = 0; 416234515Sadrian if (resource_int_value(device_get_name(dev), device_get_unit(dev), 417234515Sadrian "pinon", &pinon) != 0) 418234515Sadrian pinon = 0; 419228518Sadrian device_printf(dev, "gpio pinmask=0x%x\n", mask); 420228518Sadrian for (i = 0, j = 0; j < maxpin; j++) { 421228518Sadrian if ((mask & (1 << j)) == 0) 422228518Sadrian continue; 423228518Sadrian snprintf(sc->gpio_pins[i].gp_name, GPIOMAXNAME, 424228518Sadrian "pin %d", j); 425228518Sadrian sc->gpio_pins[i].gp_pin = j; 426213239Sgonzo sc->gpio_pins[i].gp_caps = DEFAULT_CAPS; 427213239Sgonzo sc->gpio_pins[i].gp_flags = 0; 428228518Sadrian ar71xx_gpio_pin_configure(sc, &sc->gpio_pins[i], DEFAULT_CAPS); 429213239Sgonzo i++; 430213239Sgonzo } 431213239Sgonzo sc->gpio_npins = i; 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 } 437213239Sgonzo device_add_child(dev, "gpioc", device_get_unit(dev)); 438213239Sgonzo device_add_child(dev, "gpiobus", device_get_unit(dev)); 439213239Sgonzo return (bus_generic_attach(dev)); 440213239Sgonzo} 441213239Sgonzo 442213239Sgonzostatic int 443213239Sgonzoar71xx_gpio_detach(device_t dev) 444213239Sgonzo{ 445213239Sgonzo struct ar71xx_gpio_softc *sc = device_get_softc(dev); 446213239Sgonzo 447213239Sgonzo KASSERT(mtx_initialized(&sc->gpio_mtx), ("gpio mutex not initialized")); 448213239Sgonzo 449213286Sgonzo ar71xx_gpio_function_disable(sc, GPIO_FUNC_SPI_CS1_EN); 450213286Sgonzo ar71xx_gpio_function_disable(sc, GPIO_FUNC_SPI_CS2_EN); 451213239Sgonzo bus_generic_detach(dev); 452213239Sgonzo 453213239Sgonzo if (sc->gpio_mem_res) 454213239Sgonzo bus_release_resource(dev, SYS_RES_MEMORY, sc->gpio_mem_rid, 455213239Sgonzo sc->gpio_mem_res); 456213239Sgonzo 457213239Sgonzo mtx_destroy(&sc->gpio_mtx); 458213239Sgonzo 459213239Sgonzo return(0); 460213239Sgonzo} 461213239Sgonzo 462213239Sgonzostatic device_method_t ar71xx_gpio_methods[] = { 463213239Sgonzo DEVMETHOD(device_probe, ar71xx_gpio_probe), 464213239Sgonzo DEVMETHOD(device_attach, ar71xx_gpio_attach), 465213239Sgonzo DEVMETHOD(device_detach, ar71xx_gpio_detach), 466213239Sgonzo 467213239Sgonzo /* GPIO protocol */ 468213239Sgonzo DEVMETHOD(gpio_pin_max, ar71xx_gpio_pin_max), 469213239Sgonzo DEVMETHOD(gpio_pin_getname, ar71xx_gpio_pin_getname), 470213239Sgonzo DEVMETHOD(gpio_pin_getflags, ar71xx_gpio_pin_getflags), 471213239Sgonzo DEVMETHOD(gpio_pin_getcaps, ar71xx_gpio_pin_getcaps), 472213239Sgonzo DEVMETHOD(gpio_pin_setflags, ar71xx_gpio_pin_setflags), 473213239Sgonzo DEVMETHOD(gpio_pin_get, ar71xx_gpio_pin_get), 474213239Sgonzo DEVMETHOD(gpio_pin_set, ar71xx_gpio_pin_set), 475213239Sgonzo DEVMETHOD(gpio_pin_toggle, ar71xx_gpio_pin_toggle), 476213239Sgonzo {0, 0}, 477213239Sgonzo}; 478213239Sgonzo 479213239Sgonzostatic driver_t ar71xx_gpio_driver = { 480213239Sgonzo "gpio", 481213239Sgonzo ar71xx_gpio_methods, 482213239Sgonzo sizeof(struct ar71xx_gpio_softc), 483213239Sgonzo}; 484213239Sgonzostatic devclass_t ar71xx_gpio_devclass; 485213239Sgonzo 486213239SgonzoDRIVER_MODULE(ar71xx_gpio, apb, ar71xx_gpio_driver, ar71xx_gpio_devclass, 0, 0); 487