1e53470feSOleksandr Tymoshenko /*- 23681c8d7SLuiz Otavio O Souza * Copyright (c) 2011 Ben Gray <ben.r.gray@gmail.com>. 33681c8d7SLuiz Otavio O Souza * Copyright (c) 2014 Luiz Otavio O Souza <loos@FreeBSD.org>. 4e53470feSOleksandr Tymoshenko * All rights reserved. 5e53470feSOleksandr Tymoshenko * 6e53470feSOleksandr Tymoshenko * Redistribution and use in source and binary forms, with or without 7e53470feSOleksandr Tymoshenko * modification, are permitted provided that the following conditions 8e53470feSOleksandr Tymoshenko * are met: 9e53470feSOleksandr Tymoshenko * 1. Redistributions of source code must retain the above copyright 10e53470feSOleksandr Tymoshenko * notice, this list of conditions and the following disclaimer. 11e53470feSOleksandr Tymoshenko * 2. Redistributions in binary form must reproduce the above copyright 12e53470feSOleksandr Tymoshenko * notice, this list of conditions and the following disclaimer in the 13e53470feSOleksandr Tymoshenko * documentation and/or other materials provided with the distribution. 14e53470feSOleksandr Tymoshenko * 15e53470feSOleksandr Tymoshenko * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16e53470feSOleksandr Tymoshenko * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17e53470feSOleksandr Tymoshenko * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18e53470feSOleksandr Tymoshenko * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 19e53470feSOleksandr Tymoshenko * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20e53470feSOleksandr Tymoshenko * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21e53470feSOleksandr Tymoshenko * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22e53470feSOleksandr Tymoshenko * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23e53470feSOleksandr Tymoshenko * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24e53470feSOleksandr Tymoshenko * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25e53470feSOleksandr Tymoshenko * SUCH DAMAGE. 26e53470feSOleksandr Tymoshenko */ 27e53470feSOleksandr Tymoshenko 28e53470feSOleksandr Tymoshenko /** 293681c8d7SLuiz Otavio O Souza * Beware that the OMAP4 datasheet(s) lists GPIO banks 1-6, whereas the code 303681c8d7SLuiz Otavio O Souza * here uses 0-5. 31e53470feSOleksandr Tymoshenko */ 32e53470feSOleksandr Tymoshenko 33e53470feSOleksandr Tymoshenko #include <sys/cdefs.h> 34e53470feSOleksandr Tymoshenko __FBSDID("$FreeBSD$"); 35e53470feSOleksandr Tymoshenko 36*2df5562dSSvatopluk Kraus #include "opt_platform.h" 37*2df5562dSSvatopluk Kraus 38e53470feSOleksandr Tymoshenko #include <sys/param.h> 39e53470feSOleksandr Tymoshenko #include <sys/systm.h> 40e53470feSOleksandr Tymoshenko #include <sys/bus.h> 41e53470feSOleksandr Tymoshenko 42e53470feSOleksandr Tymoshenko #include <sys/kernel.h> 43e53470feSOleksandr Tymoshenko #include <sys/module.h> 44*2df5562dSSvatopluk Kraus #include <sys/proc.h> 45e53470feSOleksandr Tymoshenko #include <sys/rman.h> 46e53470feSOleksandr Tymoshenko #include <sys/lock.h> 47e53470feSOleksandr Tymoshenko #include <sys/mutex.h> 48e53470feSOleksandr Tymoshenko #include <sys/gpio.h> 493681c8d7SLuiz Otavio O Souza #include <sys/interrupt.h> 50e53470feSOleksandr Tymoshenko 51e53470feSOleksandr Tymoshenko #include <machine/bus.h> 52*2df5562dSSvatopluk Kraus #include <machine/intr.h> 53e53470feSOleksandr Tymoshenko #include <machine/resource.h> 54e53470feSOleksandr Tymoshenko 554eb12144SAndrew Turner #include <arm/ti/ti_cpuid.h> 56b6c7dacfSAndrew Turner #include <arm/ti/ti_gpio.h> 57e53470feSOleksandr Tymoshenko #include <arm/ti/ti_scm.h> 58e53470feSOleksandr Tymoshenko #include <arm/ti/ti_prcm.h> 595b03aba6SOleksandr Tymoshenko #include <arm/ti/ti_hwmods.h> 60e53470feSOleksandr Tymoshenko 61e53470feSOleksandr Tymoshenko #include <dev/fdt/fdt_common.h> 627836352bSLuiz Otavio O Souza #include <dev/gpio/gpiobusvar.h> 63e53470feSOleksandr Tymoshenko #include <dev/ofw/openfirm.h> 64e53470feSOleksandr Tymoshenko #include <dev/ofw/ofw_bus.h> 65e53470feSOleksandr Tymoshenko #include <dev/ofw/ofw_bus_subr.h> 66e53470feSOleksandr Tymoshenko 67e53470feSOleksandr Tymoshenko #include "gpio_if.h" 68b6c7dacfSAndrew Turner #include "ti_gpio_if.h" 69*2df5562dSSvatopluk Kraus #ifdef ARM_INTRNG 70*2df5562dSSvatopluk Kraus #include "pic_if.h" 71*2df5562dSSvatopluk Kraus #endif 72e53470feSOleksandr Tymoshenko 73a59806b2SLuiz Otavio O Souza #if !defined(SOC_OMAP4) && !defined(SOC_TI_AM335X) 74a59806b2SLuiz Otavio O Souza #error "Unknown SoC" 75a59806b2SLuiz Otavio O Souza #endif 76a59806b2SLuiz Otavio O Souza 77e53470feSOleksandr Tymoshenko /* Register definitions */ 78e53470feSOleksandr Tymoshenko #define TI_GPIO_REVISION 0x0000 79e53470feSOleksandr Tymoshenko #define TI_GPIO_SYSCONFIG 0x0010 80e53470feSOleksandr Tymoshenko #define TI_GPIO_IRQSTATUS_RAW_0 0x0024 81e53470feSOleksandr Tymoshenko #define TI_GPIO_IRQSTATUS_RAW_1 0x0028 82*2df5562dSSvatopluk Kraus #define TI_GPIO_IRQSTATUS_0 0x002C /* writing a 0 has no effect */ 83*2df5562dSSvatopluk Kraus #define TI_GPIO_IRQSTATUS_1 0x0030 /* writing a 0 has no effect */ 84*2df5562dSSvatopluk Kraus #define TI_GPIO_IRQSTATUS_SET_0 0x0034 /* writing a 0 has no effect */ 85*2df5562dSSvatopluk Kraus #define TI_GPIO_IRQSTATUS_SET_1 0x0038 /* writing a 0 has no effect */ 86*2df5562dSSvatopluk Kraus #define TI_GPIO_IRQSTATUS_CLR_0 0x003C /* writing a 0 has no effect */ 87*2df5562dSSvatopluk Kraus #define TI_GPIO_IRQSTATUS_CLR_1 0x0040 /* writing a 0 has no effect */ 88e53470feSOleksandr Tymoshenko #define TI_GPIO_IRQWAKEN_0 0x0044 89e53470feSOleksandr Tymoshenko #define TI_GPIO_IRQWAKEN_1 0x0048 90e53470feSOleksandr Tymoshenko #define TI_GPIO_SYSSTATUS 0x0114 91e53470feSOleksandr Tymoshenko #define TI_GPIO_IRQSTATUS1 0x0118 92e53470feSOleksandr Tymoshenko #define TI_GPIO_IRQENABLE1 0x011C 93e53470feSOleksandr Tymoshenko #define TI_GPIO_WAKEUPENABLE 0x0120 94e53470feSOleksandr Tymoshenko #define TI_GPIO_IRQSTATUS2 0x0128 95e53470feSOleksandr Tymoshenko #define TI_GPIO_IRQENABLE2 0x012C 96e53470feSOleksandr Tymoshenko #define TI_GPIO_CTRL 0x0130 97e53470feSOleksandr Tymoshenko #define TI_GPIO_OE 0x0134 98e53470feSOleksandr Tymoshenko #define TI_GPIO_DATAIN 0x0138 99e53470feSOleksandr Tymoshenko #define TI_GPIO_DATAOUT 0x013C 100*2df5562dSSvatopluk Kraus #define TI_GPIO_LEVELDETECT0 0x0140 /* RW register */ 101*2df5562dSSvatopluk Kraus #define TI_GPIO_LEVELDETECT1 0x0144 /* RW register */ 102*2df5562dSSvatopluk Kraus #define TI_GPIO_RISINGDETECT 0x0148 /* RW register */ 103*2df5562dSSvatopluk Kraus #define TI_GPIO_FALLINGDETECT 0x014C /* RW register */ 104e53470feSOleksandr Tymoshenko #define TI_GPIO_DEBOUNCENABLE 0x0150 105e53470feSOleksandr Tymoshenko #define TI_GPIO_DEBOUNCINGTIME 0x0154 106e53470feSOleksandr Tymoshenko #define TI_GPIO_CLEARWKUPENA 0x0180 107e53470feSOleksandr Tymoshenko #define TI_GPIO_SETWKUENA 0x0184 108e53470feSOleksandr Tymoshenko #define TI_GPIO_CLEARDATAOUT 0x0190 109e53470feSOleksandr Tymoshenko #define TI_GPIO_SETDATAOUT 0x0194 110e53470feSOleksandr Tymoshenko 111e53470feSOleksandr Tymoshenko /* Other SoC Specific definitions */ 1124eb12144SAndrew Turner #define OMAP4_FIRST_GPIO_BANK 1 1134eb12144SAndrew Turner #define OMAP4_INTR_PER_BANK 1 1144eb12144SAndrew Turner #define OMAP4_GPIO_REV 0x50600801 1154eb12144SAndrew Turner #define AM335X_FIRST_GPIO_BANK 0 1164eb12144SAndrew Turner #define AM335X_INTR_PER_BANK 2 1174eb12144SAndrew Turner #define AM335X_GPIO_REV 0x50600801 118ff5823beSLuiz Otavio O Souza #define PINS_PER_BANK 32 119e350f76cSLuiz Otavio O Souza #define TI_GPIO_MASK(p) (1U << ((p) % PINS_PER_BANK)) 1204eb12144SAndrew Turner 121*2df5562dSSvatopluk Kraus static int ti_gpio_intr(void *arg); 122876c1bd8SLuiz Otavio O Souza static int ti_gpio_detach(device_t); 1233681c8d7SLuiz Otavio O Souza 124*2df5562dSSvatopluk Kraus #ifdef ARM_INTRNG 125*2df5562dSSvatopluk Kraus static int ti_gpio_pic_attach(struct ti_gpio_softc *sc); 126*2df5562dSSvatopluk Kraus static int ti_gpio_pic_detach(struct ti_gpio_softc *sc); 127*2df5562dSSvatopluk Kraus #endif 128*2df5562dSSvatopluk Kraus 1294eb12144SAndrew Turner static u_int 1304eb12144SAndrew Turner ti_first_gpio_bank(void) 1314eb12144SAndrew Turner { 1324eb12144SAndrew Turner switch(ti_chip()) { 1334eb12144SAndrew Turner #ifdef SOC_OMAP4 1344eb12144SAndrew Turner case CHIP_OMAP_4: 1354eb12144SAndrew Turner return (OMAP4_FIRST_GPIO_BANK); 1364eb12144SAndrew Turner #endif 1374eb12144SAndrew Turner #ifdef SOC_TI_AM335X 1384eb12144SAndrew Turner case CHIP_AM335X: 1394eb12144SAndrew Turner return (AM335X_FIRST_GPIO_BANK); 1404eb12144SAndrew Turner #endif 1414eb12144SAndrew Turner } 1424eb12144SAndrew Turner return (0); 1434eb12144SAndrew Turner } 1444eb12144SAndrew Turner 1454eb12144SAndrew Turner static uint32_t 1464eb12144SAndrew Turner ti_gpio_rev(void) 1474eb12144SAndrew Turner { 1484eb12144SAndrew Turner switch(ti_chip()) { 1494eb12144SAndrew Turner #ifdef SOC_OMAP4 1504eb12144SAndrew Turner case CHIP_OMAP_4: 1514eb12144SAndrew Turner return (OMAP4_GPIO_REV); 1524eb12144SAndrew Turner #endif 1534eb12144SAndrew Turner #ifdef SOC_TI_AM335X 1544eb12144SAndrew Turner case CHIP_AM335X: 1554eb12144SAndrew Turner return (AM335X_GPIO_REV); 1564eb12144SAndrew Turner #endif 1574eb12144SAndrew Turner } 1584eb12144SAndrew Turner return (0); 1594eb12144SAndrew Turner } 160e53470feSOleksandr Tymoshenko 161e53470feSOleksandr Tymoshenko /** 162e53470feSOleksandr Tymoshenko * Macros for driver mutex locking 163e53470feSOleksandr Tymoshenko */ 1643681c8d7SLuiz Otavio O Souza #define TI_GPIO_LOCK(_sc) mtx_lock_spin(&(_sc)->sc_mtx) 1653681c8d7SLuiz Otavio O Souza #define TI_GPIO_UNLOCK(_sc) mtx_unlock_spin(&(_sc)->sc_mtx) 166e53470feSOleksandr Tymoshenko #define TI_GPIO_LOCK_INIT(_sc) \ 1673681c8d7SLuiz Otavio O Souza mtx_init(&_sc->sc_mtx, device_get_nameunit((_sc)->sc_dev), \ 1683681c8d7SLuiz Otavio O Souza "ti_gpio", MTX_SPIN) 1693681c8d7SLuiz Otavio O Souza #define TI_GPIO_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_mtx) 1703681c8d7SLuiz Otavio O Souza #define TI_GPIO_ASSERT_LOCKED(_sc) mtx_assert(&(_sc)->sc_mtx, MA_OWNED) 1713681c8d7SLuiz Otavio O Souza #define TI_GPIO_ASSERT_UNLOCKED(_sc) mtx_assert(&(_sc)->sc_mtx, MA_NOTOWNED) 172e53470feSOleksandr Tymoshenko 173e53470feSOleksandr Tymoshenko /** 174e350f76cSLuiz Otavio O Souza * ti_gpio_read_4 - reads a 32-bit value from one of the GPIO registers 175e53470feSOleksandr Tymoshenko * @sc: GPIO device context 176e53470feSOleksandr Tymoshenko * @bank: The bank to read from 177e53470feSOleksandr Tymoshenko * @off: The offset of a register from the GPIO register address range 178e53470feSOleksandr Tymoshenko * 179e53470feSOleksandr Tymoshenko * 180e53470feSOleksandr Tymoshenko * RETURNS: 181e53470feSOleksandr Tymoshenko * 32-bit value read from the register. 182e53470feSOleksandr Tymoshenko */ 183e53470feSOleksandr Tymoshenko static inline uint32_t 1845b03aba6SOleksandr Tymoshenko ti_gpio_read_4(struct ti_gpio_softc *sc, bus_size_t off) 185e53470feSOleksandr Tymoshenko { 1865b03aba6SOleksandr Tymoshenko return (bus_read_4(sc->sc_mem_res, off)); 187e53470feSOleksandr Tymoshenko } 188e53470feSOleksandr Tymoshenko 189e53470feSOleksandr Tymoshenko /** 190e350f76cSLuiz Otavio O Souza * ti_gpio_write_4 - writes a 32-bit value to one of the GPIO registers 191e53470feSOleksandr Tymoshenko * @sc: GPIO device context 192e53470feSOleksandr Tymoshenko * @bank: The bank to write to 193e53470feSOleksandr Tymoshenko * @off: The offset of a register from the GPIO register address range 194e53470feSOleksandr Tymoshenko * @val: The value to write into the register 195e53470feSOleksandr Tymoshenko * 196e53470feSOleksandr Tymoshenko * RETURNS: 197e53470feSOleksandr Tymoshenko * nothing 198e53470feSOleksandr Tymoshenko */ 199e53470feSOleksandr Tymoshenko static inline void 2005b03aba6SOleksandr Tymoshenko ti_gpio_write_4(struct ti_gpio_softc *sc, bus_size_t off, 201e53470feSOleksandr Tymoshenko uint32_t val) 202e53470feSOleksandr Tymoshenko { 2035b03aba6SOleksandr Tymoshenko bus_write_4(sc->sc_mem_res, off, val); 204e53470feSOleksandr Tymoshenko } 205e53470feSOleksandr Tymoshenko 206db8a14ecSLuiz Otavio O Souza static inline void 2075b03aba6SOleksandr Tymoshenko ti_gpio_intr_clr(struct ti_gpio_softc *sc, uint32_t mask) 208db8a14ecSLuiz Otavio O Souza { 209db8a14ecSLuiz Otavio O Souza 210db8a14ecSLuiz Otavio O Souza /* We clear both set of registers. */ 2115b03aba6SOleksandr Tymoshenko ti_gpio_write_4(sc, TI_GPIO_IRQSTATUS_CLR_0, mask); 2125b03aba6SOleksandr Tymoshenko ti_gpio_write_4(sc, TI_GPIO_IRQSTATUS_CLR_1, mask); 213db8a14ecSLuiz Otavio O Souza } 214db8a14ecSLuiz Otavio O Souza 2153681c8d7SLuiz Otavio O Souza static inline void 2165b03aba6SOleksandr Tymoshenko ti_gpio_intr_set(struct ti_gpio_softc *sc, uint32_t mask) 2173681c8d7SLuiz Otavio O Souza { 2183681c8d7SLuiz Otavio O Souza 2193681c8d7SLuiz Otavio O Souza /* 2203681c8d7SLuiz Otavio O Souza * On OMAP4 we unmask only the MPU interrupt and on AM335x we 2213681c8d7SLuiz Otavio O Souza * also activate only the first interrupt. 2223681c8d7SLuiz Otavio O Souza */ 2235b03aba6SOleksandr Tymoshenko ti_gpio_write_4(sc, TI_GPIO_IRQSTATUS_SET_0, mask); 2243681c8d7SLuiz Otavio O Souza } 2253681c8d7SLuiz Otavio O Souza 2263681c8d7SLuiz Otavio O Souza static inline void 2275b03aba6SOleksandr Tymoshenko ti_gpio_intr_ack(struct ti_gpio_softc *sc, uint32_t mask) 2283681c8d7SLuiz Otavio O Souza { 2293681c8d7SLuiz Otavio O Souza 2303681c8d7SLuiz Otavio O Souza /* 2313681c8d7SLuiz Otavio O Souza * Acknowledge the interrupt on both registers even if we use only 2323681c8d7SLuiz Otavio O Souza * the first one. 2333681c8d7SLuiz Otavio O Souza */ 2345b03aba6SOleksandr Tymoshenko ti_gpio_write_4(sc, TI_GPIO_IRQSTATUS_0, mask); 2355b03aba6SOleksandr Tymoshenko ti_gpio_write_4(sc, TI_GPIO_IRQSTATUS_1, mask); 2363681c8d7SLuiz Otavio O Souza } 2373681c8d7SLuiz Otavio O Souza 2383681c8d7SLuiz Otavio O Souza static inline uint32_t 2395b03aba6SOleksandr Tymoshenko ti_gpio_intr_status(struct ti_gpio_softc *sc) 2403681c8d7SLuiz Otavio O Souza { 2413681c8d7SLuiz Otavio O Souza uint32_t reg; 2423681c8d7SLuiz Otavio O Souza 2433681c8d7SLuiz Otavio O Souza /* Get the status from both registers. */ 2445b03aba6SOleksandr Tymoshenko reg = ti_gpio_read_4(sc, TI_GPIO_IRQSTATUS_0); 2455b03aba6SOleksandr Tymoshenko reg |= ti_gpio_read_4(sc, TI_GPIO_IRQSTATUS_1); 2463681c8d7SLuiz Otavio O Souza 2473681c8d7SLuiz Otavio O Souza return (reg); 2483681c8d7SLuiz Otavio O Souza } 2493681c8d7SLuiz Otavio O Souza 2507836352bSLuiz Otavio O Souza static device_t 2517836352bSLuiz Otavio O Souza ti_gpio_get_bus(device_t dev) 2527836352bSLuiz Otavio O Souza { 2537836352bSLuiz Otavio O Souza struct ti_gpio_softc *sc; 2547836352bSLuiz Otavio O Souza 2557836352bSLuiz Otavio O Souza sc = device_get_softc(dev); 2567836352bSLuiz Otavio O Souza 2577836352bSLuiz Otavio O Souza return (sc->sc_busdev); 2587836352bSLuiz Otavio O Souza } 2597836352bSLuiz Otavio O Souza 260e53470feSOleksandr Tymoshenko /** 261e53470feSOleksandr Tymoshenko * ti_gpio_pin_max - Returns the maximum number of GPIO pins 262e53470feSOleksandr Tymoshenko * @dev: gpio device handle 263e53470feSOleksandr Tymoshenko * @maxpin: pointer to a value that upon return will contain the maximum number 264e53470feSOleksandr Tymoshenko * of pins in the device. 265e53470feSOleksandr Tymoshenko * 266e53470feSOleksandr Tymoshenko * 267e53470feSOleksandr Tymoshenko * LOCKING: 268f9de33d4SLuiz Otavio O Souza * No locking required, returns static data. 269e53470feSOleksandr Tymoshenko * 270e53470feSOleksandr Tymoshenko * RETURNS: 271e53470feSOleksandr Tymoshenko * Returns 0 on success otherwise an error code 272e53470feSOleksandr Tymoshenko */ 273e53470feSOleksandr Tymoshenko static int 274e53470feSOleksandr Tymoshenko ti_gpio_pin_max(device_t dev, int *maxpin) 275e53470feSOleksandr Tymoshenko { 276e53470feSOleksandr Tymoshenko 2775b03aba6SOleksandr Tymoshenko *maxpin = PINS_PER_BANK - 1; 278e53470feSOleksandr Tymoshenko 279e53470feSOleksandr Tymoshenko return (0); 280e53470feSOleksandr Tymoshenko } 281e53470feSOleksandr Tymoshenko 282e350f76cSLuiz Otavio O Souza static int 283e350f76cSLuiz Otavio O Souza ti_gpio_valid_pin(struct ti_gpio_softc *sc, int pin) 284e350f76cSLuiz Otavio O Souza { 285e350f76cSLuiz Otavio O Souza 2865b03aba6SOleksandr Tymoshenko if (pin >= sc->sc_maxpin || sc->sc_mem_res == NULL) 287e350f76cSLuiz Otavio O Souza return (EINVAL); 288e350f76cSLuiz Otavio O Souza 289e350f76cSLuiz Otavio O Souza return (0); 290e350f76cSLuiz Otavio O Souza } 291e350f76cSLuiz Otavio O Souza 292e53470feSOleksandr Tymoshenko /** 293e53470feSOleksandr Tymoshenko * ti_gpio_pin_getcaps - Gets the capabilties of a given pin 294e53470feSOleksandr Tymoshenko * @dev: gpio device handle 295e53470feSOleksandr Tymoshenko * @pin: the number of the pin 296e53470feSOleksandr Tymoshenko * @caps: pointer to a value that upon return will contain the capabilities 297e53470feSOleksandr Tymoshenko * 298e53470feSOleksandr Tymoshenko * Currently all pins have the same capability, notably: 299e53470feSOleksandr Tymoshenko * - GPIO_PIN_INPUT 300e53470feSOleksandr Tymoshenko * - GPIO_PIN_OUTPUT 301e53470feSOleksandr Tymoshenko * - GPIO_PIN_PULLUP 302e53470feSOleksandr Tymoshenko * - GPIO_PIN_PULLDOWN 303e53470feSOleksandr Tymoshenko * 304e53470feSOleksandr Tymoshenko * LOCKING: 305f9de33d4SLuiz Otavio O Souza * No locking required, returns static data. 306e53470feSOleksandr Tymoshenko * 307e53470feSOleksandr Tymoshenko * RETURNS: 308e53470feSOleksandr Tymoshenko * Returns 0 on success otherwise an error code 309e53470feSOleksandr Tymoshenko */ 310e53470feSOleksandr Tymoshenko static int 311e53470feSOleksandr Tymoshenko ti_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) 312e53470feSOleksandr Tymoshenko { 313e350f76cSLuiz Otavio O Souza struct ti_gpio_softc *sc; 314e53470feSOleksandr Tymoshenko 315e350f76cSLuiz Otavio O Souza sc = device_get_softc(dev); 316e350f76cSLuiz Otavio O Souza if (ti_gpio_valid_pin(sc, pin) != 0) 317e53470feSOleksandr Tymoshenko return (EINVAL); 318e53470feSOleksandr Tymoshenko 319e53470feSOleksandr Tymoshenko *caps = (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_PULLUP | 320e53470feSOleksandr Tymoshenko GPIO_PIN_PULLDOWN); 321e53470feSOleksandr Tymoshenko 322e53470feSOleksandr Tymoshenko return (0); 323e53470feSOleksandr Tymoshenko } 324e53470feSOleksandr Tymoshenko 325e53470feSOleksandr Tymoshenko /** 326e53470feSOleksandr Tymoshenko * ti_gpio_pin_getflags - Gets the current flags of a given pin 327e53470feSOleksandr Tymoshenko * @dev: gpio device handle 328e53470feSOleksandr Tymoshenko * @pin: the number of the pin 329e53470feSOleksandr Tymoshenko * @flags: upon return will contain the current flags of the pin 330e53470feSOleksandr Tymoshenko * 331e53470feSOleksandr Tymoshenko * Reads the current flags of a given pin, here we actually read the H/W 332e53470feSOleksandr Tymoshenko * registers to determine the flags, rather than storing the value in the 333e53470feSOleksandr Tymoshenko * setflags call. 334e53470feSOleksandr Tymoshenko * 335e53470feSOleksandr Tymoshenko * LOCKING: 336e53470feSOleksandr Tymoshenko * Internally locks the context 337e53470feSOleksandr Tymoshenko * 338e53470feSOleksandr Tymoshenko * RETURNS: 339e53470feSOleksandr Tymoshenko * Returns 0 on success otherwise an error code 340e53470feSOleksandr Tymoshenko */ 341e53470feSOleksandr Tymoshenko static int 342e53470feSOleksandr Tymoshenko ti_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) 343e53470feSOleksandr Tymoshenko { 344e350f76cSLuiz Otavio O Souza struct ti_gpio_softc *sc; 345e53470feSOleksandr Tymoshenko 346e350f76cSLuiz Otavio O Souza sc = device_get_softc(dev); 347e350f76cSLuiz Otavio O Souza if (ti_gpio_valid_pin(sc, pin) != 0) 348e53470feSOleksandr Tymoshenko return (EINVAL); 349e53470feSOleksandr Tymoshenko 350e53470feSOleksandr Tymoshenko /* Get the current pin state */ 351f9de33d4SLuiz Otavio O Souza TI_GPIO_LOCK(sc); 352b6c7dacfSAndrew Turner TI_GPIO_GET_FLAGS(dev, pin, flags); 353e53470feSOleksandr Tymoshenko TI_GPIO_UNLOCK(sc); 354e53470feSOleksandr Tymoshenko 355e53470feSOleksandr Tymoshenko return (0); 356e53470feSOleksandr Tymoshenko } 357e53470feSOleksandr Tymoshenko 358e53470feSOleksandr Tymoshenko /** 359e53470feSOleksandr Tymoshenko * ti_gpio_pin_getname - Gets the name of a given pin 360e53470feSOleksandr Tymoshenko * @dev: gpio device handle 361e53470feSOleksandr Tymoshenko * @pin: the number of the pin 362e53470feSOleksandr Tymoshenko * @name: buffer to put the name in 363e53470feSOleksandr Tymoshenko * 364e53470feSOleksandr Tymoshenko * The driver simply calls the pins gpio_n, where 'n' is obviously the number 365e53470feSOleksandr Tymoshenko * of the pin. 366e53470feSOleksandr Tymoshenko * 367e53470feSOleksandr Tymoshenko * LOCKING: 368f9de33d4SLuiz Otavio O Souza * No locking required, returns static data. 369e53470feSOleksandr Tymoshenko * 370e53470feSOleksandr Tymoshenko * RETURNS: 371e53470feSOleksandr Tymoshenko * Returns 0 on success otherwise an error code 372e53470feSOleksandr Tymoshenko */ 373e53470feSOleksandr Tymoshenko static int 374e53470feSOleksandr Tymoshenko ti_gpio_pin_getname(device_t dev, uint32_t pin, char *name) 375e53470feSOleksandr Tymoshenko { 376e350f76cSLuiz Otavio O Souza struct ti_gpio_softc *sc; 377e53470feSOleksandr Tymoshenko 378e350f76cSLuiz Otavio O Souza sc = device_get_softc(dev); 379e350f76cSLuiz Otavio O Souza if (ti_gpio_valid_pin(sc, pin) != 0) 380e53470feSOleksandr Tymoshenko return (EINVAL); 381e53470feSOleksandr Tymoshenko 382e53470feSOleksandr Tymoshenko /* Set a very simple name */ 383e53470feSOleksandr Tymoshenko snprintf(name, GPIOMAXNAME, "gpio_%u", pin); 384e53470feSOleksandr Tymoshenko name[GPIOMAXNAME - 1] = '\0'; 385e53470feSOleksandr Tymoshenko 386e53470feSOleksandr Tymoshenko return (0); 387e53470feSOleksandr Tymoshenko } 388e53470feSOleksandr Tymoshenko 389e53470feSOleksandr Tymoshenko /** 390e53470feSOleksandr Tymoshenko * ti_gpio_pin_setflags - Sets the flags for a given pin 391e53470feSOleksandr Tymoshenko * @dev: gpio device handle 392e53470feSOleksandr Tymoshenko * @pin: the number of the pin 393e53470feSOleksandr Tymoshenko * @flags: the flags to set 394e53470feSOleksandr Tymoshenko * 395e53470feSOleksandr Tymoshenko * The flags of the pin correspond to things like input/output mode, pull-ups, 396e53470feSOleksandr Tymoshenko * pull-downs, etc. This driver doesn't support all flags, only the following: 397e53470feSOleksandr Tymoshenko * - GPIO_PIN_INPUT 398e53470feSOleksandr Tymoshenko * - GPIO_PIN_OUTPUT 399e53470feSOleksandr Tymoshenko * - GPIO_PIN_PULLUP 400e53470feSOleksandr Tymoshenko * - GPIO_PIN_PULLDOWN 401e53470feSOleksandr Tymoshenko * 402e53470feSOleksandr Tymoshenko * LOCKING: 403e53470feSOleksandr Tymoshenko * Internally locks the context 404e53470feSOleksandr Tymoshenko * 405e53470feSOleksandr Tymoshenko * RETURNS: 406e53470feSOleksandr Tymoshenko * Returns 0 on success otherwise an error code 407e53470feSOleksandr Tymoshenko */ 408e53470feSOleksandr Tymoshenko static int 409e53470feSOleksandr Tymoshenko ti_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) 410e53470feSOleksandr Tymoshenko { 411e350f76cSLuiz Otavio O Souza struct ti_gpio_softc *sc; 412f9de33d4SLuiz Otavio O Souza uint32_t oe; 413e53470feSOleksandr Tymoshenko 414e350f76cSLuiz Otavio O Souza sc = device_get_softc(dev); 415e350f76cSLuiz Otavio O Souza if (ti_gpio_valid_pin(sc, pin) != 0) 416e53470feSOleksandr Tymoshenko return (EINVAL); 417e53470feSOleksandr Tymoshenko 418e53470feSOleksandr Tymoshenko /* Set the GPIO mode and state */ 419f9de33d4SLuiz Otavio O Souza TI_GPIO_LOCK(sc); 420b6c7dacfSAndrew Turner if (TI_GPIO_SET_FLAGS(dev, pin, flags) != 0) { 421e53470feSOleksandr Tymoshenko TI_GPIO_UNLOCK(sc); 422e53470feSOleksandr Tymoshenko return (EINVAL); 423e53470feSOleksandr Tymoshenko } 424e53470feSOleksandr Tymoshenko 425e53470feSOleksandr Tymoshenko /* If configuring as an output set the "output enable" bit */ 4265b03aba6SOleksandr Tymoshenko oe = ti_gpio_read_4(sc, TI_GPIO_OE); 427e53470feSOleksandr Tymoshenko if (flags & GPIO_PIN_INPUT) 428e350f76cSLuiz Otavio O Souza oe |= TI_GPIO_MASK(pin); 429e53470feSOleksandr Tymoshenko else 430e350f76cSLuiz Otavio O Souza oe &= ~TI_GPIO_MASK(pin); 4315b03aba6SOleksandr Tymoshenko ti_gpio_write_4(sc, TI_GPIO_OE, oe); 432e53470feSOleksandr Tymoshenko TI_GPIO_UNLOCK(sc); 433e53470feSOleksandr Tymoshenko 434e53470feSOleksandr Tymoshenko return (0); 435e53470feSOleksandr Tymoshenko } 436e53470feSOleksandr Tymoshenko 437e53470feSOleksandr Tymoshenko /** 438e53470feSOleksandr Tymoshenko * ti_gpio_pin_set - Sets the current level on a GPIO pin 439e53470feSOleksandr Tymoshenko * @dev: gpio device handle 440e53470feSOleksandr Tymoshenko * @pin: the number of the pin 441e53470feSOleksandr Tymoshenko * @value: non-zero value will drive the pin high, otherwise the pin is 442e53470feSOleksandr Tymoshenko * driven low. 443e53470feSOleksandr Tymoshenko * 444e53470feSOleksandr Tymoshenko * 445e53470feSOleksandr Tymoshenko * LOCKING: 446e53470feSOleksandr Tymoshenko * Internally locks the context 447e53470feSOleksandr Tymoshenko * 448e53470feSOleksandr Tymoshenko * RETURNS: 449e53470feSOleksandr Tymoshenko * Returns 0 on success otherwise a error code 450e53470feSOleksandr Tymoshenko */ 451e53470feSOleksandr Tymoshenko static int 452e53470feSOleksandr Tymoshenko ti_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value) 453e53470feSOleksandr Tymoshenko { 454e350f76cSLuiz Otavio O Souza struct ti_gpio_softc *sc; 455f9de33d4SLuiz Otavio O Souza uint32_t reg; 456e53470feSOleksandr Tymoshenko 457e350f76cSLuiz Otavio O Souza sc = device_get_softc(dev); 458e350f76cSLuiz Otavio O Souza if (ti_gpio_valid_pin(sc, pin) != 0) 459e53470feSOleksandr Tymoshenko return (EINVAL); 460e53470feSOleksandr Tymoshenko 461f9de33d4SLuiz Otavio O Souza TI_GPIO_LOCK(sc); 462f9de33d4SLuiz Otavio O Souza if (value == GPIO_PIN_LOW) 463f9de33d4SLuiz Otavio O Souza reg = TI_GPIO_CLEARDATAOUT; 464f9de33d4SLuiz Otavio O Souza else 465f9de33d4SLuiz Otavio O Souza reg = TI_GPIO_SETDATAOUT; 4665b03aba6SOleksandr Tymoshenko ti_gpio_write_4(sc, reg, TI_GPIO_MASK(pin)); 467e53470feSOleksandr Tymoshenko TI_GPIO_UNLOCK(sc); 468e53470feSOleksandr Tymoshenko 469e53470feSOleksandr Tymoshenko return (0); 470e53470feSOleksandr Tymoshenko } 471e53470feSOleksandr Tymoshenko 472e53470feSOleksandr Tymoshenko /** 473e53470feSOleksandr Tymoshenko * ti_gpio_pin_get - Gets the current level on a GPIO pin 474e53470feSOleksandr Tymoshenko * @dev: gpio device handle 475e53470feSOleksandr Tymoshenko * @pin: the number of the pin 476e53470feSOleksandr Tymoshenko * @value: pointer to a value that upond return will contain the pin value 477e53470feSOleksandr Tymoshenko * 478e53470feSOleksandr Tymoshenko * The pin must be configured as an input pin beforehand, otherwise this 479e53470feSOleksandr Tymoshenko * function will fail. 480e53470feSOleksandr Tymoshenko * 481e53470feSOleksandr Tymoshenko * LOCKING: 482e53470feSOleksandr Tymoshenko * Internally locks the context 483e53470feSOleksandr Tymoshenko * 484e53470feSOleksandr Tymoshenko * RETURNS: 485e53470feSOleksandr Tymoshenko * Returns 0 on success otherwise a error code 486e53470feSOleksandr Tymoshenko */ 487e53470feSOleksandr Tymoshenko static int 488e53470feSOleksandr Tymoshenko ti_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *value) 489e53470feSOleksandr Tymoshenko { 490e350f76cSLuiz Otavio O Souza struct ti_gpio_softc *sc; 491e350f76cSLuiz Otavio O Souza uint32_t oe, reg, val; 492e53470feSOleksandr Tymoshenko 493e350f76cSLuiz Otavio O Souza sc = device_get_softc(dev); 494e350f76cSLuiz Otavio O Souza if (ti_gpio_valid_pin(sc, pin) != 0) 495e53470feSOleksandr Tymoshenko return (EINVAL); 496e53470feSOleksandr Tymoshenko 497f9de33d4SLuiz Otavio O Souza /* 498f9de33d4SLuiz Otavio O Souza * Return data from output latch when set as output and from the 499f9de33d4SLuiz Otavio O Souza * input register otherwise. 500f9de33d4SLuiz Otavio O Souza */ 501f9de33d4SLuiz Otavio O Souza TI_GPIO_LOCK(sc); 5025b03aba6SOleksandr Tymoshenko oe = ti_gpio_read_4(sc, TI_GPIO_OE); 503e350f76cSLuiz Otavio O Souza if (oe & TI_GPIO_MASK(pin)) 504f9de33d4SLuiz Otavio O Souza reg = TI_GPIO_DATAIN; 5059f165184SLuiz Otavio O Souza else 506f9de33d4SLuiz Otavio O Souza reg = TI_GPIO_DATAOUT; 5075b03aba6SOleksandr Tymoshenko val = ti_gpio_read_4(sc, reg); 508e350f76cSLuiz Otavio O Souza *value = (val & TI_GPIO_MASK(pin)) ? 1 : 0; 509e53470feSOleksandr Tymoshenko TI_GPIO_UNLOCK(sc); 510e53470feSOleksandr Tymoshenko 511e53470feSOleksandr Tymoshenko return (0); 512e53470feSOleksandr Tymoshenko } 513e53470feSOleksandr Tymoshenko 514e53470feSOleksandr Tymoshenko /** 515e53470feSOleksandr Tymoshenko * ti_gpio_pin_toggle - Toggles a given GPIO pin 516e53470feSOleksandr Tymoshenko * @dev: gpio device handle 517e53470feSOleksandr Tymoshenko * @pin: the number of the pin 518e53470feSOleksandr Tymoshenko * 519e53470feSOleksandr Tymoshenko * 520e53470feSOleksandr Tymoshenko * LOCKING: 521e53470feSOleksandr Tymoshenko * Internally locks the context 522e53470feSOleksandr Tymoshenko * 523e53470feSOleksandr Tymoshenko * RETURNS: 524e53470feSOleksandr Tymoshenko * Returns 0 on success otherwise a error code 525e53470feSOleksandr Tymoshenko */ 526e53470feSOleksandr Tymoshenko static int 527e53470feSOleksandr Tymoshenko ti_gpio_pin_toggle(device_t dev, uint32_t pin) 528e53470feSOleksandr Tymoshenko { 529e350f76cSLuiz Otavio O Souza struct ti_gpio_softc *sc; 530f9de33d4SLuiz Otavio O Souza uint32_t reg, val; 531e53470feSOleksandr Tymoshenko 532e350f76cSLuiz Otavio O Souza sc = device_get_softc(dev); 533e350f76cSLuiz Otavio O Souza if (ti_gpio_valid_pin(sc, pin) != 0) 534e53470feSOleksandr Tymoshenko return (EINVAL); 535e53470feSOleksandr Tymoshenko 536e53470feSOleksandr Tymoshenko /* Toggle the pin */ 537f9de33d4SLuiz Otavio O Souza TI_GPIO_LOCK(sc); 5385b03aba6SOleksandr Tymoshenko val = ti_gpio_read_4(sc, TI_GPIO_DATAOUT); 539e350f76cSLuiz Otavio O Souza if (val & TI_GPIO_MASK(pin)) 540f9de33d4SLuiz Otavio O Souza reg = TI_GPIO_CLEARDATAOUT; 541e53470feSOleksandr Tymoshenko else 542f9de33d4SLuiz Otavio O Souza reg = TI_GPIO_SETDATAOUT; 5435b03aba6SOleksandr Tymoshenko ti_gpio_write_4(sc, reg, TI_GPIO_MASK(pin)); 544e53470feSOleksandr Tymoshenko TI_GPIO_UNLOCK(sc); 545e53470feSOleksandr Tymoshenko 546e53470feSOleksandr Tymoshenko return (0); 547e53470feSOleksandr Tymoshenko } 548e53470feSOleksandr Tymoshenko 549*2df5562dSSvatopluk Kraus #ifndef ARM_INTRNG 550e53470feSOleksandr Tymoshenko /** 551e53470feSOleksandr Tymoshenko * ti_gpio_intr - ISR for all GPIO modules 552e53470feSOleksandr Tymoshenko * @arg: the soft context pointer 553e53470feSOleksandr Tymoshenko * 554e53470feSOleksandr Tymoshenko * LOCKING: 555e53470feSOleksandr Tymoshenko * Internally locks the context 556e53470feSOleksandr Tymoshenko * 557e53470feSOleksandr Tymoshenko */ 5583681c8d7SLuiz Otavio O Souza static int 559e53470feSOleksandr Tymoshenko ti_gpio_intr(void *arg) 560e53470feSOleksandr Tymoshenko { 5613681c8d7SLuiz Otavio O Souza int bank_last, irq; 5623681c8d7SLuiz Otavio O Souza struct intr_event *event; 5633681c8d7SLuiz Otavio O Souza struct ti_gpio_softc *sc; 5643681c8d7SLuiz Otavio O Souza uint32_t reg; 565e53470feSOleksandr Tymoshenko 5663681c8d7SLuiz Otavio O Souza sc = (struct ti_gpio_softc *)arg; 5673681c8d7SLuiz Otavio O Souza bank_last = -1; 5682ed434b4SIan Lepore reg = 0; /* squelch bogus gcc warning */ 5695b03aba6SOleksandr Tymoshenko reg = ti_gpio_intr_status(sc); 5703681c8d7SLuiz Otavio O Souza for (irq = 0; irq < sc->sc_maxpin; irq++) { 5713681c8d7SLuiz Otavio O Souza if ((reg & TI_GPIO_MASK(irq)) == 0) 5723681c8d7SLuiz Otavio O Souza continue; 5733681c8d7SLuiz Otavio O Souza event = sc->sc_events[irq]; 5743681c8d7SLuiz Otavio O Souza if (event != NULL && !TAILQ_EMPTY(&event->ie_handlers)) 5753681c8d7SLuiz Otavio O Souza intr_event_handle(event, NULL); 5763681c8d7SLuiz Otavio O Souza else 5773681c8d7SLuiz Otavio O Souza device_printf(sc->sc_dev, "Stray IRQ %d\n", irq); 5783681c8d7SLuiz Otavio O Souza /* Ack the IRQ Status bit. */ 5795b03aba6SOleksandr Tymoshenko ti_gpio_intr_ack(sc, TI_GPIO_MASK(irq)); 5803681c8d7SLuiz Otavio O Souza } 5813681c8d7SLuiz Otavio O Souza 5823681c8d7SLuiz Otavio O Souza return (FILTER_HANDLED); 583e53470feSOleksandr Tymoshenko } 584*2df5562dSSvatopluk Kraus #endif 585e53470feSOleksandr Tymoshenko 5869b1cba84SLuiz Otavio O Souza static int 5875b03aba6SOleksandr Tymoshenko ti_gpio_bank_init(device_t dev) 5889b1cba84SLuiz Otavio O Souza { 5891f1e8f16SLuiz Otavio O Souza int pin; 5909b1cba84SLuiz Otavio O Souza struct ti_gpio_softc *sc; 591c3321180SOleksandr Tymoshenko uint32_t flags, reg_oe, reg_set, rev; 5925b03aba6SOleksandr Tymoshenko clk_ident_t clk; 5939b1cba84SLuiz Otavio O Souza 5949b1cba84SLuiz Otavio O Souza sc = device_get_softc(dev); 5959b1cba84SLuiz Otavio O Souza 5969b1cba84SLuiz Otavio O Souza /* Enable the interface and functional clocks for the module. */ 5975b03aba6SOleksandr Tymoshenko clk = ti_hwmods_get_clock(dev); 5985b03aba6SOleksandr Tymoshenko if (clk == INVALID_CLK_IDENT) { 5995b03aba6SOleksandr Tymoshenko device_printf(dev, "failed to get device id based on ti,hwmods\n"); 6005b03aba6SOleksandr Tymoshenko return (EINVAL); 6015b03aba6SOleksandr Tymoshenko } 6025b03aba6SOleksandr Tymoshenko 6035b03aba6SOleksandr Tymoshenko sc->sc_bank = clk - GPIO1_CLK + ti_first_gpio_bank(); 6045b03aba6SOleksandr Tymoshenko ti_prcm_clk_enable(clk); 6059b1cba84SLuiz Otavio O Souza 6069b1cba84SLuiz Otavio O Souza /* 6079b1cba84SLuiz Otavio O Souza * Read the revision number of the module. TI don't publish the 6089b1cba84SLuiz Otavio O Souza * actual revision numbers, so instead the values have been 6099b1cba84SLuiz Otavio O Souza * determined by experimentation. 6109b1cba84SLuiz Otavio O Souza */ 6115b03aba6SOleksandr Tymoshenko rev = ti_gpio_read_4(sc, TI_GPIO_REVISION); 6129b1cba84SLuiz Otavio O Souza 6139b1cba84SLuiz Otavio O Souza /* Check the revision. */ 614e350f76cSLuiz Otavio O Souza if (rev != ti_gpio_rev()) { 6159b1cba84SLuiz Otavio O Souza device_printf(dev, "Warning: could not determine the revision " 6165b03aba6SOleksandr Tymoshenko "of GPIO module (revision:0x%08x)\n", rev); 6179b1cba84SLuiz Otavio O Souza return (EINVAL); 6189b1cba84SLuiz Otavio O Souza } 6199b1cba84SLuiz Otavio O Souza 6209b1cba84SLuiz Otavio O Souza /* Disable interrupts for all pins. */ 6215b03aba6SOleksandr Tymoshenko ti_gpio_intr_clr(sc, 0xffffffff); 6229b1cba84SLuiz Otavio O Souza 6239b1cba84SLuiz Otavio O Souza /* Init OE register based on pads configuration. */ 6249b1cba84SLuiz Otavio O Souza reg_oe = 0xffffffff; 625c3321180SOleksandr Tymoshenko reg_set = 0; 6269b1cba84SLuiz Otavio O Souza for (pin = 0; pin < PINS_PER_BANK; pin++) { 6275b03aba6SOleksandr Tymoshenko TI_GPIO_GET_FLAGS(dev, pin, &flags); 628c3321180SOleksandr Tymoshenko if (flags & GPIO_PIN_OUTPUT) { 6299b1cba84SLuiz Otavio O Souza reg_oe &= ~(1UL << pin); 630c3321180SOleksandr Tymoshenko if (flags & GPIO_PIN_PULLUP) 631c3321180SOleksandr Tymoshenko reg_set |= (1UL << pin); 632c3321180SOleksandr Tymoshenko } 6339b1cba84SLuiz Otavio O Souza } 6345b03aba6SOleksandr Tymoshenko ti_gpio_write_4(sc, TI_GPIO_OE, reg_oe); 635c3321180SOleksandr Tymoshenko if (reg_set) 636c3321180SOleksandr Tymoshenko ti_gpio_write_4(sc, TI_GPIO_SETDATAOUT, reg_set); 6379b1cba84SLuiz Otavio O Souza 6389b1cba84SLuiz Otavio O Souza return (0); 6399b1cba84SLuiz Otavio O Souza } 6409b1cba84SLuiz Otavio O Souza 641e53470feSOleksandr Tymoshenko /** 642e53470feSOleksandr Tymoshenko * ti_gpio_attach - attach function for the driver 643e53470feSOleksandr Tymoshenko * @dev: gpio device handle 644e53470feSOleksandr Tymoshenko * 645e53470feSOleksandr Tymoshenko * Allocates and sets up the driver context for all GPIO banks. This function 646e53470feSOleksandr Tymoshenko * expects the memory ranges and IRQs to already be allocated to the driver. 647e53470feSOleksandr Tymoshenko * 648e53470feSOleksandr Tymoshenko * LOCKING: 649e53470feSOleksandr Tymoshenko * None 650e53470feSOleksandr Tymoshenko * 651e53470feSOleksandr Tymoshenko * RETURNS: 652e53470feSOleksandr Tymoshenko * Always returns 0 653e53470feSOleksandr Tymoshenko */ 654e53470feSOleksandr Tymoshenko static int 655e53470feSOleksandr Tymoshenko ti_gpio_attach(device_t dev) 656e53470feSOleksandr Tymoshenko { 6579b1cba84SLuiz Otavio O Souza struct ti_gpio_softc *sc; 658*2df5562dSSvatopluk Kraus #ifndef ARM_INTRNG 659e53470feSOleksandr Tymoshenko unsigned int i; 660*2df5562dSSvatopluk Kraus #endif 6619b1cba84SLuiz Otavio O Souza int err; 662e53470feSOleksandr Tymoshenko 6635b03aba6SOleksandr Tymoshenko sc = device_get_softc(dev); 664e53470feSOleksandr Tymoshenko sc->sc_dev = dev; 665e53470feSOleksandr Tymoshenko TI_GPIO_LOCK_INIT(sc); 666e350f76cSLuiz Otavio O Souza ti_gpio_pin_max(dev, &sc->sc_maxpin); 667f7f77280SLuiz Otavio O Souza sc->sc_maxpin++; 668e53470feSOleksandr Tymoshenko 6695b03aba6SOleksandr Tymoshenko sc->sc_mem_rid = 0; 6705b03aba6SOleksandr Tymoshenko sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 6715b03aba6SOleksandr Tymoshenko &sc->sc_mem_rid, RF_ACTIVE); 6725b03aba6SOleksandr Tymoshenko if (!sc->sc_mem_res) { 673e53470feSOleksandr Tymoshenko device_printf(dev, "Error: could not allocate mem resources\n"); 674876c1bd8SLuiz Otavio O Souza ti_gpio_detach(dev); 675e53470feSOleksandr Tymoshenko return (ENXIO); 676e53470feSOleksandr Tymoshenko } 677e53470feSOleksandr Tymoshenko 6785b03aba6SOleksandr Tymoshenko sc->sc_irq_rid = 0; 6795b03aba6SOleksandr Tymoshenko sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 6805b03aba6SOleksandr Tymoshenko &sc->sc_irq_rid, RF_ACTIVE); 6815b03aba6SOleksandr Tymoshenko if (!sc->sc_irq_res) { 682e53470feSOleksandr Tymoshenko device_printf(dev, "Error: could not allocate irq resources\n"); 683876c1bd8SLuiz Otavio O Souza ti_gpio_detach(dev); 684e53470feSOleksandr Tymoshenko return (ENXIO); 685e53470feSOleksandr Tymoshenko } 686e53470feSOleksandr Tymoshenko 6875b03aba6SOleksandr Tymoshenko /* 6885b03aba6SOleksandr Tymoshenko * Register our interrupt filter for each of the IRQ resources. 6895b03aba6SOleksandr Tymoshenko */ 6905b03aba6SOleksandr Tymoshenko if (bus_setup_intr(dev, sc->sc_irq_res, 6915b03aba6SOleksandr Tymoshenko INTR_TYPE_MISC | INTR_MPSAFE, ti_gpio_intr, NULL, sc, 6925b03aba6SOleksandr Tymoshenko &sc->sc_irq_hdl) != 0) { 6935b03aba6SOleksandr Tymoshenko device_printf(dev, 6945b03aba6SOleksandr Tymoshenko "WARNING: unable to register interrupt filter\n"); 695876c1bd8SLuiz Otavio O Souza ti_gpio_detach(dev); 696e53470feSOleksandr Tymoshenko return (ENXIO); 697e53470feSOleksandr Tymoshenko } 698e53470feSOleksandr Tymoshenko 699*2df5562dSSvatopluk Kraus #ifdef ARM_INTRNG 700*2df5562dSSvatopluk Kraus if (ti_gpio_pic_attach(sc) != 0) { 701*2df5562dSSvatopluk Kraus device_printf(dev, "WARNING: unable to attach PIC\n"); 702*2df5562dSSvatopluk Kraus ti_gpio_detach(dev); 703*2df5562dSSvatopluk Kraus return (ENXIO); 704*2df5562dSSvatopluk Kraus } 705*2df5562dSSvatopluk Kraus #else 7063681c8d7SLuiz Otavio O Souza /* 7073681c8d7SLuiz Otavio O Souza * Initialize the interrupt settings. The default is active-low 7083681c8d7SLuiz Otavio O Souza * interrupts. 7093681c8d7SLuiz Otavio O Souza */ 7103681c8d7SLuiz Otavio O Souza sc->sc_irq_trigger = malloc( 7113681c8d7SLuiz Otavio O Souza sizeof(*sc->sc_irq_trigger) * sc->sc_maxpin, 7123681c8d7SLuiz Otavio O Souza M_DEVBUF, M_WAITOK | M_ZERO); 7133681c8d7SLuiz Otavio O Souza sc->sc_irq_polarity = malloc( 7143681c8d7SLuiz Otavio O Souza sizeof(*sc->sc_irq_polarity) * sc->sc_maxpin, 7153681c8d7SLuiz Otavio O Souza M_DEVBUF, M_WAITOK | M_ZERO); 7163681c8d7SLuiz Otavio O Souza for (i = 0; i < sc->sc_maxpin; i++) { 7173681c8d7SLuiz Otavio O Souza sc->sc_irq_trigger[i] = INTR_TRIGGER_LEVEL; 7183681c8d7SLuiz Otavio O Souza sc->sc_irq_polarity[i] = INTR_POLARITY_LOW; 7193681c8d7SLuiz Otavio O Souza } 7203681c8d7SLuiz Otavio O Souza 7213681c8d7SLuiz Otavio O Souza sc->sc_events = malloc(sizeof(struct intr_event *) * sc->sc_maxpin, 7223681c8d7SLuiz Otavio O Souza M_DEVBUF, M_WAITOK | M_ZERO); 7233681c8d7SLuiz Otavio O Souza 7245b03aba6SOleksandr Tymoshenko sc->sc_mask_args = malloc(sizeof(struct ti_gpio_mask_arg) * sc->sc_maxpin, 7255b03aba6SOleksandr Tymoshenko M_DEVBUF, M_WAITOK | M_ZERO); 726*2df5562dSSvatopluk Kraus #endif 727e53470feSOleksandr Tymoshenko /* We need to go through each block and ensure the clocks are running and 728e53470feSOleksandr Tymoshenko * the module is enabled. It might be better to do this only when the 729e53470feSOleksandr Tymoshenko * pins are configured which would result in less power used if the GPIO 730e53470feSOleksandr Tymoshenko * pins weren't used ... 731e53470feSOleksandr Tymoshenko */ 7325b03aba6SOleksandr Tymoshenko if (sc->sc_mem_res != NULL) { 7331f1e8f16SLuiz Otavio O Souza /* Initialize the GPIO module. */ 7345b03aba6SOleksandr Tymoshenko err = ti_gpio_bank_init(dev); 7359b1cba84SLuiz Otavio O Souza if (err != 0) { 736876c1bd8SLuiz Otavio O Souza ti_gpio_detach(dev); 7379b1cba84SLuiz Otavio O Souza return (err); 738e53470feSOleksandr Tymoshenko } 739e53470feSOleksandr Tymoshenko } 7405b03aba6SOleksandr Tymoshenko 7417836352bSLuiz Otavio O Souza sc->sc_busdev = gpiobus_attach_bus(dev); 7427836352bSLuiz Otavio O Souza if (sc->sc_busdev == NULL) { 7437836352bSLuiz Otavio O Souza ti_gpio_detach(dev); 7447836352bSLuiz Otavio O Souza return (ENXIO); 7457836352bSLuiz Otavio O Souza } 746e53470feSOleksandr Tymoshenko 7477836352bSLuiz Otavio O Souza return (0); 748e53470feSOleksandr Tymoshenko } 749e53470feSOleksandr Tymoshenko 750e53470feSOleksandr Tymoshenko /** 751e53470feSOleksandr Tymoshenko * ti_gpio_detach - detach function for the driver 752e53470feSOleksandr Tymoshenko * @dev: scm device handle 753e53470feSOleksandr Tymoshenko * 754e53470feSOleksandr Tymoshenko * Allocates and sets up the driver context, this simply entails creating a 755e53470feSOleksandr Tymoshenko * bus mappings for the SCM register set. 756e53470feSOleksandr Tymoshenko * 757e53470feSOleksandr Tymoshenko * LOCKING: 758e53470feSOleksandr Tymoshenko * None 759e53470feSOleksandr Tymoshenko * 760e53470feSOleksandr Tymoshenko * RETURNS: 761e53470feSOleksandr Tymoshenko * Always returns 0 762e53470feSOleksandr Tymoshenko */ 763e53470feSOleksandr Tymoshenko static int 764e53470feSOleksandr Tymoshenko ti_gpio_detach(device_t dev) 765e53470feSOleksandr Tymoshenko { 766e53470feSOleksandr Tymoshenko struct ti_gpio_softc *sc = device_get_softc(dev); 767e53470feSOleksandr Tymoshenko 768e53470feSOleksandr Tymoshenko KASSERT(mtx_initialized(&sc->sc_mtx), ("gpio mutex not initialized")); 769e53470feSOleksandr Tymoshenko 770e53470feSOleksandr Tymoshenko /* Disable all interrupts */ 7715b03aba6SOleksandr Tymoshenko if (sc->sc_mem_res != NULL) 7725b03aba6SOleksandr Tymoshenko ti_gpio_intr_clr(sc, 0xffffffff); 7737836352bSLuiz Otavio O Souza gpiobus_detach_bus(dev); 774*2df5562dSSvatopluk Kraus #ifdef ARM_INTRNG 775*2df5562dSSvatopluk Kraus if (sc->sc_isrcs != NULL) 776*2df5562dSSvatopluk Kraus ti_gpio_pic_detach(sc); 777*2df5562dSSvatopluk Kraus #else 778876c1bd8SLuiz Otavio O Souza if (sc->sc_events) 7793681c8d7SLuiz Otavio O Souza free(sc->sc_events, M_DEVBUF); 7805b03aba6SOleksandr Tymoshenko if (sc->sc_mask_args) 7815b03aba6SOleksandr Tymoshenko free(sc->sc_mask_args, M_DEVBUF); 782876c1bd8SLuiz Otavio O Souza if (sc->sc_irq_polarity) 7833681c8d7SLuiz Otavio O Souza free(sc->sc_irq_polarity, M_DEVBUF); 784876c1bd8SLuiz Otavio O Souza if (sc->sc_irq_trigger) 7853681c8d7SLuiz Otavio O Souza free(sc->sc_irq_trigger, M_DEVBUF); 786*2df5562dSSvatopluk Kraus #endif 7879b1cba84SLuiz Otavio O Souza /* Release the memory and IRQ resources. */ 7885b03aba6SOleksandr Tymoshenko if (sc->sc_irq_hdl) { 7895b03aba6SOleksandr Tymoshenko bus_teardown_intr(dev, sc->sc_irq_res, 7905b03aba6SOleksandr Tymoshenko sc->sc_irq_hdl); 7915b03aba6SOleksandr Tymoshenko } 7925b03aba6SOleksandr Tymoshenko bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irq_rid, 7935b03aba6SOleksandr Tymoshenko sc->sc_irq_res); 7945b03aba6SOleksandr Tymoshenko bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_mem_rid, 7955b03aba6SOleksandr Tymoshenko sc->sc_mem_res); 796e53470feSOleksandr Tymoshenko TI_GPIO_LOCK_DESTROY(sc); 797e53470feSOleksandr Tymoshenko 798e53470feSOleksandr Tymoshenko return (0); 799e53470feSOleksandr Tymoshenko } 800e53470feSOleksandr Tymoshenko 801*2df5562dSSvatopluk Kraus #ifdef ARM_INTRNG 802*2df5562dSSvatopluk Kraus static inline void 803*2df5562dSSvatopluk Kraus ti_gpio_rwreg_set(struct ti_gpio_softc *sc, uint32_t reg, uint32_t mask) 804*2df5562dSSvatopluk Kraus { 805*2df5562dSSvatopluk Kraus 806*2df5562dSSvatopluk Kraus ti_gpio_write_4(sc, reg, ti_gpio_read_4(sc, reg) | mask); 807*2df5562dSSvatopluk Kraus } 808*2df5562dSSvatopluk Kraus 809*2df5562dSSvatopluk Kraus static inline void 810*2df5562dSSvatopluk Kraus ti_gpio_rwreg_clr(struct ti_gpio_softc *sc, uint32_t reg, uint32_t mask) 811*2df5562dSSvatopluk Kraus { 812*2df5562dSSvatopluk Kraus 813*2df5562dSSvatopluk Kraus ti_gpio_write_4(sc, reg, ti_gpio_read_4(sc, reg) & ~mask); 814*2df5562dSSvatopluk Kraus } 815*2df5562dSSvatopluk Kraus 816*2df5562dSSvatopluk Kraus static inline void 817*2df5562dSSvatopluk Kraus ti_gpio_isrc_mask(struct ti_gpio_softc *sc, struct ti_gpio_irqsrc *tgi) 818*2df5562dSSvatopluk Kraus { 819*2df5562dSSvatopluk Kraus 820*2df5562dSSvatopluk Kraus /* Writing a 0 has no effect. */ 821*2df5562dSSvatopluk Kraus ti_gpio_intr_clr(sc, tgi->tgi_mask); 822*2df5562dSSvatopluk Kraus } 823*2df5562dSSvatopluk Kraus 824*2df5562dSSvatopluk Kraus static inline void 825*2df5562dSSvatopluk Kraus ti_gpio_isrc_unmask(struct ti_gpio_softc *sc, struct ti_gpio_irqsrc *tgi) 826*2df5562dSSvatopluk Kraus { 827*2df5562dSSvatopluk Kraus 828*2df5562dSSvatopluk Kraus /* Writing a 0 has no effect. */ 829*2df5562dSSvatopluk Kraus ti_gpio_intr_set(sc, tgi->tgi_mask); 830*2df5562dSSvatopluk Kraus } 831*2df5562dSSvatopluk Kraus 832*2df5562dSSvatopluk Kraus static inline void 833*2df5562dSSvatopluk Kraus ti_gpio_isrc_eoi(struct ti_gpio_softc *sc, struct ti_gpio_irqsrc *tgi) 834*2df5562dSSvatopluk Kraus { 835*2df5562dSSvatopluk Kraus 836*2df5562dSSvatopluk Kraus /* Writing a 0 has no effect. */ 837*2df5562dSSvatopluk Kraus ti_gpio_intr_ack(sc, tgi->tgi_mask); 838*2df5562dSSvatopluk Kraus } 839*2df5562dSSvatopluk Kraus 840*2df5562dSSvatopluk Kraus static inline bool 841*2df5562dSSvatopluk Kraus ti_gpio_isrc_is_level(struct ti_gpio_irqsrc *tgi) 842*2df5562dSSvatopluk Kraus { 843*2df5562dSSvatopluk Kraus 844*2df5562dSSvatopluk Kraus return (tgi->tgi_cfgreg == TI_GPIO_LEVELDETECT0 || 845*2df5562dSSvatopluk Kraus tgi->tgi_cfgreg == TI_GPIO_LEVELDETECT1); 846*2df5562dSSvatopluk Kraus } 847*2df5562dSSvatopluk Kraus 848*2df5562dSSvatopluk Kraus static int 849*2df5562dSSvatopluk Kraus ti_gpio_intr(void *arg) 850*2df5562dSSvatopluk Kraus { 851*2df5562dSSvatopluk Kraus u_int irq; 852*2df5562dSSvatopluk Kraus uint32_t reg; 853*2df5562dSSvatopluk Kraus struct ti_gpio_softc *sc; 854*2df5562dSSvatopluk Kraus struct trapframe *tf; 855*2df5562dSSvatopluk Kraus struct ti_gpio_irqsrc *tgi; 856*2df5562dSSvatopluk Kraus 857*2df5562dSSvatopluk Kraus sc = (struct ti_gpio_softc *)arg; 858*2df5562dSSvatopluk Kraus tf = curthread->td_intr_frame; 859*2df5562dSSvatopluk Kraus 860*2df5562dSSvatopluk Kraus reg = ti_gpio_intr_status(sc); 861*2df5562dSSvatopluk Kraus for (irq = 0; irq < sc->sc_maxpin; irq++) { 862*2df5562dSSvatopluk Kraus tgi = &sc->sc_isrcs[irq]; 863*2df5562dSSvatopluk Kraus if ((reg & tgi->tgi_mask) == 0) 864*2df5562dSSvatopluk Kraus continue; 865*2df5562dSSvatopluk Kraus if (!ti_gpio_isrc_is_level(tgi)) 866*2df5562dSSvatopluk Kraus ti_gpio_isrc_eoi(sc, tgi); 867*2df5562dSSvatopluk Kraus if (intr_isrc_dispatch(&tgi->tgi_isrc, tf) != 0) { 868*2df5562dSSvatopluk Kraus ti_gpio_isrc_mask(sc, tgi); 869*2df5562dSSvatopluk Kraus if (ti_gpio_isrc_is_level(tgi)) 870*2df5562dSSvatopluk Kraus ti_gpio_isrc_eoi(sc, tgi); 871*2df5562dSSvatopluk Kraus device_printf(sc->sc_dev, "Stray irq %u disabled\n", 872*2df5562dSSvatopluk Kraus irq); 873*2df5562dSSvatopluk Kraus } 874*2df5562dSSvatopluk Kraus } 875*2df5562dSSvatopluk Kraus return (FILTER_HANDLED); 876*2df5562dSSvatopluk Kraus } 877*2df5562dSSvatopluk Kraus 878*2df5562dSSvatopluk Kraus static int 879*2df5562dSSvatopluk Kraus ti_gpio_pic_attach(struct ti_gpio_softc *sc) 880*2df5562dSSvatopluk Kraus { 881*2df5562dSSvatopluk Kraus int error; 882*2df5562dSSvatopluk Kraus uint32_t irq; 883*2df5562dSSvatopluk Kraus const char *name; 884*2df5562dSSvatopluk Kraus 885*2df5562dSSvatopluk Kraus sc->sc_isrcs = malloc(sizeof(*sc->sc_isrcs) * sc->sc_maxpin, M_DEVBUF, 886*2df5562dSSvatopluk Kraus M_WAITOK | M_ZERO); 887*2df5562dSSvatopluk Kraus 888*2df5562dSSvatopluk Kraus name = device_get_nameunit(sc->sc_dev); 889*2df5562dSSvatopluk Kraus for (irq = 0; irq < sc->sc_maxpin; irq++) { 890*2df5562dSSvatopluk Kraus sc->sc_isrcs[irq].tgi_irq = irq; 891*2df5562dSSvatopluk Kraus sc->sc_isrcs[irq].tgi_mask = TI_GPIO_MASK(irq); 892*2df5562dSSvatopluk Kraus sc->sc_isrcs[irq].tgi_cfgreg = 0; 893*2df5562dSSvatopluk Kraus 894*2df5562dSSvatopluk Kraus error = intr_isrc_register(&sc->sc_isrcs[irq].tgi_isrc, 895*2df5562dSSvatopluk Kraus sc->sc_dev, 0, "%s,%u", name, irq); 896*2df5562dSSvatopluk Kraus if (error != 0) 897*2df5562dSSvatopluk Kraus return (error); /* XXX deregister ISRCs */ 898*2df5562dSSvatopluk Kraus } 899*2df5562dSSvatopluk Kraus return (intr_pic_register(sc->sc_dev, 900*2df5562dSSvatopluk Kraus OF_xref_from_node(ofw_bus_get_node(sc->sc_dev)))); 901*2df5562dSSvatopluk Kraus } 902*2df5562dSSvatopluk Kraus 903*2df5562dSSvatopluk Kraus static int 904*2df5562dSSvatopluk Kraus ti_gpio_pic_detach(struct ti_gpio_softc *sc) 905*2df5562dSSvatopluk Kraus { 906*2df5562dSSvatopluk Kraus 907*2df5562dSSvatopluk Kraus /* 908*2df5562dSSvatopluk Kraus * There has not been established any procedure yet 909*2df5562dSSvatopluk Kraus * how to detach PIC from living system correctly. 910*2df5562dSSvatopluk Kraus */ 911*2df5562dSSvatopluk Kraus device_printf(sc->sc_dev, "%s: not implemented yet\n", __func__); 912*2df5562dSSvatopluk Kraus return (EBUSY); 913*2df5562dSSvatopluk Kraus } 914*2df5562dSSvatopluk Kraus 915*2df5562dSSvatopluk Kraus static void 916*2df5562dSSvatopluk Kraus ti_gpio_pic_disable_intr(device_t dev, struct intr_irqsrc *isrc) 917*2df5562dSSvatopluk Kraus { 918*2df5562dSSvatopluk Kraus struct ti_gpio_softc *sc = device_get_softc(dev); 919*2df5562dSSvatopluk Kraus struct ti_gpio_irqsrc *tgi = (struct ti_gpio_irqsrc *)isrc; 920*2df5562dSSvatopluk Kraus 921*2df5562dSSvatopluk Kraus ti_gpio_isrc_mask(sc, tgi); 922*2df5562dSSvatopluk Kraus } 923*2df5562dSSvatopluk Kraus 924*2df5562dSSvatopluk Kraus static void 925*2df5562dSSvatopluk Kraus ti_gpio_pic_enable_intr(device_t dev, struct intr_irqsrc *isrc) 926*2df5562dSSvatopluk Kraus { 927*2df5562dSSvatopluk Kraus struct ti_gpio_softc *sc = device_get_softc(dev); 928*2df5562dSSvatopluk Kraus struct ti_gpio_irqsrc *tgi = (struct ti_gpio_irqsrc *)isrc; 929*2df5562dSSvatopluk Kraus 930*2df5562dSSvatopluk Kraus arm_irq_memory_barrier(tgi->tgi_irq); 931*2df5562dSSvatopluk Kraus ti_gpio_isrc_unmask(sc, tgi); 932*2df5562dSSvatopluk Kraus } 933*2df5562dSSvatopluk Kraus 934*2df5562dSSvatopluk Kraus static int 935*2df5562dSSvatopluk Kraus ti_gpio_pic_map_fdt(struct ti_gpio_softc *sc, u_int ncells, pcell_t *cells, 936*2df5562dSSvatopluk Kraus u_int *irqp, uint32_t *regp) 937*2df5562dSSvatopluk Kraus { 938*2df5562dSSvatopluk Kraus uint32_t reg; 939*2df5562dSSvatopluk Kraus 940*2df5562dSSvatopluk Kraus /* 941*2df5562dSSvatopluk Kraus * The first cell is the interrupt number. 942*2df5562dSSvatopluk Kraus * The second cell is used to specify flags: 943*2df5562dSSvatopluk Kraus * bits[3:0] trigger type and level flags: 944*2df5562dSSvatopluk Kraus * 1 = low-to-high edge triggered. 945*2df5562dSSvatopluk Kraus * 2 = high-to-low edge triggered. 946*2df5562dSSvatopluk Kraus * 4 = active high level-sensitive. 947*2df5562dSSvatopluk Kraus * 8 = active low level-sensitive. 948*2df5562dSSvatopluk Kraus */ 949*2df5562dSSvatopluk Kraus if (ncells != 2 || cells[0] >= sc->sc_maxpin) 950*2df5562dSSvatopluk Kraus return (EINVAL); 951*2df5562dSSvatopluk Kraus 952*2df5562dSSvatopluk Kraus /* 953*2df5562dSSvatopluk Kraus * All interrupt types could be set for an interrupt at one moment. 954*2df5562dSSvatopluk Kraus * At least, the combination of 'low-to-high' and 'high-to-low' edge 955*2df5562dSSvatopluk Kraus * triggered interrupt types can make a sense. However, no combo is 956*2df5562dSSvatopluk Kraus * supported now. 957*2df5562dSSvatopluk Kraus */ 958*2df5562dSSvatopluk Kraus if (cells[1] == 1) 959*2df5562dSSvatopluk Kraus reg = TI_GPIO_RISINGDETECT; 960*2df5562dSSvatopluk Kraus else if (cells[1] == 2) 961*2df5562dSSvatopluk Kraus reg = TI_GPIO_FALLINGDETECT; 962*2df5562dSSvatopluk Kraus else if (cells[1] == 4) 963*2df5562dSSvatopluk Kraus reg = TI_GPIO_LEVELDETECT1; 964*2df5562dSSvatopluk Kraus else if (cells[1] == 8) 965*2df5562dSSvatopluk Kraus reg = TI_GPIO_LEVELDETECT0; 966*2df5562dSSvatopluk Kraus else 967*2df5562dSSvatopluk Kraus return (EINVAL); 968*2df5562dSSvatopluk Kraus 969*2df5562dSSvatopluk Kraus *irqp = cells[0]; 970*2df5562dSSvatopluk Kraus if (regp != NULL) 971*2df5562dSSvatopluk Kraus *regp = reg; 972*2df5562dSSvatopluk Kraus return (0); 973*2df5562dSSvatopluk Kraus } 974*2df5562dSSvatopluk Kraus 975*2df5562dSSvatopluk Kraus static int 976*2df5562dSSvatopluk Kraus ti_gpio_pic_map_intr(device_t dev, struct intr_map_data *data, 977*2df5562dSSvatopluk Kraus struct intr_irqsrc **isrcp) 978*2df5562dSSvatopluk Kraus { 979*2df5562dSSvatopluk Kraus int error; 980*2df5562dSSvatopluk Kraus u_int irq; 981*2df5562dSSvatopluk Kraus struct ti_gpio_softc *sc; 982*2df5562dSSvatopluk Kraus 983*2df5562dSSvatopluk Kraus if (data->type != INTR_MAP_DATA_FDT) 984*2df5562dSSvatopluk Kraus return (ENOTSUP); 985*2df5562dSSvatopluk Kraus 986*2df5562dSSvatopluk Kraus sc = device_get_softc(dev); 987*2df5562dSSvatopluk Kraus error = ti_gpio_pic_map_fdt(sc, data->fdt.ncells, data->fdt.cells, &irq, 988*2df5562dSSvatopluk Kraus NULL); 989*2df5562dSSvatopluk Kraus if (error == 0) 990*2df5562dSSvatopluk Kraus *isrcp = &sc->sc_isrcs[irq].tgi_isrc; 991*2df5562dSSvatopluk Kraus return (error); 992*2df5562dSSvatopluk Kraus } 993*2df5562dSSvatopluk Kraus 994*2df5562dSSvatopluk Kraus static void 995*2df5562dSSvatopluk Kraus ti_gpio_pic_post_filter(device_t dev, struct intr_irqsrc *isrc) 996*2df5562dSSvatopluk Kraus { 997*2df5562dSSvatopluk Kraus struct ti_gpio_softc *sc = device_get_softc(dev); 998*2df5562dSSvatopluk Kraus struct ti_gpio_irqsrc *tgi = (struct ti_gpio_irqsrc *)isrc; 999*2df5562dSSvatopluk Kraus 1000*2df5562dSSvatopluk Kraus if (ti_gpio_isrc_is_level(tgi)) 1001*2df5562dSSvatopluk Kraus ti_gpio_isrc_eoi(sc, tgi); 1002*2df5562dSSvatopluk Kraus } 1003*2df5562dSSvatopluk Kraus 1004*2df5562dSSvatopluk Kraus static void 1005*2df5562dSSvatopluk Kraus ti_gpio_pic_post_ithread(device_t dev, struct intr_irqsrc *isrc) 1006*2df5562dSSvatopluk Kraus { 1007*2df5562dSSvatopluk Kraus 1008*2df5562dSSvatopluk Kraus ti_gpio_pic_enable_intr(dev, isrc); 1009*2df5562dSSvatopluk Kraus } 1010*2df5562dSSvatopluk Kraus 1011*2df5562dSSvatopluk Kraus static void 1012*2df5562dSSvatopluk Kraus ti_gpio_pic_pre_ithread(device_t dev, struct intr_irqsrc *isrc) 1013*2df5562dSSvatopluk Kraus { 1014*2df5562dSSvatopluk Kraus struct ti_gpio_softc *sc = device_get_softc(dev); 1015*2df5562dSSvatopluk Kraus struct ti_gpio_irqsrc *tgi = (struct ti_gpio_irqsrc *)isrc; 1016*2df5562dSSvatopluk Kraus 1017*2df5562dSSvatopluk Kraus ti_gpio_isrc_mask(sc, tgi); 1018*2df5562dSSvatopluk Kraus if (ti_gpio_isrc_is_level(tgi)) 1019*2df5562dSSvatopluk Kraus ti_gpio_isrc_eoi(sc, tgi); 1020*2df5562dSSvatopluk Kraus } 1021*2df5562dSSvatopluk Kraus 1022*2df5562dSSvatopluk Kraus static int 1023*2df5562dSSvatopluk Kraus ti_gpio_pic_setup_intr(device_t dev, struct intr_irqsrc *isrc, 1024*2df5562dSSvatopluk Kraus struct resource *res, struct intr_map_data *data) 1025*2df5562dSSvatopluk Kraus { 1026*2df5562dSSvatopluk Kraus u_int irq; 1027*2df5562dSSvatopluk Kraus uint32_t cfgreg; 1028*2df5562dSSvatopluk Kraus struct ti_gpio_softc *sc; 1029*2df5562dSSvatopluk Kraus struct ti_gpio_irqsrc *tgi; 1030*2df5562dSSvatopluk Kraus 1031*2df5562dSSvatopluk Kraus if (data == NULL || data->type != INTR_MAP_DATA_FDT) 1032*2df5562dSSvatopluk Kraus return (ENOTSUP); 1033*2df5562dSSvatopluk Kraus 1034*2df5562dSSvatopluk Kraus sc = device_get_softc(dev); 1035*2df5562dSSvatopluk Kraus tgi = (struct ti_gpio_irqsrc *)isrc; 1036*2df5562dSSvatopluk Kraus 1037*2df5562dSSvatopluk Kraus /* Get and check config for an interrupt. */ 1038*2df5562dSSvatopluk Kraus if (ti_gpio_pic_map_fdt(sc, data->fdt.ncells, data->fdt.cells, &irq, 1039*2df5562dSSvatopluk Kraus &cfgreg) != 0 || tgi->tgi_irq != irq) 1040*2df5562dSSvatopluk Kraus return (EINVAL); 1041*2df5562dSSvatopluk Kraus 1042*2df5562dSSvatopluk Kraus /* 1043*2df5562dSSvatopluk Kraus * If this is a setup for another handler, 1044*2df5562dSSvatopluk Kraus * only check that its configuration match. 1045*2df5562dSSvatopluk Kraus */ 1046*2df5562dSSvatopluk Kraus if (isrc->isrc_handlers != 0) 1047*2df5562dSSvatopluk Kraus return (tgi->tgi_cfgreg == cfgreg ? 0 : EINVAL); 1048*2df5562dSSvatopluk Kraus 1049*2df5562dSSvatopluk Kraus TI_GPIO_LOCK(sc); 1050*2df5562dSSvatopluk Kraus ti_gpio_rwreg_clr(sc, TI_GPIO_RISINGDETECT, tgi->tgi_mask); 1051*2df5562dSSvatopluk Kraus ti_gpio_rwreg_clr(sc, TI_GPIO_FALLINGDETECT, tgi->tgi_mask); 1052*2df5562dSSvatopluk Kraus ti_gpio_rwreg_clr(sc, TI_GPIO_LEVELDETECT1, tgi->tgi_mask); 1053*2df5562dSSvatopluk Kraus ti_gpio_rwreg_clr(sc, TI_GPIO_LEVELDETECT0, tgi->tgi_mask); 1054*2df5562dSSvatopluk Kraus tgi->tgi_cfgreg = cfgreg; 1055*2df5562dSSvatopluk Kraus ti_gpio_rwreg_set(sc, cfgreg, tgi->tgi_mask); 1056*2df5562dSSvatopluk Kraus TI_GPIO_UNLOCK(sc); 1057*2df5562dSSvatopluk Kraus return (0); 1058*2df5562dSSvatopluk Kraus } 1059*2df5562dSSvatopluk Kraus 1060*2df5562dSSvatopluk Kraus static int 1061*2df5562dSSvatopluk Kraus ti_gpio_pic_teardown_intr(device_t dev, struct intr_irqsrc *isrc, 1062*2df5562dSSvatopluk Kraus struct resource *res, struct intr_map_data *data) 1063*2df5562dSSvatopluk Kraus { 1064*2df5562dSSvatopluk Kraus struct ti_gpio_softc *sc = device_get_softc(dev); 1065*2df5562dSSvatopluk Kraus struct ti_gpio_irqsrc *tgi = (struct ti_gpio_irqsrc *)isrc; 1066*2df5562dSSvatopluk Kraus 1067*2df5562dSSvatopluk Kraus if (isrc->isrc_handlers == 0) { 1068*2df5562dSSvatopluk Kraus TI_GPIO_LOCK(sc); 1069*2df5562dSSvatopluk Kraus ti_gpio_rwreg_clr(sc, tgi->tgi_cfgreg, tgi->tgi_mask); 1070*2df5562dSSvatopluk Kraus tgi->tgi_cfgreg = 0; 1071*2df5562dSSvatopluk Kraus TI_GPIO_UNLOCK(sc); 1072*2df5562dSSvatopluk Kraus } 1073*2df5562dSSvatopluk Kraus return (0); 1074*2df5562dSSvatopluk Kraus } 1075*2df5562dSSvatopluk Kraus 1076*2df5562dSSvatopluk Kraus #else 10773681c8d7SLuiz Otavio O Souza static uint32_t 10783681c8d7SLuiz Otavio O Souza ti_gpio_intr_reg(struct ti_gpio_softc *sc, int irq) 10793681c8d7SLuiz Otavio O Souza { 10803681c8d7SLuiz Otavio O Souza 10813681c8d7SLuiz Otavio O Souza if (ti_gpio_valid_pin(sc, irq) != 0) 10823681c8d7SLuiz Otavio O Souza return (0); 10833681c8d7SLuiz Otavio O Souza 10843681c8d7SLuiz Otavio O Souza if (sc->sc_irq_trigger[irq] == INTR_TRIGGER_LEVEL) { 10853681c8d7SLuiz Otavio O Souza if (sc->sc_irq_polarity[irq] == INTR_POLARITY_LOW) 10863681c8d7SLuiz Otavio O Souza return (TI_GPIO_LEVELDETECT0); 10873681c8d7SLuiz Otavio O Souza else if (sc->sc_irq_polarity[irq] == INTR_POLARITY_HIGH) 10883681c8d7SLuiz Otavio O Souza return (TI_GPIO_LEVELDETECT1); 10893681c8d7SLuiz Otavio O Souza } else if (sc->sc_irq_trigger[irq] == INTR_TRIGGER_EDGE) { 10903681c8d7SLuiz Otavio O Souza if (sc->sc_irq_polarity[irq] == INTR_POLARITY_LOW) 10913681c8d7SLuiz Otavio O Souza return (TI_GPIO_FALLINGDETECT); 10923681c8d7SLuiz Otavio O Souza else if (sc->sc_irq_polarity[irq] == INTR_POLARITY_HIGH) 10933681c8d7SLuiz Otavio O Souza return (TI_GPIO_RISINGDETECT); 10943681c8d7SLuiz Otavio O Souza } 10953681c8d7SLuiz Otavio O Souza 10963681c8d7SLuiz Otavio O Souza return (0); 10973681c8d7SLuiz Otavio O Souza } 10983681c8d7SLuiz Otavio O Souza 10993681c8d7SLuiz Otavio O Souza static void 11005b03aba6SOleksandr Tymoshenko ti_gpio_mask_irq_internal(struct ti_gpio_softc *sc, int irq) 11013681c8d7SLuiz Otavio O Souza { 11023681c8d7SLuiz Otavio O Souza uint32_t reg, val; 11033681c8d7SLuiz Otavio O Souza 11045b03aba6SOleksandr Tymoshenko if (ti_gpio_valid_pin(sc, irq) != 0) 11053681c8d7SLuiz Otavio O Souza return; 11063681c8d7SLuiz Otavio O Souza 11075b03aba6SOleksandr Tymoshenko TI_GPIO_LOCK(sc); 11085b03aba6SOleksandr Tymoshenko ti_gpio_intr_clr(sc, TI_GPIO_MASK(irq)); 11095b03aba6SOleksandr Tymoshenko reg = ti_gpio_intr_reg(sc, irq); 11103681c8d7SLuiz Otavio O Souza if (reg != 0) { 11115b03aba6SOleksandr Tymoshenko val = ti_gpio_read_4(sc, reg); 11123681c8d7SLuiz Otavio O Souza val &= ~TI_GPIO_MASK(irq); 11135b03aba6SOleksandr Tymoshenko ti_gpio_write_4(sc, reg, val); 11143681c8d7SLuiz Otavio O Souza } 11155b03aba6SOleksandr Tymoshenko TI_GPIO_UNLOCK(sc); 11165b03aba6SOleksandr Tymoshenko } 11175b03aba6SOleksandr Tymoshenko 11185b03aba6SOleksandr Tymoshenko static void 11195b03aba6SOleksandr Tymoshenko ti_gpio_unmask_irq_internal(struct ti_gpio_softc *sc, int irq) 11205b03aba6SOleksandr Tymoshenko { 11215b03aba6SOleksandr Tymoshenko uint32_t reg, val; 11225b03aba6SOleksandr Tymoshenko 11235b03aba6SOleksandr Tymoshenko if (ti_gpio_valid_pin(sc, irq) != 0) 11245b03aba6SOleksandr Tymoshenko return; 11255b03aba6SOleksandr Tymoshenko 11265b03aba6SOleksandr Tymoshenko TI_GPIO_LOCK(sc); 11275b03aba6SOleksandr Tymoshenko reg = ti_gpio_intr_reg(sc, irq); 11285b03aba6SOleksandr Tymoshenko if (reg != 0) { 11295b03aba6SOleksandr Tymoshenko val = ti_gpio_read_4(sc, reg); 11305b03aba6SOleksandr Tymoshenko val |= TI_GPIO_MASK(irq); 11315b03aba6SOleksandr Tymoshenko ti_gpio_write_4(sc, reg, val); 11325b03aba6SOleksandr Tymoshenko ti_gpio_intr_set(sc, TI_GPIO_MASK(irq)); 11335b03aba6SOleksandr Tymoshenko } 11345b03aba6SOleksandr Tymoshenko TI_GPIO_UNLOCK(sc); 11355b03aba6SOleksandr Tymoshenko } 11365b03aba6SOleksandr Tymoshenko 11375b03aba6SOleksandr Tymoshenko static void 11385b03aba6SOleksandr Tymoshenko ti_gpio_mask_irq(void *source) 11395b03aba6SOleksandr Tymoshenko { 11405b03aba6SOleksandr Tymoshenko struct ti_gpio_mask_arg *arg = source; 11415b03aba6SOleksandr Tymoshenko 11425b03aba6SOleksandr Tymoshenko ti_gpio_mask_irq_internal(arg->softc, arg->pin); 11433681c8d7SLuiz Otavio O Souza } 11443681c8d7SLuiz Otavio O Souza 11453681c8d7SLuiz Otavio O Souza static void 11463681c8d7SLuiz Otavio O Souza ti_gpio_unmask_irq(void *source) 11473681c8d7SLuiz Otavio O Souza { 11485b03aba6SOleksandr Tymoshenko struct ti_gpio_mask_arg *arg = source; 11493681c8d7SLuiz Otavio O Souza 11505b03aba6SOleksandr Tymoshenko ti_gpio_unmask_irq_internal(arg->softc, arg->pin); 11513681c8d7SLuiz Otavio O Souza } 11523681c8d7SLuiz Otavio O Souza 11533681c8d7SLuiz Otavio O Souza static int 11543681c8d7SLuiz Otavio O Souza ti_gpio_activate_resource(device_t dev, device_t child, int type, int rid, 11553681c8d7SLuiz Otavio O Souza struct resource *res) 11563681c8d7SLuiz Otavio O Souza { 11577b25d1d6SOleksandr Tymoshenko struct ti_gpio_mask_arg mask_arg; 11583681c8d7SLuiz Otavio O Souza 11593681c8d7SLuiz Otavio O Souza if (type != SYS_RES_IRQ) 11603681c8d7SLuiz Otavio O Souza return (ENXIO); 11613681c8d7SLuiz Otavio O Souza 11623681c8d7SLuiz Otavio O Souza /* Unmask the interrupt. */ 11637b25d1d6SOleksandr Tymoshenko mask_arg.pin = rman_get_start(res); 11647b25d1d6SOleksandr Tymoshenko mask_arg.softc = device_get_softc(dev); 11657b25d1d6SOleksandr Tymoshenko 11667b25d1d6SOleksandr Tymoshenko ti_gpio_unmask_irq((void *)&mask_arg); 11673681c8d7SLuiz Otavio O Souza 11683681c8d7SLuiz Otavio O Souza return (0); 11693681c8d7SLuiz Otavio O Souza } 11703681c8d7SLuiz Otavio O Souza 11713681c8d7SLuiz Otavio O Souza static int 11723681c8d7SLuiz Otavio O Souza ti_gpio_deactivate_resource(device_t dev, device_t child, int type, int rid, 11733681c8d7SLuiz Otavio O Souza struct resource *res) 11743681c8d7SLuiz Otavio O Souza { 11753681c8d7SLuiz Otavio O Souza int pin; 11763681c8d7SLuiz Otavio O Souza 11773681c8d7SLuiz Otavio O Souza if (type != SYS_RES_IRQ) 11783681c8d7SLuiz Otavio O Souza return (ENXIO); 11793681c8d7SLuiz Otavio O Souza 11803681c8d7SLuiz Otavio O Souza /* Mask the interrupt. */ 11813681c8d7SLuiz Otavio O Souza pin = rman_get_start(res); 11823681c8d7SLuiz Otavio O Souza ti_gpio_mask_irq((void *)(uintptr_t)pin); 11833681c8d7SLuiz Otavio O Souza 11843681c8d7SLuiz Otavio O Souza return (0); 11853681c8d7SLuiz Otavio O Souza } 11863681c8d7SLuiz Otavio O Souza 11873681c8d7SLuiz Otavio O Souza static int 11883681c8d7SLuiz Otavio O Souza ti_gpio_config_intr(device_t dev, int irq, enum intr_trigger trig, 11893681c8d7SLuiz Otavio O Souza enum intr_polarity pol) 11903681c8d7SLuiz Otavio O Souza { 11913681c8d7SLuiz Otavio O Souza struct ti_gpio_softc *sc; 11923681c8d7SLuiz Otavio O Souza uint32_t oldreg, reg, val; 11933681c8d7SLuiz Otavio O Souza 11943681c8d7SLuiz Otavio O Souza sc = device_get_softc(dev); 11953681c8d7SLuiz Otavio O Souza if (ti_gpio_valid_pin(sc, irq) != 0) 11963681c8d7SLuiz Otavio O Souza return (EINVAL); 11973681c8d7SLuiz Otavio O Souza 11983681c8d7SLuiz Otavio O Souza /* There is no standard trigger or polarity. */ 11993681c8d7SLuiz Otavio O Souza if (trig == INTR_TRIGGER_CONFORM || pol == INTR_POLARITY_CONFORM) 12003681c8d7SLuiz Otavio O Souza return (EINVAL); 12013681c8d7SLuiz Otavio O Souza 12023681c8d7SLuiz Otavio O Souza TI_GPIO_LOCK(sc); 12033681c8d7SLuiz Otavio O Souza /* 12043681c8d7SLuiz Otavio O Souza * TRM recommends add the new event before remove the old one to 12053681c8d7SLuiz Otavio O Souza * avoid losing interrupts. 12063681c8d7SLuiz Otavio O Souza */ 12073681c8d7SLuiz Otavio O Souza oldreg = ti_gpio_intr_reg(sc, irq); 12083681c8d7SLuiz Otavio O Souza sc->sc_irq_trigger[irq] = trig; 12093681c8d7SLuiz Otavio O Souza sc->sc_irq_polarity[irq] = pol; 12103681c8d7SLuiz Otavio O Souza reg = ti_gpio_intr_reg(sc, irq); 12113681c8d7SLuiz Otavio O Souza if (reg != 0) { 12123681c8d7SLuiz Otavio O Souza /* Apply the new settings. */ 12135b03aba6SOleksandr Tymoshenko val = ti_gpio_read_4(sc, reg); 12143681c8d7SLuiz Otavio O Souza val |= TI_GPIO_MASK(irq); 12155b03aba6SOleksandr Tymoshenko ti_gpio_write_4(sc, reg, val); 12163681c8d7SLuiz Otavio O Souza } 12177d732ceaSLuiz Otavio O Souza if (reg != oldreg && oldreg != 0) { 12183681c8d7SLuiz Otavio O Souza /* Remove the old settings. */ 12195b03aba6SOleksandr Tymoshenko val = ti_gpio_read_4(sc, oldreg); 12203681c8d7SLuiz Otavio O Souza val &= ~TI_GPIO_MASK(irq); 12215b03aba6SOleksandr Tymoshenko ti_gpio_write_4(sc, oldreg, val); 12223681c8d7SLuiz Otavio O Souza } 12233681c8d7SLuiz Otavio O Souza TI_GPIO_UNLOCK(sc); 12243681c8d7SLuiz Otavio O Souza 12253681c8d7SLuiz Otavio O Souza return (0); 12263681c8d7SLuiz Otavio O Souza } 12273681c8d7SLuiz Otavio O Souza 12283681c8d7SLuiz Otavio O Souza static int 12293681c8d7SLuiz Otavio O Souza ti_gpio_setup_intr(device_t dev, device_t child, struct resource *ires, 12303681c8d7SLuiz Otavio O Souza int flags, driver_filter_t *filt, driver_intr_t *handler, 12313681c8d7SLuiz Otavio O Souza void *arg, void **cookiep) 12323681c8d7SLuiz Otavio O Souza { 12333681c8d7SLuiz Otavio O Souza struct ti_gpio_softc *sc; 12343681c8d7SLuiz Otavio O Souza struct intr_event *event; 12353681c8d7SLuiz Otavio O Souza int pin, error; 12363681c8d7SLuiz Otavio O Souza 12373681c8d7SLuiz Otavio O Souza sc = device_get_softc(dev); 12383681c8d7SLuiz Otavio O Souza pin = rman_get_start(ires); 12393681c8d7SLuiz Otavio O Souza if (ti_gpio_valid_pin(sc, pin) != 0) 12403681c8d7SLuiz Otavio O Souza panic("%s: bad pin %d", __func__, pin); 12413681c8d7SLuiz Otavio O Souza 12423681c8d7SLuiz Otavio O Souza event = sc->sc_events[pin]; 12433681c8d7SLuiz Otavio O Souza if (event == NULL) { 12445b03aba6SOleksandr Tymoshenko sc->sc_mask_args[pin].softc = sc; 12455b03aba6SOleksandr Tymoshenko sc->sc_mask_args[pin].pin = pin; 12465b03aba6SOleksandr Tymoshenko error = intr_event_create(&event, (void *)&sc->sc_mask_args[pin], 0, 12473681c8d7SLuiz Otavio O Souza pin, ti_gpio_mask_irq, ti_gpio_unmask_irq, NULL, NULL, 12483681c8d7SLuiz Otavio O Souza "gpio%d pin%d:", device_get_unit(dev), pin); 12493681c8d7SLuiz Otavio O Souza if (error != 0) 12503681c8d7SLuiz Otavio O Souza return (error); 12513681c8d7SLuiz Otavio O Souza sc->sc_events[pin] = event; 12523681c8d7SLuiz Otavio O Souza } 12533681c8d7SLuiz Otavio O Souza intr_event_add_handler(event, device_get_nameunit(child), filt, 12543681c8d7SLuiz Otavio O Souza handler, arg, intr_priority(flags), flags, cookiep); 12553681c8d7SLuiz Otavio O Souza 12563681c8d7SLuiz Otavio O Souza return (0); 12573681c8d7SLuiz Otavio O Souza } 12583681c8d7SLuiz Otavio O Souza 12593681c8d7SLuiz Otavio O Souza static int 12603681c8d7SLuiz Otavio O Souza ti_gpio_teardown_intr(device_t dev, device_t child, struct resource *ires, 12613681c8d7SLuiz Otavio O Souza void *cookie) 12623681c8d7SLuiz Otavio O Souza { 12633681c8d7SLuiz Otavio O Souza struct ti_gpio_softc *sc; 12643681c8d7SLuiz Otavio O Souza int pin, err; 12653681c8d7SLuiz Otavio O Souza 12663681c8d7SLuiz Otavio O Souza sc = device_get_softc(dev); 12673681c8d7SLuiz Otavio O Souza pin = rman_get_start(ires); 12683681c8d7SLuiz Otavio O Souza if (ti_gpio_valid_pin(sc, pin) != 0) 12693681c8d7SLuiz Otavio O Souza panic("%s: bad pin %d", __func__, pin); 12703681c8d7SLuiz Otavio O Souza if (sc->sc_events[pin] == NULL) 12713681c8d7SLuiz Otavio O Souza panic("Trying to teardown unoccupied IRQ"); 12723681c8d7SLuiz Otavio O Souza err = intr_event_remove_handler(cookie); 12733681c8d7SLuiz Otavio O Souza if (!err) 12743681c8d7SLuiz Otavio O Souza sc->sc_events[pin] = NULL; 12753681c8d7SLuiz Otavio O Souza 12763681c8d7SLuiz Otavio O Souza return (err); 12773681c8d7SLuiz Otavio O Souza } 1278*2df5562dSSvatopluk Kraus #endif 12793681c8d7SLuiz Otavio O Souza 12808c705c2cSLuiz Otavio O Souza static phandle_t 12818c705c2cSLuiz Otavio O Souza ti_gpio_get_node(device_t bus, device_t dev) 12828c705c2cSLuiz Otavio O Souza { 12838c705c2cSLuiz Otavio O Souza 12848c705c2cSLuiz Otavio O Souza /* We only have one child, the GPIO bus, which needs our own node. */ 12858c705c2cSLuiz Otavio O Souza return (ofw_bus_get_node(bus)); 12868c705c2cSLuiz Otavio O Souza } 12878c705c2cSLuiz Otavio O Souza 1288e53470feSOleksandr Tymoshenko static device_method_t ti_gpio_methods[] = { 1289e53470feSOleksandr Tymoshenko DEVMETHOD(device_attach, ti_gpio_attach), 1290e53470feSOleksandr Tymoshenko DEVMETHOD(device_detach, ti_gpio_detach), 1291e53470feSOleksandr Tymoshenko 1292e53470feSOleksandr Tymoshenko /* GPIO protocol */ 12937836352bSLuiz Otavio O Souza DEVMETHOD(gpio_get_bus, ti_gpio_get_bus), 1294e53470feSOleksandr Tymoshenko DEVMETHOD(gpio_pin_max, ti_gpio_pin_max), 1295e53470feSOleksandr Tymoshenko DEVMETHOD(gpio_pin_getname, ti_gpio_pin_getname), 1296e53470feSOleksandr Tymoshenko DEVMETHOD(gpio_pin_getflags, ti_gpio_pin_getflags), 1297e53470feSOleksandr Tymoshenko DEVMETHOD(gpio_pin_getcaps, ti_gpio_pin_getcaps), 1298e53470feSOleksandr Tymoshenko DEVMETHOD(gpio_pin_setflags, ti_gpio_pin_setflags), 1299e53470feSOleksandr Tymoshenko DEVMETHOD(gpio_pin_get, ti_gpio_pin_get), 1300e53470feSOleksandr Tymoshenko DEVMETHOD(gpio_pin_set, ti_gpio_pin_set), 1301e53470feSOleksandr Tymoshenko DEVMETHOD(gpio_pin_toggle, ti_gpio_pin_toggle), 13028c705c2cSLuiz Otavio O Souza 1303*2df5562dSSvatopluk Kraus #ifdef ARM_INTRNG 1304*2df5562dSSvatopluk Kraus /* Interrupt controller interface */ 1305*2df5562dSSvatopluk Kraus DEVMETHOD(pic_disable_intr, ti_gpio_pic_disable_intr), 1306*2df5562dSSvatopluk Kraus DEVMETHOD(pic_enable_intr, ti_gpio_pic_enable_intr), 1307*2df5562dSSvatopluk Kraus DEVMETHOD(pic_map_intr, ti_gpio_pic_map_intr), 1308*2df5562dSSvatopluk Kraus DEVMETHOD(pic_setup_intr, ti_gpio_pic_setup_intr), 1309*2df5562dSSvatopluk Kraus DEVMETHOD(pic_teardown_intr, ti_gpio_pic_teardown_intr), 1310*2df5562dSSvatopluk Kraus DEVMETHOD(pic_post_filter, ti_gpio_pic_post_filter), 1311*2df5562dSSvatopluk Kraus DEVMETHOD(pic_post_ithread, ti_gpio_pic_post_ithread), 1312*2df5562dSSvatopluk Kraus DEVMETHOD(pic_pre_ithread, ti_gpio_pic_pre_ithread), 1313*2df5562dSSvatopluk Kraus #else 13143681c8d7SLuiz Otavio O Souza /* Bus interface */ 13153681c8d7SLuiz Otavio O Souza DEVMETHOD(bus_activate_resource, ti_gpio_activate_resource), 13163681c8d7SLuiz Otavio O Souza DEVMETHOD(bus_deactivate_resource, ti_gpio_deactivate_resource), 13173681c8d7SLuiz Otavio O Souza DEVMETHOD(bus_config_intr, ti_gpio_config_intr), 13183681c8d7SLuiz Otavio O Souza DEVMETHOD(bus_setup_intr, ti_gpio_setup_intr), 13193681c8d7SLuiz Otavio O Souza DEVMETHOD(bus_teardown_intr, ti_gpio_teardown_intr), 1320*2df5562dSSvatopluk Kraus #endif 13213681c8d7SLuiz Otavio O Souza 13228c705c2cSLuiz Otavio O Souza /* ofw_bus interface */ 13238c705c2cSLuiz Otavio O Souza DEVMETHOD(ofw_bus_get_node, ti_gpio_get_node), 13248c705c2cSLuiz Otavio O Souza 1325e53470feSOleksandr Tymoshenko {0, 0}, 1326e53470feSOleksandr Tymoshenko }; 1327e53470feSOleksandr Tymoshenko 1328b6c7dacfSAndrew Turner driver_t ti_gpio_driver = { 1329e53470feSOleksandr Tymoshenko "gpio", 1330e53470feSOleksandr Tymoshenko ti_gpio_methods, 1331e53470feSOleksandr Tymoshenko sizeof(struct ti_gpio_softc), 1332e53470feSOleksandr Tymoshenko }; 1333