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 362df5562dSSvatopluk Kraus #include "opt_platform.h" 372df5562dSSvatopluk 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> 442df5562dSSvatopluk 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> 522df5562dSSvatopluk 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" 6959c3cb81SAndrew Turner #ifdef INTRNG 702df5562dSSvatopluk Kraus #include "pic_if.h" 712df5562dSSvatopluk 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 822df5562dSSvatopluk Kraus #define TI_GPIO_IRQSTATUS_0 0x002C /* writing a 0 has no effect */ 832df5562dSSvatopluk Kraus #define TI_GPIO_IRQSTATUS_1 0x0030 /* writing a 0 has no effect */ 842df5562dSSvatopluk Kraus #define TI_GPIO_IRQSTATUS_SET_0 0x0034 /* writing a 0 has no effect */ 852df5562dSSvatopluk Kraus #define TI_GPIO_IRQSTATUS_SET_1 0x0038 /* writing a 0 has no effect */ 862df5562dSSvatopluk Kraus #define TI_GPIO_IRQSTATUS_CLR_0 0x003C /* writing a 0 has no effect */ 872df5562dSSvatopluk 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 1002df5562dSSvatopluk Kraus #define TI_GPIO_LEVELDETECT0 0x0140 /* RW register */ 1012df5562dSSvatopluk Kraus #define TI_GPIO_LEVELDETECT1 0x0144 /* RW register */ 1022df5562dSSvatopluk Kraus #define TI_GPIO_RISINGDETECT 0x0148 /* RW register */ 1032df5562dSSvatopluk 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 1212df5562dSSvatopluk Kraus static int ti_gpio_intr(void *arg); 122876c1bd8SLuiz Otavio O Souza static int ti_gpio_detach(device_t); 1233681c8d7SLuiz Otavio O Souza 12459c3cb81SAndrew Turner #ifdef INTRNG 1252df5562dSSvatopluk Kraus static int ti_gpio_pic_attach(struct ti_gpio_softc *sc); 1262df5562dSSvatopluk Kraus static int ti_gpio_pic_detach(struct ti_gpio_softc *sc); 1272df5562dSSvatopluk Kraus #endif 1282df5562dSSvatopluk 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 /** 293*aa0d25b7SSvatopluk Kraus * ti_gpio_pin_getcaps - Gets the capabilities 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 303*aa0d25b7SSvatopluk Kraus * - GPIO_INTR_LEVEL_LOW 304*aa0d25b7SSvatopluk Kraus * - GPIO_INTR_LEVEL_HIGH 305*aa0d25b7SSvatopluk Kraus * - GPIO_INTR_EDGE_RISING 306*aa0d25b7SSvatopluk Kraus * - GPIO_INTR_EDGE_FALLING 307*aa0d25b7SSvatopluk Kraus * - GPIO_INTR_EDGE_BOTH 308e53470feSOleksandr Tymoshenko * 309e53470feSOleksandr Tymoshenko * LOCKING: 310f9de33d4SLuiz Otavio O Souza * No locking required, returns static data. 311e53470feSOleksandr Tymoshenko * 312e53470feSOleksandr Tymoshenko * RETURNS: 313e53470feSOleksandr Tymoshenko * Returns 0 on success otherwise an error code 314e53470feSOleksandr Tymoshenko */ 315e53470feSOleksandr Tymoshenko static int 316e53470feSOleksandr Tymoshenko ti_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) 317e53470feSOleksandr Tymoshenko { 318e350f76cSLuiz Otavio O Souza struct ti_gpio_softc *sc; 319e53470feSOleksandr Tymoshenko 320e350f76cSLuiz Otavio O Souza sc = device_get_softc(dev); 321e350f76cSLuiz Otavio O Souza if (ti_gpio_valid_pin(sc, pin) != 0) 322e53470feSOleksandr Tymoshenko return (EINVAL); 323e53470feSOleksandr Tymoshenko 324*aa0d25b7SSvatopluk Kraus #ifdef INTRNG 325*aa0d25b7SSvatopluk Kraus *caps = (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_PULLUP | 326*aa0d25b7SSvatopluk Kraus GPIO_PIN_PULLDOWN | GPIO_INTR_LEVEL_LOW | GPIO_INTR_LEVEL_HIGH | 327*aa0d25b7SSvatopluk Kraus GPIO_INTR_EDGE_RISING | GPIO_INTR_EDGE_FALLING | 328*aa0d25b7SSvatopluk Kraus GPIO_INTR_EDGE_BOTH); 329*aa0d25b7SSvatopluk Kraus #else 330e53470feSOleksandr Tymoshenko *caps = (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_PULLUP | 331e53470feSOleksandr Tymoshenko GPIO_PIN_PULLDOWN); 332*aa0d25b7SSvatopluk Kraus #endif 333e53470feSOleksandr Tymoshenko 334e53470feSOleksandr Tymoshenko return (0); 335e53470feSOleksandr Tymoshenko } 336e53470feSOleksandr Tymoshenko 337e53470feSOleksandr Tymoshenko /** 338e53470feSOleksandr Tymoshenko * ti_gpio_pin_getflags - Gets the current flags of a given pin 339e53470feSOleksandr Tymoshenko * @dev: gpio device handle 340e53470feSOleksandr Tymoshenko * @pin: the number of the pin 341e53470feSOleksandr Tymoshenko * @flags: upon return will contain the current flags of the pin 342e53470feSOleksandr Tymoshenko * 343e53470feSOleksandr Tymoshenko * Reads the current flags of a given pin, here we actually read the H/W 344e53470feSOleksandr Tymoshenko * registers to determine the flags, rather than storing the value in the 345e53470feSOleksandr Tymoshenko * setflags call. 346e53470feSOleksandr Tymoshenko * 347e53470feSOleksandr Tymoshenko * LOCKING: 348e53470feSOleksandr Tymoshenko * Internally locks the context 349e53470feSOleksandr Tymoshenko * 350e53470feSOleksandr Tymoshenko * RETURNS: 351e53470feSOleksandr Tymoshenko * Returns 0 on success otherwise an error code 352e53470feSOleksandr Tymoshenko */ 353e53470feSOleksandr Tymoshenko static int 354e53470feSOleksandr Tymoshenko ti_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) 355e53470feSOleksandr Tymoshenko { 356e350f76cSLuiz Otavio O Souza struct ti_gpio_softc *sc; 357e53470feSOleksandr Tymoshenko 358e350f76cSLuiz Otavio O Souza sc = device_get_softc(dev); 359e350f76cSLuiz Otavio O Souza if (ti_gpio_valid_pin(sc, pin) != 0) 360e53470feSOleksandr Tymoshenko return (EINVAL); 361e53470feSOleksandr Tymoshenko 362e53470feSOleksandr Tymoshenko /* Get the current pin state */ 363f9de33d4SLuiz Otavio O Souza TI_GPIO_LOCK(sc); 364b6c7dacfSAndrew Turner TI_GPIO_GET_FLAGS(dev, pin, flags); 365e53470feSOleksandr Tymoshenko TI_GPIO_UNLOCK(sc); 366e53470feSOleksandr Tymoshenko 367e53470feSOleksandr Tymoshenko return (0); 368e53470feSOleksandr Tymoshenko } 369e53470feSOleksandr Tymoshenko 370e53470feSOleksandr Tymoshenko /** 371e53470feSOleksandr Tymoshenko * ti_gpio_pin_getname - Gets the name of a given pin 372e53470feSOleksandr Tymoshenko * @dev: gpio device handle 373e53470feSOleksandr Tymoshenko * @pin: the number of the pin 374e53470feSOleksandr Tymoshenko * @name: buffer to put the name in 375e53470feSOleksandr Tymoshenko * 376e53470feSOleksandr Tymoshenko * The driver simply calls the pins gpio_n, where 'n' is obviously the number 377e53470feSOleksandr Tymoshenko * of the pin. 378e53470feSOleksandr Tymoshenko * 379e53470feSOleksandr Tymoshenko * LOCKING: 380f9de33d4SLuiz Otavio O Souza * No locking required, returns static data. 381e53470feSOleksandr Tymoshenko * 382e53470feSOleksandr Tymoshenko * RETURNS: 383e53470feSOleksandr Tymoshenko * Returns 0 on success otherwise an error code 384e53470feSOleksandr Tymoshenko */ 385e53470feSOleksandr Tymoshenko static int 386e53470feSOleksandr Tymoshenko ti_gpio_pin_getname(device_t dev, uint32_t pin, char *name) 387e53470feSOleksandr Tymoshenko { 388e350f76cSLuiz Otavio O Souza struct ti_gpio_softc *sc; 389e53470feSOleksandr Tymoshenko 390e350f76cSLuiz Otavio O Souza sc = device_get_softc(dev); 391e350f76cSLuiz Otavio O Souza if (ti_gpio_valid_pin(sc, pin) != 0) 392e53470feSOleksandr Tymoshenko return (EINVAL); 393e53470feSOleksandr Tymoshenko 394e53470feSOleksandr Tymoshenko /* Set a very simple name */ 395e53470feSOleksandr Tymoshenko snprintf(name, GPIOMAXNAME, "gpio_%u", pin); 396e53470feSOleksandr Tymoshenko name[GPIOMAXNAME - 1] = '\0'; 397e53470feSOleksandr Tymoshenko 398e53470feSOleksandr Tymoshenko return (0); 399e53470feSOleksandr Tymoshenko } 400e53470feSOleksandr Tymoshenko 401e53470feSOleksandr Tymoshenko /** 402e53470feSOleksandr Tymoshenko * ti_gpio_pin_setflags - Sets the flags for a given pin 403e53470feSOleksandr Tymoshenko * @dev: gpio device handle 404e53470feSOleksandr Tymoshenko * @pin: the number of the pin 405e53470feSOleksandr Tymoshenko * @flags: the flags to set 406e53470feSOleksandr Tymoshenko * 407e53470feSOleksandr Tymoshenko * The flags of the pin correspond to things like input/output mode, pull-ups, 408e53470feSOleksandr Tymoshenko * pull-downs, etc. This driver doesn't support all flags, only the following: 409e53470feSOleksandr Tymoshenko * - GPIO_PIN_INPUT 410e53470feSOleksandr Tymoshenko * - GPIO_PIN_OUTPUT 411e53470feSOleksandr Tymoshenko * - GPIO_PIN_PULLUP 412e53470feSOleksandr Tymoshenko * - GPIO_PIN_PULLDOWN 413e53470feSOleksandr Tymoshenko * 414e53470feSOleksandr Tymoshenko * LOCKING: 415e53470feSOleksandr Tymoshenko * Internally locks the context 416e53470feSOleksandr Tymoshenko * 417e53470feSOleksandr Tymoshenko * RETURNS: 418e53470feSOleksandr Tymoshenko * Returns 0 on success otherwise an error code 419e53470feSOleksandr Tymoshenko */ 420e53470feSOleksandr Tymoshenko static int 421e53470feSOleksandr Tymoshenko ti_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) 422e53470feSOleksandr Tymoshenko { 423e350f76cSLuiz Otavio O Souza struct ti_gpio_softc *sc; 424f9de33d4SLuiz Otavio O Souza uint32_t oe; 425e53470feSOleksandr Tymoshenko 426e350f76cSLuiz Otavio O Souza sc = device_get_softc(dev); 427e350f76cSLuiz Otavio O Souza if (ti_gpio_valid_pin(sc, pin) != 0) 428e53470feSOleksandr Tymoshenko return (EINVAL); 429e53470feSOleksandr Tymoshenko 430e53470feSOleksandr Tymoshenko /* Set the GPIO mode and state */ 431f9de33d4SLuiz Otavio O Souza TI_GPIO_LOCK(sc); 432b6c7dacfSAndrew Turner if (TI_GPIO_SET_FLAGS(dev, pin, flags) != 0) { 433e53470feSOleksandr Tymoshenko TI_GPIO_UNLOCK(sc); 434e53470feSOleksandr Tymoshenko return (EINVAL); 435e53470feSOleksandr Tymoshenko } 436e53470feSOleksandr Tymoshenko 437e53470feSOleksandr Tymoshenko /* If configuring as an output set the "output enable" bit */ 4385b03aba6SOleksandr Tymoshenko oe = ti_gpio_read_4(sc, TI_GPIO_OE); 439e53470feSOleksandr Tymoshenko if (flags & GPIO_PIN_INPUT) 440e350f76cSLuiz Otavio O Souza oe |= TI_GPIO_MASK(pin); 441e53470feSOleksandr Tymoshenko else 442e350f76cSLuiz Otavio O Souza oe &= ~TI_GPIO_MASK(pin); 4435b03aba6SOleksandr Tymoshenko ti_gpio_write_4(sc, TI_GPIO_OE, oe); 444e53470feSOleksandr Tymoshenko TI_GPIO_UNLOCK(sc); 445e53470feSOleksandr Tymoshenko 446e53470feSOleksandr Tymoshenko return (0); 447e53470feSOleksandr Tymoshenko } 448e53470feSOleksandr Tymoshenko 449e53470feSOleksandr Tymoshenko /** 450e53470feSOleksandr Tymoshenko * ti_gpio_pin_set - Sets the current level on a GPIO pin 451e53470feSOleksandr Tymoshenko * @dev: gpio device handle 452e53470feSOleksandr Tymoshenko * @pin: the number of the pin 453e53470feSOleksandr Tymoshenko * @value: non-zero value will drive the pin high, otherwise the pin is 454e53470feSOleksandr Tymoshenko * driven low. 455e53470feSOleksandr Tymoshenko * 456e53470feSOleksandr Tymoshenko * 457e53470feSOleksandr Tymoshenko * LOCKING: 458e53470feSOleksandr Tymoshenko * Internally locks the context 459e53470feSOleksandr Tymoshenko * 460e53470feSOleksandr Tymoshenko * RETURNS: 461e53470feSOleksandr Tymoshenko * Returns 0 on success otherwise a error code 462e53470feSOleksandr Tymoshenko */ 463e53470feSOleksandr Tymoshenko static int 464e53470feSOleksandr Tymoshenko ti_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value) 465e53470feSOleksandr Tymoshenko { 466e350f76cSLuiz Otavio O Souza struct ti_gpio_softc *sc; 467f9de33d4SLuiz Otavio O Souza uint32_t reg; 468e53470feSOleksandr Tymoshenko 469e350f76cSLuiz Otavio O Souza sc = device_get_softc(dev); 470e350f76cSLuiz Otavio O Souza if (ti_gpio_valid_pin(sc, pin) != 0) 471e53470feSOleksandr Tymoshenko return (EINVAL); 472e53470feSOleksandr Tymoshenko 473f9de33d4SLuiz Otavio O Souza TI_GPIO_LOCK(sc); 474f9de33d4SLuiz Otavio O Souza if (value == GPIO_PIN_LOW) 475f9de33d4SLuiz Otavio O Souza reg = TI_GPIO_CLEARDATAOUT; 476f9de33d4SLuiz Otavio O Souza else 477f9de33d4SLuiz Otavio O Souza reg = TI_GPIO_SETDATAOUT; 4785b03aba6SOleksandr Tymoshenko ti_gpio_write_4(sc, reg, TI_GPIO_MASK(pin)); 479e53470feSOleksandr Tymoshenko TI_GPIO_UNLOCK(sc); 480e53470feSOleksandr Tymoshenko 481e53470feSOleksandr Tymoshenko return (0); 482e53470feSOleksandr Tymoshenko } 483e53470feSOleksandr Tymoshenko 484e53470feSOleksandr Tymoshenko /** 485e53470feSOleksandr Tymoshenko * ti_gpio_pin_get - Gets the current level on a GPIO pin 486e53470feSOleksandr Tymoshenko * @dev: gpio device handle 487e53470feSOleksandr Tymoshenko * @pin: the number of the pin 488e53470feSOleksandr Tymoshenko * @value: pointer to a value that upond return will contain the pin value 489e53470feSOleksandr Tymoshenko * 490e53470feSOleksandr Tymoshenko * The pin must be configured as an input pin beforehand, otherwise this 491e53470feSOleksandr Tymoshenko * function will fail. 492e53470feSOleksandr Tymoshenko * 493e53470feSOleksandr Tymoshenko * LOCKING: 494e53470feSOleksandr Tymoshenko * Internally locks the context 495e53470feSOleksandr Tymoshenko * 496e53470feSOleksandr Tymoshenko * RETURNS: 497e53470feSOleksandr Tymoshenko * Returns 0 on success otherwise a error code 498e53470feSOleksandr Tymoshenko */ 499e53470feSOleksandr Tymoshenko static int 500e53470feSOleksandr Tymoshenko ti_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *value) 501e53470feSOleksandr Tymoshenko { 502e350f76cSLuiz Otavio O Souza struct ti_gpio_softc *sc; 503e350f76cSLuiz Otavio O Souza uint32_t oe, reg, val; 504e53470feSOleksandr Tymoshenko 505e350f76cSLuiz Otavio O Souza sc = device_get_softc(dev); 506e350f76cSLuiz Otavio O Souza if (ti_gpio_valid_pin(sc, pin) != 0) 507e53470feSOleksandr Tymoshenko return (EINVAL); 508e53470feSOleksandr Tymoshenko 509f9de33d4SLuiz Otavio O Souza /* 510f9de33d4SLuiz Otavio O Souza * Return data from output latch when set as output and from the 511f9de33d4SLuiz Otavio O Souza * input register otherwise. 512f9de33d4SLuiz Otavio O Souza */ 513f9de33d4SLuiz Otavio O Souza TI_GPIO_LOCK(sc); 5145b03aba6SOleksandr Tymoshenko oe = ti_gpio_read_4(sc, TI_GPIO_OE); 515e350f76cSLuiz Otavio O Souza if (oe & TI_GPIO_MASK(pin)) 516f9de33d4SLuiz Otavio O Souza reg = TI_GPIO_DATAIN; 5179f165184SLuiz Otavio O Souza else 518f9de33d4SLuiz Otavio O Souza reg = TI_GPIO_DATAOUT; 5195b03aba6SOleksandr Tymoshenko val = ti_gpio_read_4(sc, reg); 520e350f76cSLuiz Otavio O Souza *value = (val & TI_GPIO_MASK(pin)) ? 1 : 0; 521e53470feSOleksandr Tymoshenko TI_GPIO_UNLOCK(sc); 522e53470feSOleksandr Tymoshenko 523e53470feSOleksandr Tymoshenko return (0); 524e53470feSOleksandr Tymoshenko } 525e53470feSOleksandr Tymoshenko 526e53470feSOleksandr Tymoshenko /** 527e53470feSOleksandr Tymoshenko * ti_gpio_pin_toggle - Toggles a given GPIO pin 528e53470feSOleksandr Tymoshenko * @dev: gpio device handle 529e53470feSOleksandr Tymoshenko * @pin: the number of the pin 530e53470feSOleksandr Tymoshenko * 531e53470feSOleksandr Tymoshenko * 532e53470feSOleksandr Tymoshenko * LOCKING: 533e53470feSOleksandr Tymoshenko * Internally locks the context 534e53470feSOleksandr Tymoshenko * 535e53470feSOleksandr Tymoshenko * RETURNS: 536e53470feSOleksandr Tymoshenko * Returns 0 on success otherwise a error code 537e53470feSOleksandr Tymoshenko */ 538e53470feSOleksandr Tymoshenko static int 539e53470feSOleksandr Tymoshenko ti_gpio_pin_toggle(device_t dev, uint32_t pin) 540e53470feSOleksandr Tymoshenko { 541e350f76cSLuiz Otavio O Souza struct ti_gpio_softc *sc; 542f9de33d4SLuiz Otavio O Souza uint32_t reg, val; 543e53470feSOleksandr Tymoshenko 544e350f76cSLuiz Otavio O Souza sc = device_get_softc(dev); 545e350f76cSLuiz Otavio O Souza if (ti_gpio_valid_pin(sc, pin) != 0) 546e53470feSOleksandr Tymoshenko return (EINVAL); 547e53470feSOleksandr Tymoshenko 548e53470feSOleksandr Tymoshenko /* Toggle the pin */ 549f9de33d4SLuiz Otavio O Souza TI_GPIO_LOCK(sc); 5505b03aba6SOleksandr Tymoshenko val = ti_gpio_read_4(sc, TI_GPIO_DATAOUT); 551e350f76cSLuiz Otavio O Souza if (val & TI_GPIO_MASK(pin)) 552f9de33d4SLuiz Otavio O Souza reg = TI_GPIO_CLEARDATAOUT; 553e53470feSOleksandr Tymoshenko else 554f9de33d4SLuiz Otavio O Souza reg = TI_GPIO_SETDATAOUT; 5555b03aba6SOleksandr Tymoshenko ti_gpio_write_4(sc, reg, TI_GPIO_MASK(pin)); 556e53470feSOleksandr Tymoshenko TI_GPIO_UNLOCK(sc); 557e53470feSOleksandr Tymoshenko 558e53470feSOleksandr Tymoshenko return (0); 559e53470feSOleksandr Tymoshenko } 560e53470feSOleksandr Tymoshenko 56159c3cb81SAndrew Turner #ifndef INTRNG 562e53470feSOleksandr Tymoshenko /** 563e53470feSOleksandr Tymoshenko * ti_gpio_intr - ISR for all GPIO modules 564e53470feSOleksandr Tymoshenko * @arg: the soft context pointer 565e53470feSOleksandr Tymoshenko * 566e53470feSOleksandr Tymoshenko * LOCKING: 567e53470feSOleksandr Tymoshenko * Internally locks the context 568e53470feSOleksandr Tymoshenko * 569e53470feSOleksandr Tymoshenko */ 5703681c8d7SLuiz Otavio O Souza static int 571e53470feSOleksandr Tymoshenko ti_gpio_intr(void *arg) 572e53470feSOleksandr Tymoshenko { 5733681c8d7SLuiz Otavio O Souza int bank_last, irq; 5743681c8d7SLuiz Otavio O Souza struct intr_event *event; 5753681c8d7SLuiz Otavio O Souza struct ti_gpio_softc *sc; 5763681c8d7SLuiz Otavio O Souza uint32_t reg; 577e53470feSOleksandr Tymoshenko 5783681c8d7SLuiz Otavio O Souza sc = (struct ti_gpio_softc *)arg; 5793681c8d7SLuiz Otavio O Souza bank_last = -1; 5802ed434b4SIan Lepore reg = 0; /* squelch bogus gcc warning */ 5815b03aba6SOleksandr Tymoshenko reg = ti_gpio_intr_status(sc); 5823681c8d7SLuiz Otavio O Souza for (irq = 0; irq < sc->sc_maxpin; irq++) { 5833681c8d7SLuiz Otavio O Souza if ((reg & TI_GPIO_MASK(irq)) == 0) 5843681c8d7SLuiz Otavio O Souza continue; 5853681c8d7SLuiz Otavio O Souza event = sc->sc_events[irq]; 5863681c8d7SLuiz Otavio O Souza if (event != NULL && !TAILQ_EMPTY(&event->ie_handlers)) 5873681c8d7SLuiz Otavio O Souza intr_event_handle(event, NULL); 5883681c8d7SLuiz Otavio O Souza else 5893681c8d7SLuiz Otavio O Souza device_printf(sc->sc_dev, "Stray IRQ %d\n", irq); 5903681c8d7SLuiz Otavio O Souza /* Ack the IRQ Status bit. */ 5915b03aba6SOleksandr Tymoshenko ti_gpio_intr_ack(sc, TI_GPIO_MASK(irq)); 5923681c8d7SLuiz Otavio O Souza } 5933681c8d7SLuiz Otavio O Souza 5943681c8d7SLuiz Otavio O Souza return (FILTER_HANDLED); 595e53470feSOleksandr Tymoshenko } 5962df5562dSSvatopluk Kraus #endif 597e53470feSOleksandr Tymoshenko 5989b1cba84SLuiz Otavio O Souza static int 5995b03aba6SOleksandr Tymoshenko ti_gpio_bank_init(device_t dev) 6009b1cba84SLuiz Otavio O Souza { 6011f1e8f16SLuiz Otavio O Souza int pin; 6029b1cba84SLuiz Otavio O Souza struct ti_gpio_softc *sc; 603c3321180SOleksandr Tymoshenko uint32_t flags, reg_oe, reg_set, rev; 6045b03aba6SOleksandr Tymoshenko clk_ident_t clk; 6059b1cba84SLuiz Otavio O Souza 6069b1cba84SLuiz Otavio O Souza sc = device_get_softc(dev); 6079b1cba84SLuiz Otavio O Souza 6089b1cba84SLuiz Otavio O Souza /* Enable the interface and functional clocks for the module. */ 6095b03aba6SOleksandr Tymoshenko clk = ti_hwmods_get_clock(dev); 6105b03aba6SOleksandr Tymoshenko if (clk == INVALID_CLK_IDENT) { 6115b03aba6SOleksandr Tymoshenko device_printf(dev, "failed to get device id based on ti,hwmods\n"); 6125b03aba6SOleksandr Tymoshenko return (EINVAL); 6135b03aba6SOleksandr Tymoshenko } 6145b03aba6SOleksandr Tymoshenko 6155b03aba6SOleksandr Tymoshenko sc->sc_bank = clk - GPIO1_CLK + ti_first_gpio_bank(); 6165b03aba6SOleksandr Tymoshenko ti_prcm_clk_enable(clk); 6179b1cba84SLuiz Otavio O Souza 6189b1cba84SLuiz Otavio O Souza /* 6199b1cba84SLuiz Otavio O Souza * Read the revision number of the module. TI don't publish the 6209b1cba84SLuiz Otavio O Souza * actual revision numbers, so instead the values have been 6219b1cba84SLuiz Otavio O Souza * determined by experimentation. 6229b1cba84SLuiz Otavio O Souza */ 6235b03aba6SOleksandr Tymoshenko rev = ti_gpio_read_4(sc, TI_GPIO_REVISION); 6249b1cba84SLuiz Otavio O Souza 6259b1cba84SLuiz Otavio O Souza /* Check the revision. */ 626e350f76cSLuiz Otavio O Souza if (rev != ti_gpio_rev()) { 6279b1cba84SLuiz Otavio O Souza device_printf(dev, "Warning: could not determine the revision " 6285b03aba6SOleksandr Tymoshenko "of GPIO module (revision:0x%08x)\n", rev); 6299b1cba84SLuiz Otavio O Souza return (EINVAL); 6309b1cba84SLuiz Otavio O Souza } 6319b1cba84SLuiz Otavio O Souza 6329b1cba84SLuiz Otavio O Souza /* Disable interrupts for all pins. */ 6335b03aba6SOleksandr Tymoshenko ti_gpio_intr_clr(sc, 0xffffffff); 6349b1cba84SLuiz Otavio O Souza 6359b1cba84SLuiz Otavio O Souza /* Init OE register based on pads configuration. */ 6369b1cba84SLuiz Otavio O Souza reg_oe = 0xffffffff; 637c3321180SOleksandr Tymoshenko reg_set = 0; 6389b1cba84SLuiz Otavio O Souza for (pin = 0; pin < PINS_PER_BANK; pin++) { 6395b03aba6SOleksandr Tymoshenko TI_GPIO_GET_FLAGS(dev, pin, &flags); 640c3321180SOleksandr Tymoshenko if (flags & GPIO_PIN_OUTPUT) { 6419b1cba84SLuiz Otavio O Souza reg_oe &= ~(1UL << pin); 642c3321180SOleksandr Tymoshenko if (flags & GPIO_PIN_PULLUP) 643c3321180SOleksandr Tymoshenko reg_set |= (1UL << pin); 644c3321180SOleksandr Tymoshenko } 6459b1cba84SLuiz Otavio O Souza } 6465b03aba6SOleksandr Tymoshenko ti_gpio_write_4(sc, TI_GPIO_OE, reg_oe); 647c3321180SOleksandr Tymoshenko if (reg_set) 648c3321180SOleksandr Tymoshenko ti_gpio_write_4(sc, TI_GPIO_SETDATAOUT, reg_set); 6499b1cba84SLuiz Otavio O Souza 6509b1cba84SLuiz Otavio O Souza return (0); 6519b1cba84SLuiz Otavio O Souza } 6529b1cba84SLuiz Otavio O Souza 653e53470feSOleksandr Tymoshenko /** 654e53470feSOleksandr Tymoshenko * ti_gpio_attach - attach function for the driver 655e53470feSOleksandr Tymoshenko * @dev: gpio device handle 656e53470feSOleksandr Tymoshenko * 657e53470feSOleksandr Tymoshenko * Allocates and sets up the driver context for all GPIO banks. This function 658e53470feSOleksandr Tymoshenko * expects the memory ranges and IRQs to already be allocated to the driver. 659e53470feSOleksandr Tymoshenko * 660e53470feSOleksandr Tymoshenko * LOCKING: 661e53470feSOleksandr Tymoshenko * None 662e53470feSOleksandr Tymoshenko * 663e53470feSOleksandr Tymoshenko * RETURNS: 664e53470feSOleksandr Tymoshenko * Always returns 0 665e53470feSOleksandr Tymoshenko */ 666e53470feSOleksandr Tymoshenko static int 667e53470feSOleksandr Tymoshenko ti_gpio_attach(device_t dev) 668e53470feSOleksandr Tymoshenko { 6699b1cba84SLuiz Otavio O Souza struct ti_gpio_softc *sc; 67059c3cb81SAndrew Turner #ifndef INTRNG 671e53470feSOleksandr Tymoshenko unsigned int i; 6722df5562dSSvatopluk Kraus #endif 6739b1cba84SLuiz Otavio O Souza int err; 674e53470feSOleksandr Tymoshenko 6755b03aba6SOleksandr Tymoshenko sc = device_get_softc(dev); 676e53470feSOleksandr Tymoshenko sc->sc_dev = dev; 677e53470feSOleksandr Tymoshenko TI_GPIO_LOCK_INIT(sc); 678e350f76cSLuiz Otavio O Souza ti_gpio_pin_max(dev, &sc->sc_maxpin); 679f7f77280SLuiz Otavio O Souza sc->sc_maxpin++; 680e53470feSOleksandr Tymoshenko 6815b03aba6SOleksandr Tymoshenko sc->sc_mem_rid = 0; 6825b03aba6SOleksandr Tymoshenko sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 6835b03aba6SOleksandr Tymoshenko &sc->sc_mem_rid, RF_ACTIVE); 6845b03aba6SOleksandr Tymoshenko if (!sc->sc_mem_res) { 685e53470feSOleksandr Tymoshenko device_printf(dev, "Error: could not allocate mem resources\n"); 686876c1bd8SLuiz Otavio O Souza ti_gpio_detach(dev); 687e53470feSOleksandr Tymoshenko return (ENXIO); 688e53470feSOleksandr Tymoshenko } 689e53470feSOleksandr Tymoshenko 6905b03aba6SOleksandr Tymoshenko sc->sc_irq_rid = 0; 6915b03aba6SOleksandr Tymoshenko sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 6925b03aba6SOleksandr Tymoshenko &sc->sc_irq_rid, RF_ACTIVE); 6935b03aba6SOleksandr Tymoshenko if (!sc->sc_irq_res) { 694e53470feSOleksandr Tymoshenko device_printf(dev, "Error: could not allocate irq resources\n"); 695876c1bd8SLuiz Otavio O Souza ti_gpio_detach(dev); 696e53470feSOleksandr Tymoshenko return (ENXIO); 697e53470feSOleksandr Tymoshenko } 698e53470feSOleksandr Tymoshenko 6995b03aba6SOleksandr Tymoshenko /* 7005b03aba6SOleksandr Tymoshenko * Register our interrupt filter for each of the IRQ resources. 7015b03aba6SOleksandr Tymoshenko */ 7025b03aba6SOleksandr Tymoshenko if (bus_setup_intr(dev, sc->sc_irq_res, 7035b03aba6SOleksandr Tymoshenko INTR_TYPE_MISC | INTR_MPSAFE, ti_gpio_intr, NULL, sc, 7045b03aba6SOleksandr Tymoshenko &sc->sc_irq_hdl) != 0) { 7055b03aba6SOleksandr Tymoshenko device_printf(dev, 7065b03aba6SOleksandr Tymoshenko "WARNING: unable to register interrupt filter\n"); 707876c1bd8SLuiz Otavio O Souza ti_gpio_detach(dev); 708e53470feSOleksandr Tymoshenko return (ENXIO); 709e53470feSOleksandr Tymoshenko } 710e53470feSOleksandr Tymoshenko 71159c3cb81SAndrew Turner #ifdef INTRNG 7122df5562dSSvatopluk Kraus if (ti_gpio_pic_attach(sc) != 0) { 7132df5562dSSvatopluk Kraus device_printf(dev, "WARNING: unable to attach PIC\n"); 7142df5562dSSvatopluk Kraus ti_gpio_detach(dev); 7152df5562dSSvatopluk Kraus return (ENXIO); 7162df5562dSSvatopluk Kraus } 7172df5562dSSvatopluk Kraus #else 7183681c8d7SLuiz Otavio O Souza /* 7193681c8d7SLuiz Otavio O Souza * Initialize the interrupt settings. The default is active-low 7203681c8d7SLuiz Otavio O Souza * interrupts. 7213681c8d7SLuiz Otavio O Souza */ 7223681c8d7SLuiz Otavio O Souza sc->sc_irq_trigger = malloc( 7233681c8d7SLuiz Otavio O Souza sizeof(*sc->sc_irq_trigger) * sc->sc_maxpin, 7243681c8d7SLuiz Otavio O Souza M_DEVBUF, M_WAITOK | M_ZERO); 7253681c8d7SLuiz Otavio O Souza sc->sc_irq_polarity = malloc( 7263681c8d7SLuiz Otavio O Souza sizeof(*sc->sc_irq_polarity) * sc->sc_maxpin, 7273681c8d7SLuiz Otavio O Souza M_DEVBUF, M_WAITOK | M_ZERO); 7283681c8d7SLuiz Otavio O Souza for (i = 0; i < sc->sc_maxpin; i++) { 7293681c8d7SLuiz Otavio O Souza sc->sc_irq_trigger[i] = INTR_TRIGGER_LEVEL; 7303681c8d7SLuiz Otavio O Souza sc->sc_irq_polarity[i] = INTR_POLARITY_LOW; 7313681c8d7SLuiz Otavio O Souza } 7323681c8d7SLuiz Otavio O Souza 7333681c8d7SLuiz Otavio O Souza sc->sc_events = malloc(sizeof(struct intr_event *) * sc->sc_maxpin, 7343681c8d7SLuiz Otavio O Souza M_DEVBUF, M_WAITOK | M_ZERO); 7353681c8d7SLuiz Otavio O Souza 7365b03aba6SOleksandr Tymoshenko sc->sc_mask_args = malloc(sizeof(struct ti_gpio_mask_arg) * sc->sc_maxpin, 7375b03aba6SOleksandr Tymoshenko M_DEVBUF, M_WAITOK | M_ZERO); 7382df5562dSSvatopluk Kraus #endif 739e53470feSOleksandr Tymoshenko /* We need to go through each block and ensure the clocks are running and 740e53470feSOleksandr Tymoshenko * the module is enabled. It might be better to do this only when the 741e53470feSOleksandr Tymoshenko * pins are configured which would result in less power used if the GPIO 742e53470feSOleksandr Tymoshenko * pins weren't used ... 743e53470feSOleksandr Tymoshenko */ 7445b03aba6SOleksandr Tymoshenko if (sc->sc_mem_res != NULL) { 7451f1e8f16SLuiz Otavio O Souza /* Initialize the GPIO module. */ 7465b03aba6SOleksandr Tymoshenko err = ti_gpio_bank_init(dev); 7479b1cba84SLuiz Otavio O Souza if (err != 0) { 748876c1bd8SLuiz Otavio O Souza ti_gpio_detach(dev); 7499b1cba84SLuiz Otavio O Souza return (err); 750e53470feSOleksandr Tymoshenko } 751e53470feSOleksandr Tymoshenko } 7525b03aba6SOleksandr Tymoshenko 7537836352bSLuiz Otavio O Souza sc->sc_busdev = gpiobus_attach_bus(dev); 7547836352bSLuiz Otavio O Souza if (sc->sc_busdev == NULL) { 7557836352bSLuiz Otavio O Souza ti_gpio_detach(dev); 7567836352bSLuiz Otavio O Souza return (ENXIO); 7577836352bSLuiz Otavio O Souza } 758e53470feSOleksandr Tymoshenko 7597836352bSLuiz Otavio O Souza return (0); 760e53470feSOleksandr Tymoshenko } 761e53470feSOleksandr Tymoshenko 762e53470feSOleksandr Tymoshenko /** 763e53470feSOleksandr Tymoshenko * ti_gpio_detach - detach function for the driver 764e53470feSOleksandr Tymoshenko * @dev: scm device handle 765e53470feSOleksandr Tymoshenko * 766e53470feSOleksandr Tymoshenko * Allocates and sets up the driver context, this simply entails creating a 767e53470feSOleksandr Tymoshenko * bus mappings for the SCM register set. 768e53470feSOleksandr Tymoshenko * 769e53470feSOleksandr Tymoshenko * LOCKING: 770e53470feSOleksandr Tymoshenko * None 771e53470feSOleksandr Tymoshenko * 772e53470feSOleksandr Tymoshenko * RETURNS: 773e53470feSOleksandr Tymoshenko * Always returns 0 774e53470feSOleksandr Tymoshenko */ 775e53470feSOleksandr Tymoshenko static int 776e53470feSOleksandr Tymoshenko ti_gpio_detach(device_t dev) 777e53470feSOleksandr Tymoshenko { 778e53470feSOleksandr Tymoshenko struct ti_gpio_softc *sc = device_get_softc(dev); 779e53470feSOleksandr Tymoshenko 780e53470feSOleksandr Tymoshenko KASSERT(mtx_initialized(&sc->sc_mtx), ("gpio mutex not initialized")); 781e53470feSOleksandr Tymoshenko 782e53470feSOleksandr Tymoshenko /* Disable all interrupts */ 7835b03aba6SOleksandr Tymoshenko if (sc->sc_mem_res != NULL) 7845b03aba6SOleksandr Tymoshenko ti_gpio_intr_clr(sc, 0xffffffff); 7857836352bSLuiz Otavio O Souza gpiobus_detach_bus(dev); 78659c3cb81SAndrew Turner #ifdef INTRNG 7872df5562dSSvatopluk Kraus if (sc->sc_isrcs != NULL) 7882df5562dSSvatopluk Kraus ti_gpio_pic_detach(sc); 7892df5562dSSvatopluk Kraus #else 790876c1bd8SLuiz Otavio O Souza if (sc->sc_events) 7913681c8d7SLuiz Otavio O Souza free(sc->sc_events, M_DEVBUF); 7925b03aba6SOleksandr Tymoshenko if (sc->sc_mask_args) 7935b03aba6SOleksandr Tymoshenko free(sc->sc_mask_args, M_DEVBUF); 794876c1bd8SLuiz Otavio O Souza if (sc->sc_irq_polarity) 7953681c8d7SLuiz Otavio O Souza free(sc->sc_irq_polarity, M_DEVBUF); 796876c1bd8SLuiz Otavio O Souza if (sc->sc_irq_trigger) 7973681c8d7SLuiz Otavio O Souza free(sc->sc_irq_trigger, M_DEVBUF); 7982df5562dSSvatopluk Kraus #endif 7999b1cba84SLuiz Otavio O Souza /* Release the memory and IRQ resources. */ 8005b03aba6SOleksandr Tymoshenko if (sc->sc_irq_hdl) { 8015b03aba6SOleksandr Tymoshenko bus_teardown_intr(dev, sc->sc_irq_res, 8025b03aba6SOleksandr Tymoshenko sc->sc_irq_hdl); 8035b03aba6SOleksandr Tymoshenko } 8045b03aba6SOleksandr Tymoshenko bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irq_rid, 8055b03aba6SOleksandr Tymoshenko sc->sc_irq_res); 8065b03aba6SOleksandr Tymoshenko bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_mem_rid, 8075b03aba6SOleksandr Tymoshenko sc->sc_mem_res); 808e53470feSOleksandr Tymoshenko TI_GPIO_LOCK_DESTROY(sc); 809e53470feSOleksandr Tymoshenko 810e53470feSOleksandr Tymoshenko return (0); 811e53470feSOleksandr Tymoshenko } 812e53470feSOleksandr Tymoshenko 81359c3cb81SAndrew Turner #ifdef INTRNG 8142df5562dSSvatopluk Kraus static inline void 8152202c379SSvatopluk Kraus ti_gpio_rwreg_modify(struct ti_gpio_softc *sc, uint32_t reg, uint32_t mask, 8162202c379SSvatopluk Kraus bool set_bits) 8172df5562dSSvatopluk Kraus { 8182202c379SSvatopluk Kraus uint32_t value; 8192df5562dSSvatopluk Kraus 8202202c379SSvatopluk Kraus value = ti_gpio_read_4(sc, reg); 8212202c379SSvatopluk Kraus ti_gpio_write_4(sc, reg, set_bits ? value | mask : value & ~mask); 8222df5562dSSvatopluk Kraus } 8232df5562dSSvatopluk Kraus 8242df5562dSSvatopluk Kraus static inline void 8252df5562dSSvatopluk Kraus ti_gpio_isrc_mask(struct ti_gpio_softc *sc, struct ti_gpio_irqsrc *tgi) 8262df5562dSSvatopluk Kraus { 8272df5562dSSvatopluk Kraus 8282df5562dSSvatopluk Kraus /* Writing a 0 has no effect. */ 8292df5562dSSvatopluk Kraus ti_gpio_intr_clr(sc, tgi->tgi_mask); 8302df5562dSSvatopluk Kraus } 8312df5562dSSvatopluk Kraus 8322df5562dSSvatopluk Kraus static inline void 8332df5562dSSvatopluk Kraus ti_gpio_isrc_unmask(struct ti_gpio_softc *sc, struct ti_gpio_irqsrc *tgi) 8342df5562dSSvatopluk Kraus { 8352df5562dSSvatopluk Kraus 8362df5562dSSvatopluk Kraus /* Writing a 0 has no effect. */ 8372df5562dSSvatopluk Kraus ti_gpio_intr_set(sc, tgi->tgi_mask); 8382df5562dSSvatopluk Kraus } 8392df5562dSSvatopluk Kraus 8402df5562dSSvatopluk Kraus static inline void 8412df5562dSSvatopluk Kraus ti_gpio_isrc_eoi(struct ti_gpio_softc *sc, struct ti_gpio_irqsrc *tgi) 8422df5562dSSvatopluk Kraus { 8432df5562dSSvatopluk Kraus 8442df5562dSSvatopluk Kraus /* Writing a 0 has no effect. */ 8452df5562dSSvatopluk Kraus ti_gpio_intr_ack(sc, tgi->tgi_mask); 8462df5562dSSvatopluk Kraus } 8472df5562dSSvatopluk Kraus 8482df5562dSSvatopluk Kraus static inline bool 8492df5562dSSvatopluk Kraus ti_gpio_isrc_is_level(struct ti_gpio_irqsrc *tgi) 8502df5562dSSvatopluk Kraus { 8512df5562dSSvatopluk Kraus 8522202c379SSvatopluk Kraus return (tgi->tgi_mode == GPIO_INTR_LEVEL_LOW || 8532202c379SSvatopluk Kraus tgi->tgi_mode == GPIO_INTR_LEVEL_HIGH); 8542df5562dSSvatopluk Kraus } 8552df5562dSSvatopluk Kraus 8562df5562dSSvatopluk Kraus static int 8572df5562dSSvatopluk Kraus ti_gpio_intr(void *arg) 8582df5562dSSvatopluk Kraus { 8592df5562dSSvatopluk Kraus u_int irq; 8602df5562dSSvatopluk Kraus uint32_t reg; 8612df5562dSSvatopluk Kraus struct ti_gpio_softc *sc; 8622df5562dSSvatopluk Kraus struct trapframe *tf; 8632df5562dSSvatopluk Kraus struct ti_gpio_irqsrc *tgi; 8642df5562dSSvatopluk Kraus 8652df5562dSSvatopluk Kraus sc = (struct ti_gpio_softc *)arg; 8662df5562dSSvatopluk Kraus tf = curthread->td_intr_frame; 8672df5562dSSvatopluk Kraus 8682df5562dSSvatopluk Kraus reg = ti_gpio_intr_status(sc); 8692df5562dSSvatopluk Kraus for (irq = 0; irq < sc->sc_maxpin; irq++) { 8702df5562dSSvatopluk Kraus tgi = &sc->sc_isrcs[irq]; 8712df5562dSSvatopluk Kraus if ((reg & tgi->tgi_mask) == 0) 8722df5562dSSvatopluk Kraus continue; 8732df5562dSSvatopluk Kraus if (!ti_gpio_isrc_is_level(tgi)) 8742df5562dSSvatopluk Kraus ti_gpio_isrc_eoi(sc, tgi); 8752df5562dSSvatopluk Kraus if (intr_isrc_dispatch(&tgi->tgi_isrc, tf) != 0) { 8762df5562dSSvatopluk Kraus ti_gpio_isrc_mask(sc, tgi); 8772df5562dSSvatopluk Kraus if (ti_gpio_isrc_is_level(tgi)) 8782df5562dSSvatopluk Kraus ti_gpio_isrc_eoi(sc, tgi); 8792df5562dSSvatopluk Kraus device_printf(sc->sc_dev, "Stray irq %u disabled\n", 8802df5562dSSvatopluk Kraus irq); 8812df5562dSSvatopluk Kraus } 8822df5562dSSvatopluk Kraus } 8832df5562dSSvatopluk Kraus return (FILTER_HANDLED); 8842df5562dSSvatopluk Kraus } 8852df5562dSSvatopluk Kraus 8862df5562dSSvatopluk Kraus static int 8872df5562dSSvatopluk Kraus ti_gpio_pic_attach(struct ti_gpio_softc *sc) 8882df5562dSSvatopluk Kraus { 8892df5562dSSvatopluk Kraus int error; 8902df5562dSSvatopluk Kraus uint32_t irq; 8912df5562dSSvatopluk Kraus const char *name; 8922df5562dSSvatopluk Kraus 8932df5562dSSvatopluk Kraus sc->sc_isrcs = malloc(sizeof(*sc->sc_isrcs) * sc->sc_maxpin, M_DEVBUF, 8942df5562dSSvatopluk Kraus M_WAITOK | M_ZERO); 8952df5562dSSvatopluk Kraus 8962df5562dSSvatopluk Kraus name = device_get_nameunit(sc->sc_dev); 8972df5562dSSvatopluk Kraus for (irq = 0; irq < sc->sc_maxpin; irq++) { 8982df5562dSSvatopluk Kraus sc->sc_isrcs[irq].tgi_irq = irq; 8992df5562dSSvatopluk Kraus sc->sc_isrcs[irq].tgi_mask = TI_GPIO_MASK(irq); 9002202c379SSvatopluk Kraus sc->sc_isrcs[irq].tgi_mode = GPIO_INTR_CONFORM; 9012df5562dSSvatopluk Kraus 9022df5562dSSvatopluk Kraus error = intr_isrc_register(&sc->sc_isrcs[irq].tgi_isrc, 9032df5562dSSvatopluk Kraus sc->sc_dev, 0, "%s,%u", name, irq); 9042df5562dSSvatopluk Kraus if (error != 0) 9052df5562dSSvatopluk Kraus return (error); /* XXX deregister ISRCs */ 9062df5562dSSvatopluk Kraus } 9072df5562dSSvatopluk Kraus return (intr_pic_register(sc->sc_dev, 9082df5562dSSvatopluk Kraus OF_xref_from_node(ofw_bus_get_node(sc->sc_dev)))); 9092df5562dSSvatopluk Kraus } 9102df5562dSSvatopluk Kraus 9112df5562dSSvatopluk Kraus static int 9122df5562dSSvatopluk Kraus ti_gpio_pic_detach(struct ti_gpio_softc *sc) 9132df5562dSSvatopluk Kraus { 9142df5562dSSvatopluk Kraus 9152df5562dSSvatopluk Kraus /* 9162df5562dSSvatopluk Kraus * There has not been established any procedure yet 9172df5562dSSvatopluk Kraus * how to detach PIC from living system correctly. 9182df5562dSSvatopluk Kraus */ 9192df5562dSSvatopluk Kraus device_printf(sc->sc_dev, "%s: not implemented yet\n", __func__); 9202df5562dSSvatopluk Kraus return (EBUSY); 9212df5562dSSvatopluk Kraus } 9222df5562dSSvatopluk Kraus 9232df5562dSSvatopluk Kraus static void 9242202c379SSvatopluk Kraus ti_gpio_pic_config_intr(struct ti_gpio_softc *sc, struct ti_gpio_irqsrc *tgi, 9252202c379SSvatopluk Kraus uint32_t mode) 9262202c379SSvatopluk Kraus { 9272202c379SSvatopluk Kraus 9282202c379SSvatopluk Kraus TI_GPIO_LOCK(sc); 9292202c379SSvatopluk Kraus ti_gpio_rwreg_modify(sc, TI_GPIO_RISINGDETECT, tgi->tgi_mask, 9302202c379SSvatopluk Kraus mode == GPIO_INTR_EDGE_RISING || mode == GPIO_INTR_EDGE_BOTH); 9312202c379SSvatopluk Kraus ti_gpio_rwreg_modify(sc, TI_GPIO_FALLINGDETECT, tgi->tgi_mask, 9322202c379SSvatopluk Kraus mode == GPIO_INTR_EDGE_FALLING || mode == GPIO_INTR_EDGE_BOTH); 9332202c379SSvatopluk Kraus ti_gpio_rwreg_modify(sc, TI_GPIO_LEVELDETECT1, tgi->tgi_mask, 9342202c379SSvatopluk Kraus mode == GPIO_INTR_LEVEL_HIGH); 9352202c379SSvatopluk Kraus ti_gpio_rwreg_modify(sc, TI_GPIO_LEVELDETECT0, tgi->tgi_mask, 9362202c379SSvatopluk Kraus mode == GPIO_INTR_LEVEL_LOW); 9372202c379SSvatopluk Kraus tgi->tgi_mode = mode; 9382202c379SSvatopluk Kraus TI_GPIO_UNLOCK(sc); 9392202c379SSvatopluk Kraus } 9402202c379SSvatopluk Kraus 9412202c379SSvatopluk Kraus static void 9422df5562dSSvatopluk Kraus ti_gpio_pic_disable_intr(device_t dev, struct intr_irqsrc *isrc) 9432df5562dSSvatopluk Kraus { 9442df5562dSSvatopluk Kraus struct ti_gpio_softc *sc = device_get_softc(dev); 9452df5562dSSvatopluk Kraus struct ti_gpio_irqsrc *tgi = (struct ti_gpio_irqsrc *)isrc; 9462df5562dSSvatopluk Kraus 9472df5562dSSvatopluk Kraus ti_gpio_isrc_mask(sc, tgi); 9482df5562dSSvatopluk Kraus } 9492df5562dSSvatopluk Kraus 9502df5562dSSvatopluk Kraus static void 9512df5562dSSvatopluk Kraus ti_gpio_pic_enable_intr(device_t dev, struct intr_irqsrc *isrc) 9522df5562dSSvatopluk Kraus { 9532df5562dSSvatopluk Kraus struct ti_gpio_softc *sc = device_get_softc(dev); 9542df5562dSSvatopluk Kraus struct ti_gpio_irqsrc *tgi = (struct ti_gpio_irqsrc *)isrc; 9552df5562dSSvatopluk Kraus 9562df5562dSSvatopluk Kraus arm_irq_memory_barrier(tgi->tgi_irq); 9572df5562dSSvatopluk Kraus ti_gpio_isrc_unmask(sc, tgi); 9582df5562dSSvatopluk Kraus } 9592df5562dSSvatopluk Kraus 9602df5562dSSvatopluk Kraus static int 9611a251c53SSvatopluk Kraus ti_gpio_pic_map_fdt(struct ti_gpio_softc *sc, struct intr_map_data_fdt *daf, 9622202c379SSvatopluk Kraus u_int *irqp, uint32_t *modep) 9632df5562dSSvatopluk Kraus { 9642202c379SSvatopluk Kraus uint32_t mode; 9652df5562dSSvatopluk Kraus 9662df5562dSSvatopluk Kraus /* 9672df5562dSSvatopluk Kraus * The first cell is the interrupt number. 9682df5562dSSvatopluk Kraus * The second cell is used to specify flags: 9692df5562dSSvatopluk Kraus * bits[3:0] trigger type and level flags: 9702df5562dSSvatopluk Kraus * 1 = low-to-high edge triggered. 9712df5562dSSvatopluk Kraus * 2 = high-to-low edge triggered. 9722df5562dSSvatopluk Kraus * 4 = active high level-sensitive. 9732df5562dSSvatopluk Kraus * 8 = active low level-sensitive. 9742df5562dSSvatopluk Kraus */ 9751a251c53SSvatopluk Kraus if (daf->ncells != 2 || daf->cells[0] >= sc->sc_maxpin) 9762df5562dSSvatopluk Kraus return (EINVAL); 9772df5562dSSvatopluk Kraus 9782202c379SSvatopluk Kraus /* Only reasonable modes are supported. */ 9791a251c53SSvatopluk Kraus if (daf->cells[1] == 1) 9802202c379SSvatopluk Kraus mode = GPIO_INTR_EDGE_RISING; 9811a251c53SSvatopluk Kraus else if (daf->cells[1] == 2) 9822202c379SSvatopluk Kraus mode = GPIO_INTR_EDGE_FALLING; 9831a251c53SSvatopluk Kraus else if (daf->cells[1] == 3) 9842202c379SSvatopluk Kraus mode = GPIO_INTR_EDGE_BOTH; 9851a251c53SSvatopluk Kraus else if (daf->cells[1] == 4) 9862202c379SSvatopluk Kraus mode = GPIO_INTR_LEVEL_HIGH; 9871a251c53SSvatopluk Kraus else if (daf->cells[1] == 8) 9882202c379SSvatopluk Kraus mode = GPIO_INTR_LEVEL_LOW; 9892df5562dSSvatopluk Kraus else 9902df5562dSSvatopluk Kraus return (EINVAL); 9912df5562dSSvatopluk Kraus 9921a251c53SSvatopluk Kraus *irqp = daf->cells[0]; 9932202c379SSvatopluk Kraus if (modep != NULL) 9942202c379SSvatopluk Kraus *modep = mode; 9952df5562dSSvatopluk Kraus return (0); 9962df5562dSSvatopluk Kraus } 9972df5562dSSvatopluk Kraus 9982df5562dSSvatopluk Kraus static int 9991a251c53SSvatopluk Kraus ti_gpio_pic_map_gpio(struct ti_gpio_softc *sc, struct intr_map_data_gpio *dag, 10001a251c53SSvatopluk Kraus u_int *irqp, uint32_t *modep) 10011a251c53SSvatopluk Kraus { 10021a251c53SSvatopluk Kraus uint32_t mode; 10031a251c53SSvatopluk Kraus 10041a251c53SSvatopluk Kraus if (dag->gpio_pin_num >= sc->sc_maxpin) 10051a251c53SSvatopluk Kraus return (EINVAL); 10061a251c53SSvatopluk Kraus 10071a251c53SSvatopluk Kraus mode = dag->gpio_intr_mode; 10081a251c53SSvatopluk Kraus if (mode != GPIO_INTR_LEVEL_LOW && mode != GPIO_INTR_LEVEL_HIGH && 10091a251c53SSvatopluk Kraus mode != GPIO_INTR_EDGE_RISING && mode != GPIO_INTR_EDGE_FALLING && 10101a251c53SSvatopluk Kraus mode != GPIO_INTR_EDGE_BOTH) 10111a251c53SSvatopluk Kraus return (EINVAL); 10121a251c53SSvatopluk Kraus 10131a251c53SSvatopluk Kraus *irqp = dag->gpio_pin_num; 10141a251c53SSvatopluk Kraus if (modep != NULL) 10151a251c53SSvatopluk Kraus *modep = mode; 10161a251c53SSvatopluk Kraus return (0); 10171a251c53SSvatopluk Kraus } 10181a251c53SSvatopluk Kraus 10191a251c53SSvatopluk Kraus static int 10201a251c53SSvatopluk Kraus ti_gpio_pic_map(struct ti_gpio_softc *sc, struct intr_map_data *data, 10211a251c53SSvatopluk Kraus u_int *irqp, uint32_t *modep) 10221a251c53SSvatopluk Kraus { 10231a251c53SSvatopluk Kraus 10241a251c53SSvatopluk Kraus switch (data->type) { 10251a251c53SSvatopluk Kraus case INTR_MAP_DATA_FDT: 10261a251c53SSvatopluk Kraus return (ti_gpio_pic_map_fdt(sc, 10271a251c53SSvatopluk Kraus (struct intr_map_data_fdt *)data, irqp, modep)); 10281a251c53SSvatopluk Kraus case INTR_MAP_DATA_GPIO: 10291a251c53SSvatopluk Kraus return (ti_gpio_pic_map_gpio(sc, 10301a251c53SSvatopluk Kraus (struct intr_map_data_gpio *)data, irqp, modep)); 10311a251c53SSvatopluk Kraus default: 10321a251c53SSvatopluk Kraus return (ENOTSUP); 10331a251c53SSvatopluk Kraus } 10341a251c53SSvatopluk Kraus } 10351a251c53SSvatopluk Kraus 10361a251c53SSvatopluk Kraus static int 10372df5562dSSvatopluk Kraus ti_gpio_pic_map_intr(device_t dev, struct intr_map_data *data, 10382df5562dSSvatopluk Kraus struct intr_irqsrc **isrcp) 10392df5562dSSvatopluk Kraus { 10402df5562dSSvatopluk Kraus int error; 10412df5562dSSvatopluk Kraus u_int irq; 10421a251c53SSvatopluk Kraus struct ti_gpio_softc *sc = device_get_softc(dev); 10432df5562dSSvatopluk Kraus 10441a251c53SSvatopluk Kraus error = ti_gpio_pic_map(sc, data, &irq, NULL); 10452df5562dSSvatopluk Kraus if (error == 0) 10462df5562dSSvatopluk Kraus *isrcp = &sc->sc_isrcs[irq].tgi_isrc; 10472df5562dSSvatopluk Kraus return (error); 10482df5562dSSvatopluk Kraus } 10492df5562dSSvatopluk Kraus 10502df5562dSSvatopluk Kraus static void 10512df5562dSSvatopluk Kraus ti_gpio_pic_post_filter(device_t dev, struct intr_irqsrc *isrc) 10522df5562dSSvatopluk Kraus { 10532df5562dSSvatopluk Kraus struct ti_gpio_softc *sc = device_get_softc(dev); 10542df5562dSSvatopluk Kraus struct ti_gpio_irqsrc *tgi = (struct ti_gpio_irqsrc *)isrc; 10552df5562dSSvatopluk Kraus 10562df5562dSSvatopluk Kraus if (ti_gpio_isrc_is_level(tgi)) 10572df5562dSSvatopluk Kraus ti_gpio_isrc_eoi(sc, tgi); 10582df5562dSSvatopluk Kraus } 10592df5562dSSvatopluk Kraus 10602df5562dSSvatopluk Kraus static void 10612df5562dSSvatopluk Kraus ti_gpio_pic_post_ithread(device_t dev, struct intr_irqsrc *isrc) 10622df5562dSSvatopluk Kraus { 10632df5562dSSvatopluk Kraus 10642df5562dSSvatopluk Kraus ti_gpio_pic_enable_intr(dev, isrc); 10652df5562dSSvatopluk Kraus } 10662df5562dSSvatopluk Kraus 10672df5562dSSvatopluk Kraus static void 10682df5562dSSvatopluk Kraus ti_gpio_pic_pre_ithread(device_t dev, struct intr_irqsrc *isrc) 10692df5562dSSvatopluk Kraus { 10702df5562dSSvatopluk Kraus struct ti_gpio_softc *sc = device_get_softc(dev); 10712df5562dSSvatopluk Kraus struct ti_gpio_irqsrc *tgi = (struct ti_gpio_irqsrc *)isrc; 10722df5562dSSvatopluk Kraus 10732df5562dSSvatopluk Kraus ti_gpio_isrc_mask(sc, tgi); 10742df5562dSSvatopluk Kraus if (ti_gpio_isrc_is_level(tgi)) 10752df5562dSSvatopluk Kraus ti_gpio_isrc_eoi(sc, tgi); 10762df5562dSSvatopluk Kraus } 10772df5562dSSvatopluk Kraus 10782df5562dSSvatopluk Kraus static int 10792df5562dSSvatopluk Kraus ti_gpio_pic_setup_intr(device_t dev, struct intr_irqsrc *isrc, 10802df5562dSSvatopluk Kraus struct resource *res, struct intr_map_data *data) 10812df5562dSSvatopluk Kraus { 10822df5562dSSvatopluk Kraus u_int irq; 10832202c379SSvatopluk Kraus uint32_t mode; 10842df5562dSSvatopluk Kraus struct ti_gpio_softc *sc; 10852df5562dSSvatopluk Kraus struct ti_gpio_irqsrc *tgi; 10862df5562dSSvatopluk Kraus 10871a251c53SSvatopluk Kraus if (data == NULL) 10882df5562dSSvatopluk Kraus return (ENOTSUP); 10892df5562dSSvatopluk Kraus 10902df5562dSSvatopluk Kraus sc = device_get_softc(dev); 10912df5562dSSvatopluk Kraus tgi = (struct ti_gpio_irqsrc *)isrc; 10922df5562dSSvatopluk Kraus 10932df5562dSSvatopluk Kraus /* Get and check config for an interrupt. */ 10941a251c53SSvatopluk Kraus if (ti_gpio_pic_map(sc, data, &irq, &mode) != 0 || tgi->tgi_irq != irq) 10952df5562dSSvatopluk Kraus return (EINVAL); 10962df5562dSSvatopluk Kraus 10972df5562dSSvatopluk Kraus /* 10982df5562dSSvatopluk Kraus * If this is a setup for another handler, 10992df5562dSSvatopluk Kraus * only check that its configuration match. 11002df5562dSSvatopluk Kraus */ 11012df5562dSSvatopluk Kraus if (isrc->isrc_handlers != 0) 11022202c379SSvatopluk Kraus return (tgi->tgi_mode == mode ? 0 : EINVAL); 11032df5562dSSvatopluk Kraus 11042202c379SSvatopluk Kraus ti_gpio_pic_config_intr(sc, tgi, mode); 11052df5562dSSvatopluk Kraus return (0); 11062df5562dSSvatopluk Kraus } 11072df5562dSSvatopluk Kraus 11082df5562dSSvatopluk Kraus static int 11092df5562dSSvatopluk Kraus ti_gpio_pic_teardown_intr(device_t dev, struct intr_irqsrc *isrc, 11102df5562dSSvatopluk Kraus struct resource *res, struct intr_map_data *data) 11112df5562dSSvatopluk Kraus { 11122df5562dSSvatopluk Kraus struct ti_gpio_softc *sc = device_get_softc(dev); 11132df5562dSSvatopluk Kraus struct ti_gpio_irqsrc *tgi = (struct ti_gpio_irqsrc *)isrc; 11142df5562dSSvatopluk Kraus 11152202c379SSvatopluk Kraus if (isrc->isrc_handlers == 0) 11162202c379SSvatopluk Kraus ti_gpio_pic_config_intr(sc, tgi, GPIO_INTR_CONFORM); 11172df5562dSSvatopluk Kraus return (0); 11182df5562dSSvatopluk Kraus } 11192df5562dSSvatopluk Kraus 11202df5562dSSvatopluk Kraus #else 11213681c8d7SLuiz Otavio O Souza static uint32_t 11223681c8d7SLuiz Otavio O Souza ti_gpio_intr_reg(struct ti_gpio_softc *sc, int irq) 11233681c8d7SLuiz Otavio O Souza { 11243681c8d7SLuiz Otavio O Souza 11253681c8d7SLuiz Otavio O Souza if (ti_gpio_valid_pin(sc, irq) != 0) 11263681c8d7SLuiz Otavio O Souza return (0); 11273681c8d7SLuiz Otavio O Souza 11283681c8d7SLuiz Otavio O Souza if (sc->sc_irq_trigger[irq] == INTR_TRIGGER_LEVEL) { 11293681c8d7SLuiz Otavio O Souza if (sc->sc_irq_polarity[irq] == INTR_POLARITY_LOW) 11303681c8d7SLuiz Otavio O Souza return (TI_GPIO_LEVELDETECT0); 11313681c8d7SLuiz Otavio O Souza else if (sc->sc_irq_polarity[irq] == INTR_POLARITY_HIGH) 11323681c8d7SLuiz Otavio O Souza return (TI_GPIO_LEVELDETECT1); 11333681c8d7SLuiz Otavio O Souza } else if (sc->sc_irq_trigger[irq] == INTR_TRIGGER_EDGE) { 11343681c8d7SLuiz Otavio O Souza if (sc->sc_irq_polarity[irq] == INTR_POLARITY_LOW) 11353681c8d7SLuiz Otavio O Souza return (TI_GPIO_FALLINGDETECT); 11363681c8d7SLuiz Otavio O Souza else if (sc->sc_irq_polarity[irq] == INTR_POLARITY_HIGH) 11373681c8d7SLuiz Otavio O Souza return (TI_GPIO_RISINGDETECT); 11383681c8d7SLuiz Otavio O Souza } 11393681c8d7SLuiz Otavio O Souza 11403681c8d7SLuiz Otavio O Souza return (0); 11413681c8d7SLuiz Otavio O Souza } 11423681c8d7SLuiz Otavio O Souza 11433681c8d7SLuiz Otavio O Souza static void 11445b03aba6SOleksandr Tymoshenko ti_gpio_mask_irq_internal(struct ti_gpio_softc *sc, int irq) 11453681c8d7SLuiz Otavio O Souza { 11463681c8d7SLuiz Otavio O Souza uint32_t reg, val; 11473681c8d7SLuiz Otavio O Souza 11485b03aba6SOleksandr Tymoshenko if (ti_gpio_valid_pin(sc, irq) != 0) 11493681c8d7SLuiz Otavio O Souza return; 11503681c8d7SLuiz Otavio O Souza 11515b03aba6SOleksandr Tymoshenko TI_GPIO_LOCK(sc); 11525b03aba6SOleksandr Tymoshenko ti_gpio_intr_clr(sc, TI_GPIO_MASK(irq)); 11535b03aba6SOleksandr Tymoshenko reg = ti_gpio_intr_reg(sc, irq); 11543681c8d7SLuiz Otavio O Souza if (reg != 0) { 11555b03aba6SOleksandr Tymoshenko val = ti_gpio_read_4(sc, reg); 11563681c8d7SLuiz Otavio O Souza val &= ~TI_GPIO_MASK(irq); 11575b03aba6SOleksandr Tymoshenko ti_gpio_write_4(sc, reg, val); 11583681c8d7SLuiz Otavio O Souza } 11595b03aba6SOleksandr Tymoshenko TI_GPIO_UNLOCK(sc); 11605b03aba6SOleksandr Tymoshenko } 11615b03aba6SOleksandr Tymoshenko 11625b03aba6SOleksandr Tymoshenko static void 11635b03aba6SOleksandr Tymoshenko ti_gpio_unmask_irq_internal(struct ti_gpio_softc *sc, int irq) 11645b03aba6SOleksandr Tymoshenko { 11655b03aba6SOleksandr Tymoshenko uint32_t reg, val; 11665b03aba6SOleksandr Tymoshenko 11675b03aba6SOleksandr Tymoshenko if (ti_gpio_valid_pin(sc, irq) != 0) 11685b03aba6SOleksandr Tymoshenko return; 11695b03aba6SOleksandr Tymoshenko 11705b03aba6SOleksandr Tymoshenko TI_GPIO_LOCK(sc); 11715b03aba6SOleksandr Tymoshenko reg = ti_gpio_intr_reg(sc, irq); 11725b03aba6SOleksandr Tymoshenko if (reg != 0) { 11735b03aba6SOleksandr Tymoshenko val = ti_gpio_read_4(sc, reg); 11745b03aba6SOleksandr Tymoshenko val |= TI_GPIO_MASK(irq); 11755b03aba6SOleksandr Tymoshenko ti_gpio_write_4(sc, reg, val); 11765b03aba6SOleksandr Tymoshenko ti_gpio_intr_set(sc, TI_GPIO_MASK(irq)); 11775b03aba6SOleksandr Tymoshenko } 11785b03aba6SOleksandr Tymoshenko TI_GPIO_UNLOCK(sc); 11795b03aba6SOleksandr Tymoshenko } 11805b03aba6SOleksandr Tymoshenko 11815b03aba6SOleksandr Tymoshenko static void 11825b03aba6SOleksandr Tymoshenko ti_gpio_mask_irq(void *source) 11835b03aba6SOleksandr Tymoshenko { 11845b03aba6SOleksandr Tymoshenko struct ti_gpio_mask_arg *arg = source; 11855b03aba6SOleksandr Tymoshenko 11865b03aba6SOleksandr Tymoshenko ti_gpio_mask_irq_internal(arg->softc, arg->pin); 11873681c8d7SLuiz Otavio O Souza } 11883681c8d7SLuiz Otavio O Souza 11893681c8d7SLuiz Otavio O Souza static void 11903681c8d7SLuiz Otavio O Souza ti_gpio_unmask_irq(void *source) 11913681c8d7SLuiz Otavio O Souza { 11925b03aba6SOleksandr Tymoshenko struct ti_gpio_mask_arg *arg = source; 11933681c8d7SLuiz Otavio O Souza 11945b03aba6SOleksandr Tymoshenko ti_gpio_unmask_irq_internal(arg->softc, arg->pin); 11953681c8d7SLuiz Otavio O Souza } 11963681c8d7SLuiz Otavio O Souza 11973681c8d7SLuiz Otavio O Souza static int 11983681c8d7SLuiz Otavio O Souza ti_gpio_activate_resource(device_t dev, device_t child, int type, int rid, 11993681c8d7SLuiz Otavio O Souza struct resource *res) 12003681c8d7SLuiz Otavio O Souza { 12017b25d1d6SOleksandr Tymoshenko struct ti_gpio_mask_arg mask_arg; 12023681c8d7SLuiz Otavio O Souza 12033681c8d7SLuiz Otavio O Souza if (type != SYS_RES_IRQ) 12043681c8d7SLuiz Otavio O Souza return (ENXIO); 12053681c8d7SLuiz Otavio O Souza 12063681c8d7SLuiz Otavio O Souza /* Unmask the interrupt. */ 12077b25d1d6SOleksandr Tymoshenko mask_arg.pin = rman_get_start(res); 12087b25d1d6SOleksandr Tymoshenko mask_arg.softc = device_get_softc(dev); 12097b25d1d6SOleksandr Tymoshenko 12107b25d1d6SOleksandr Tymoshenko ti_gpio_unmask_irq((void *)&mask_arg); 12113681c8d7SLuiz Otavio O Souza 12123681c8d7SLuiz Otavio O Souza return (0); 12133681c8d7SLuiz Otavio O Souza } 12143681c8d7SLuiz Otavio O Souza 12153681c8d7SLuiz Otavio O Souza static int 12163681c8d7SLuiz Otavio O Souza ti_gpio_deactivate_resource(device_t dev, device_t child, int type, int rid, 12173681c8d7SLuiz Otavio O Souza struct resource *res) 12183681c8d7SLuiz Otavio O Souza { 12193681c8d7SLuiz Otavio O Souza int pin; 12203681c8d7SLuiz Otavio O Souza 12213681c8d7SLuiz Otavio O Souza if (type != SYS_RES_IRQ) 12223681c8d7SLuiz Otavio O Souza return (ENXIO); 12233681c8d7SLuiz Otavio O Souza 12243681c8d7SLuiz Otavio O Souza /* Mask the interrupt. */ 12253681c8d7SLuiz Otavio O Souza pin = rman_get_start(res); 12263681c8d7SLuiz Otavio O Souza ti_gpio_mask_irq((void *)(uintptr_t)pin); 12273681c8d7SLuiz Otavio O Souza 12283681c8d7SLuiz Otavio O Souza return (0); 12293681c8d7SLuiz Otavio O Souza } 12303681c8d7SLuiz Otavio O Souza 12313681c8d7SLuiz Otavio O Souza static int 12323681c8d7SLuiz Otavio O Souza ti_gpio_config_intr(device_t dev, int irq, enum intr_trigger trig, 12333681c8d7SLuiz Otavio O Souza enum intr_polarity pol) 12343681c8d7SLuiz Otavio O Souza { 12353681c8d7SLuiz Otavio O Souza struct ti_gpio_softc *sc; 12363681c8d7SLuiz Otavio O Souza uint32_t oldreg, reg, val; 12373681c8d7SLuiz Otavio O Souza 12383681c8d7SLuiz Otavio O Souza sc = device_get_softc(dev); 12393681c8d7SLuiz Otavio O Souza if (ti_gpio_valid_pin(sc, irq) != 0) 12403681c8d7SLuiz Otavio O Souza return (EINVAL); 12413681c8d7SLuiz Otavio O Souza 12423681c8d7SLuiz Otavio O Souza /* There is no standard trigger or polarity. */ 12433681c8d7SLuiz Otavio O Souza if (trig == INTR_TRIGGER_CONFORM || pol == INTR_POLARITY_CONFORM) 12443681c8d7SLuiz Otavio O Souza return (EINVAL); 12453681c8d7SLuiz Otavio O Souza 12463681c8d7SLuiz Otavio O Souza TI_GPIO_LOCK(sc); 12473681c8d7SLuiz Otavio O Souza /* 12483681c8d7SLuiz Otavio O Souza * TRM recommends add the new event before remove the old one to 12493681c8d7SLuiz Otavio O Souza * avoid losing interrupts. 12503681c8d7SLuiz Otavio O Souza */ 12513681c8d7SLuiz Otavio O Souza oldreg = ti_gpio_intr_reg(sc, irq); 12523681c8d7SLuiz Otavio O Souza sc->sc_irq_trigger[irq] = trig; 12533681c8d7SLuiz Otavio O Souza sc->sc_irq_polarity[irq] = pol; 12543681c8d7SLuiz Otavio O Souza reg = ti_gpio_intr_reg(sc, irq); 12553681c8d7SLuiz Otavio O Souza if (reg != 0) { 12563681c8d7SLuiz Otavio O Souza /* Apply the new settings. */ 12575b03aba6SOleksandr Tymoshenko val = ti_gpio_read_4(sc, reg); 12583681c8d7SLuiz Otavio O Souza val |= TI_GPIO_MASK(irq); 12595b03aba6SOleksandr Tymoshenko ti_gpio_write_4(sc, reg, val); 12603681c8d7SLuiz Otavio O Souza } 12617d732ceaSLuiz Otavio O Souza if (reg != oldreg && oldreg != 0) { 12623681c8d7SLuiz Otavio O Souza /* Remove the old settings. */ 12635b03aba6SOleksandr Tymoshenko val = ti_gpio_read_4(sc, oldreg); 12643681c8d7SLuiz Otavio O Souza val &= ~TI_GPIO_MASK(irq); 12655b03aba6SOleksandr Tymoshenko ti_gpio_write_4(sc, oldreg, val); 12663681c8d7SLuiz Otavio O Souza } 12673681c8d7SLuiz Otavio O Souza TI_GPIO_UNLOCK(sc); 12683681c8d7SLuiz Otavio O Souza 12693681c8d7SLuiz Otavio O Souza return (0); 12703681c8d7SLuiz Otavio O Souza } 12713681c8d7SLuiz Otavio O Souza 12723681c8d7SLuiz Otavio O Souza static int 12733681c8d7SLuiz Otavio O Souza ti_gpio_setup_intr(device_t dev, device_t child, struct resource *ires, 12743681c8d7SLuiz Otavio O Souza int flags, driver_filter_t *filt, driver_intr_t *handler, 12753681c8d7SLuiz Otavio O Souza void *arg, void **cookiep) 12763681c8d7SLuiz Otavio O Souza { 12773681c8d7SLuiz Otavio O Souza struct ti_gpio_softc *sc; 12783681c8d7SLuiz Otavio O Souza struct intr_event *event; 12793681c8d7SLuiz Otavio O Souza int pin, error; 12803681c8d7SLuiz Otavio O Souza 12813681c8d7SLuiz Otavio O Souza sc = device_get_softc(dev); 12823681c8d7SLuiz Otavio O Souza pin = rman_get_start(ires); 12833681c8d7SLuiz Otavio O Souza if (ti_gpio_valid_pin(sc, pin) != 0) 12843681c8d7SLuiz Otavio O Souza panic("%s: bad pin %d", __func__, pin); 12853681c8d7SLuiz Otavio O Souza 12863681c8d7SLuiz Otavio O Souza event = sc->sc_events[pin]; 12873681c8d7SLuiz Otavio O Souza if (event == NULL) { 12885b03aba6SOleksandr Tymoshenko sc->sc_mask_args[pin].softc = sc; 12895b03aba6SOleksandr Tymoshenko sc->sc_mask_args[pin].pin = pin; 12905b03aba6SOleksandr Tymoshenko error = intr_event_create(&event, (void *)&sc->sc_mask_args[pin], 0, 12913681c8d7SLuiz Otavio O Souza pin, ti_gpio_mask_irq, ti_gpio_unmask_irq, NULL, NULL, 12923681c8d7SLuiz Otavio O Souza "gpio%d pin%d:", device_get_unit(dev), pin); 12933681c8d7SLuiz Otavio O Souza if (error != 0) 12943681c8d7SLuiz Otavio O Souza return (error); 12953681c8d7SLuiz Otavio O Souza sc->sc_events[pin] = event; 12963681c8d7SLuiz Otavio O Souza } 12973681c8d7SLuiz Otavio O Souza intr_event_add_handler(event, device_get_nameunit(child), filt, 12983681c8d7SLuiz Otavio O Souza handler, arg, intr_priority(flags), flags, cookiep); 12993681c8d7SLuiz Otavio O Souza 13003681c8d7SLuiz Otavio O Souza return (0); 13013681c8d7SLuiz Otavio O Souza } 13023681c8d7SLuiz Otavio O Souza 13033681c8d7SLuiz Otavio O Souza static int 13043681c8d7SLuiz Otavio O Souza ti_gpio_teardown_intr(device_t dev, device_t child, struct resource *ires, 13053681c8d7SLuiz Otavio O Souza void *cookie) 13063681c8d7SLuiz Otavio O Souza { 13073681c8d7SLuiz Otavio O Souza struct ti_gpio_softc *sc; 13083681c8d7SLuiz Otavio O Souza int pin, err; 13093681c8d7SLuiz Otavio O Souza 13103681c8d7SLuiz Otavio O Souza sc = device_get_softc(dev); 13113681c8d7SLuiz Otavio O Souza pin = rman_get_start(ires); 13123681c8d7SLuiz Otavio O Souza if (ti_gpio_valid_pin(sc, pin) != 0) 13133681c8d7SLuiz Otavio O Souza panic("%s: bad pin %d", __func__, pin); 13143681c8d7SLuiz Otavio O Souza if (sc->sc_events[pin] == NULL) 13153681c8d7SLuiz Otavio O Souza panic("Trying to teardown unoccupied IRQ"); 13163681c8d7SLuiz Otavio O Souza err = intr_event_remove_handler(cookie); 13173681c8d7SLuiz Otavio O Souza if (!err) 13183681c8d7SLuiz Otavio O Souza sc->sc_events[pin] = NULL; 13193681c8d7SLuiz Otavio O Souza 13203681c8d7SLuiz Otavio O Souza return (err); 13213681c8d7SLuiz Otavio O Souza } 13222df5562dSSvatopluk Kraus #endif 13233681c8d7SLuiz Otavio O Souza 13248c705c2cSLuiz Otavio O Souza static phandle_t 13258c705c2cSLuiz Otavio O Souza ti_gpio_get_node(device_t bus, device_t dev) 13268c705c2cSLuiz Otavio O Souza { 13278c705c2cSLuiz Otavio O Souza 13288c705c2cSLuiz Otavio O Souza /* We only have one child, the GPIO bus, which needs our own node. */ 13298c705c2cSLuiz Otavio O Souza return (ofw_bus_get_node(bus)); 13308c705c2cSLuiz Otavio O Souza } 13318c705c2cSLuiz Otavio O Souza 1332e53470feSOleksandr Tymoshenko static device_method_t ti_gpio_methods[] = { 1333e53470feSOleksandr Tymoshenko DEVMETHOD(device_attach, ti_gpio_attach), 1334e53470feSOleksandr Tymoshenko DEVMETHOD(device_detach, ti_gpio_detach), 1335e53470feSOleksandr Tymoshenko 1336e53470feSOleksandr Tymoshenko /* GPIO protocol */ 13377836352bSLuiz Otavio O Souza DEVMETHOD(gpio_get_bus, ti_gpio_get_bus), 1338e53470feSOleksandr Tymoshenko DEVMETHOD(gpio_pin_max, ti_gpio_pin_max), 1339e53470feSOleksandr Tymoshenko DEVMETHOD(gpio_pin_getname, ti_gpio_pin_getname), 1340e53470feSOleksandr Tymoshenko DEVMETHOD(gpio_pin_getflags, ti_gpio_pin_getflags), 1341e53470feSOleksandr Tymoshenko DEVMETHOD(gpio_pin_getcaps, ti_gpio_pin_getcaps), 1342e53470feSOleksandr Tymoshenko DEVMETHOD(gpio_pin_setflags, ti_gpio_pin_setflags), 1343e53470feSOleksandr Tymoshenko DEVMETHOD(gpio_pin_get, ti_gpio_pin_get), 1344e53470feSOleksandr Tymoshenko DEVMETHOD(gpio_pin_set, ti_gpio_pin_set), 1345e53470feSOleksandr Tymoshenko DEVMETHOD(gpio_pin_toggle, ti_gpio_pin_toggle), 13468c705c2cSLuiz Otavio O Souza 134759c3cb81SAndrew Turner #ifdef INTRNG 13482df5562dSSvatopluk Kraus /* Interrupt controller interface */ 13492df5562dSSvatopluk Kraus DEVMETHOD(pic_disable_intr, ti_gpio_pic_disable_intr), 13502df5562dSSvatopluk Kraus DEVMETHOD(pic_enable_intr, ti_gpio_pic_enable_intr), 13512df5562dSSvatopluk Kraus DEVMETHOD(pic_map_intr, ti_gpio_pic_map_intr), 13522df5562dSSvatopluk Kraus DEVMETHOD(pic_setup_intr, ti_gpio_pic_setup_intr), 13532df5562dSSvatopluk Kraus DEVMETHOD(pic_teardown_intr, ti_gpio_pic_teardown_intr), 13542df5562dSSvatopluk Kraus DEVMETHOD(pic_post_filter, ti_gpio_pic_post_filter), 13552df5562dSSvatopluk Kraus DEVMETHOD(pic_post_ithread, ti_gpio_pic_post_ithread), 13562df5562dSSvatopluk Kraus DEVMETHOD(pic_pre_ithread, ti_gpio_pic_pre_ithread), 13572df5562dSSvatopluk Kraus #else 13583681c8d7SLuiz Otavio O Souza /* Bus interface */ 13593681c8d7SLuiz Otavio O Souza DEVMETHOD(bus_activate_resource, ti_gpio_activate_resource), 13603681c8d7SLuiz Otavio O Souza DEVMETHOD(bus_deactivate_resource, ti_gpio_deactivate_resource), 13613681c8d7SLuiz Otavio O Souza DEVMETHOD(bus_config_intr, ti_gpio_config_intr), 13623681c8d7SLuiz Otavio O Souza DEVMETHOD(bus_setup_intr, ti_gpio_setup_intr), 13633681c8d7SLuiz Otavio O Souza DEVMETHOD(bus_teardown_intr, ti_gpio_teardown_intr), 13642df5562dSSvatopluk Kraus #endif 13653681c8d7SLuiz Otavio O Souza 13668c705c2cSLuiz Otavio O Souza /* ofw_bus interface */ 13678c705c2cSLuiz Otavio O Souza DEVMETHOD(ofw_bus_get_node, ti_gpio_get_node), 13688c705c2cSLuiz Otavio O Souza 1369e53470feSOleksandr Tymoshenko {0, 0}, 1370e53470feSOleksandr Tymoshenko }; 1371e53470feSOleksandr Tymoshenko 1372b6c7dacfSAndrew Turner driver_t ti_gpio_driver = { 1373e53470feSOleksandr Tymoshenko "gpio", 1374e53470feSOleksandr Tymoshenko ti_gpio_methods, 1375e53470feSOleksandr Tymoshenko sizeof(struct ti_gpio_softc), 1376e53470feSOleksandr Tymoshenko }; 1377