1e53470feSOleksandr Tymoshenko /*- 2e53470feSOleksandr Tymoshenko * Copyright (c) 2011 3e53470feSOleksandr Tymoshenko * Ben Gray <ben.r.gray@gmail.com>. 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 /** 29e53470feSOleksandr Tymoshenko * Very simple GPIO (general purpose IO) driver module for TI OMAP SoC's. 30e53470feSOleksandr Tymoshenko * 31e53470feSOleksandr Tymoshenko * Currently this driver only does the basics, get a value on a pin & set a 32e53470feSOleksandr Tymoshenko * value on a pin. Hopefully over time I'll expand this to be a bit more generic 33e53470feSOleksandr Tymoshenko * and support interrupts and other various bits on the SoC can do ... in the 34e53470feSOleksandr Tymoshenko * meantime this is all you get. 35e53470feSOleksandr Tymoshenko * 36e53470feSOleksandr Tymoshenko * Beware the OMA datasheet(s) lists GPIO banks 1-6, whereas I've used 0-5 here 37e53470feSOleksandr Tymoshenko * in the code. 38e53470feSOleksandr Tymoshenko * 39e53470feSOleksandr Tymoshenko * 40e53470feSOleksandr Tymoshenko */ 41e53470feSOleksandr Tymoshenko 42e53470feSOleksandr Tymoshenko #include <sys/cdefs.h> 43e53470feSOleksandr Tymoshenko __FBSDID("$FreeBSD$"); 44e53470feSOleksandr Tymoshenko 45e53470feSOleksandr Tymoshenko #include <sys/param.h> 46e53470feSOleksandr Tymoshenko #include <sys/systm.h> 47e53470feSOleksandr Tymoshenko #include <sys/bus.h> 48e53470feSOleksandr Tymoshenko 49e53470feSOleksandr Tymoshenko #include <sys/kernel.h> 50e53470feSOleksandr Tymoshenko #include <sys/module.h> 51e53470feSOleksandr Tymoshenko #include <sys/rman.h> 52e53470feSOleksandr Tymoshenko #include <sys/lock.h> 53e53470feSOleksandr Tymoshenko #include <sys/mutex.h> 54e53470feSOleksandr Tymoshenko #include <sys/gpio.h> 55e53470feSOleksandr Tymoshenko 56e53470feSOleksandr Tymoshenko #include <machine/bus.h> 57e53470feSOleksandr Tymoshenko #include <machine/resource.h> 58e53470feSOleksandr Tymoshenko 594eb12144SAndrew Turner #include <arm/ti/ti_cpuid.h> 60b6c7dacfSAndrew Turner #include <arm/ti/ti_gpio.h> 61e53470feSOleksandr Tymoshenko #include <arm/ti/ti_scm.h> 62e53470feSOleksandr Tymoshenko #include <arm/ti/ti_prcm.h> 63e53470feSOleksandr Tymoshenko 64e53470feSOleksandr Tymoshenko #include <dev/fdt/fdt_common.h> 65e53470feSOleksandr Tymoshenko #include <dev/ofw/openfirm.h> 66e53470feSOleksandr Tymoshenko #include <dev/ofw/ofw_bus.h> 67e53470feSOleksandr Tymoshenko #include <dev/ofw/ofw_bus_subr.h> 68e53470feSOleksandr Tymoshenko 69e53470feSOleksandr Tymoshenko #include "gpio_if.h" 70b6c7dacfSAndrew Turner #include "ti_gpio_if.h" 71e53470feSOleksandr Tymoshenko 72e53470feSOleksandr Tymoshenko /* Register definitions */ 73e53470feSOleksandr Tymoshenko #define TI_GPIO_REVISION 0x0000 74e53470feSOleksandr Tymoshenko #define TI_GPIO_SYSCONFIG 0x0010 7556d8b96cSAndrew Turner #if defined(SOC_OMAP4) || defined(SOC_TI_AM335X) 76e53470feSOleksandr Tymoshenko #define TI_GPIO_IRQSTATUS_RAW_0 0x0024 77e53470feSOleksandr Tymoshenko #define TI_GPIO_IRQSTATUS_RAW_1 0x0028 78e53470feSOleksandr Tymoshenko #define TI_GPIO_IRQSTATUS_0 0x002C 79e53470feSOleksandr Tymoshenko #define TI_GPIO_IRQSTATUS_1 0x0030 80e53470feSOleksandr Tymoshenko #define TI_GPIO_IRQSTATUS_SET_0 0x0034 81e53470feSOleksandr Tymoshenko #define TI_GPIO_IRQSTATUS_SET_1 0x0038 82e53470feSOleksandr Tymoshenko #define TI_GPIO_IRQSTATUS_CLR_0 0x003C 83e53470feSOleksandr Tymoshenko #define TI_GPIO_IRQSTATUS_CLR_1 0x0040 84e53470feSOleksandr Tymoshenko #define TI_GPIO_IRQWAKEN_0 0x0044 85e53470feSOleksandr Tymoshenko #define TI_GPIO_IRQWAKEN_1 0x0048 86e53470feSOleksandr Tymoshenko #define TI_GPIO_SYSSTATUS 0x0114 87e53470feSOleksandr Tymoshenko #define TI_GPIO_IRQSTATUS1 0x0118 88e53470feSOleksandr Tymoshenko #define TI_GPIO_IRQENABLE1 0x011C 89e53470feSOleksandr Tymoshenko #define TI_GPIO_WAKEUPENABLE 0x0120 90e53470feSOleksandr Tymoshenko #define TI_GPIO_IRQSTATUS2 0x0128 91e53470feSOleksandr Tymoshenko #define TI_GPIO_IRQENABLE2 0x012C 92e53470feSOleksandr Tymoshenko #define TI_GPIO_CTRL 0x0130 93e53470feSOleksandr Tymoshenko #define TI_GPIO_OE 0x0134 94e53470feSOleksandr Tymoshenko #define TI_GPIO_DATAIN 0x0138 95e53470feSOleksandr Tymoshenko #define TI_GPIO_DATAOUT 0x013C 96e53470feSOleksandr Tymoshenko #define TI_GPIO_LEVELDETECT0 0x0140 97e53470feSOleksandr Tymoshenko #define TI_GPIO_LEVELDETECT1 0x0144 98e53470feSOleksandr Tymoshenko #define TI_GPIO_RISINGDETECT 0x0148 99e53470feSOleksandr Tymoshenko #define TI_GPIO_FALLINGDETECT 0x014C 100e53470feSOleksandr Tymoshenko #define TI_GPIO_DEBOUNCENABLE 0x0150 101e53470feSOleksandr Tymoshenko #define TI_GPIO_DEBOUNCINGTIME 0x0154 102e53470feSOleksandr Tymoshenko #define TI_GPIO_CLEARWKUPENA 0x0180 103e53470feSOleksandr Tymoshenko #define TI_GPIO_SETWKUENA 0x0184 104e53470feSOleksandr Tymoshenko #define TI_GPIO_CLEARDATAOUT 0x0190 105e53470feSOleksandr Tymoshenko #define TI_GPIO_SETDATAOUT 0x0194 106e53470feSOleksandr Tymoshenko #else 107e53470feSOleksandr Tymoshenko #error "Unknown SoC" 108e53470feSOleksandr Tymoshenko #endif 109e53470feSOleksandr Tymoshenko 110e53470feSOleksandr Tymoshenko /* Other SoC Specific definitions */ 1114eb12144SAndrew Turner #define OMAP4_MAX_GPIO_BANKS 6 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_MAX_GPIO_BANKS 4 1164eb12144SAndrew Turner #define AM335X_FIRST_GPIO_BANK 0 1174eb12144SAndrew Turner #define AM335X_INTR_PER_BANK 2 1184eb12144SAndrew Turner #define AM335X_GPIO_REV 0x50600801 119ff5823beSLuiz Otavio O Souza #define PINS_PER_BANK 32 1204eb12144SAndrew Turner 1214eb12144SAndrew Turner static u_int 1224eb12144SAndrew Turner ti_max_gpio_banks(void) 1234eb12144SAndrew Turner { 1244eb12144SAndrew Turner switch(ti_chip()) { 1254eb12144SAndrew Turner #ifdef SOC_OMAP4 1264eb12144SAndrew Turner case CHIP_OMAP_4: 1274eb12144SAndrew Turner return (OMAP4_MAX_GPIO_BANKS); 1284eb12144SAndrew Turner #endif 1294eb12144SAndrew Turner #ifdef SOC_TI_AM335X 1304eb12144SAndrew Turner case CHIP_AM335X: 1314eb12144SAndrew Turner return (AM335X_MAX_GPIO_BANKS); 1324eb12144SAndrew Turner #endif 1334eb12144SAndrew Turner } 1344eb12144SAndrew Turner return (0); 1354eb12144SAndrew Turner } 1364eb12144SAndrew Turner 1374eb12144SAndrew Turner static u_int 1384eb12144SAndrew Turner ti_max_gpio_intrs(void) 1394eb12144SAndrew Turner { 1404eb12144SAndrew Turner switch(ti_chip()) { 1414eb12144SAndrew Turner #ifdef SOC_OMAP4 1424eb12144SAndrew Turner case CHIP_OMAP_4: 1434eb12144SAndrew Turner return (OMAP4_MAX_GPIO_BANKS * OMAP4_INTR_PER_BANK); 1444eb12144SAndrew Turner #endif 1454eb12144SAndrew Turner #ifdef SOC_TI_AM335X 1464eb12144SAndrew Turner case CHIP_AM335X: 1474eb12144SAndrew Turner return (AM335X_MAX_GPIO_BANKS * AM335X_INTR_PER_BANK); 1484eb12144SAndrew Turner #endif 1494eb12144SAndrew Turner } 1504eb12144SAndrew Turner return (0); 1514eb12144SAndrew Turner } 1524eb12144SAndrew Turner 1534eb12144SAndrew Turner static u_int 1544eb12144SAndrew Turner ti_first_gpio_bank(void) 1554eb12144SAndrew Turner { 1564eb12144SAndrew Turner switch(ti_chip()) { 1574eb12144SAndrew Turner #ifdef SOC_OMAP4 1584eb12144SAndrew Turner case CHIP_OMAP_4: 1594eb12144SAndrew Turner return (OMAP4_FIRST_GPIO_BANK); 1604eb12144SAndrew Turner #endif 1614eb12144SAndrew Turner #ifdef SOC_TI_AM335X 1624eb12144SAndrew Turner case CHIP_AM335X: 1634eb12144SAndrew Turner return (AM335X_FIRST_GPIO_BANK); 1644eb12144SAndrew Turner #endif 1654eb12144SAndrew Turner } 1664eb12144SAndrew Turner return (0); 1674eb12144SAndrew Turner } 1684eb12144SAndrew Turner 1694eb12144SAndrew Turner static uint32_t 1704eb12144SAndrew Turner ti_gpio_rev(void) 1714eb12144SAndrew Turner { 1724eb12144SAndrew Turner switch(ti_chip()) { 1734eb12144SAndrew Turner #ifdef SOC_OMAP4 1744eb12144SAndrew Turner case CHIP_OMAP_4: 1754eb12144SAndrew Turner return (OMAP4_GPIO_REV); 1764eb12144SAndrew Turner #endif 1774eb12144SAndrew Turner #ifdef SOC_TI_AM335X 1784eb12144SAndrew Turner case CHIP_AM335X: 1794eb12144SAndrew Turner return (AM335X_GPIO_REV); 1804eb12144SAndrew Turner #endif 1814eb12144SAndrew Turner } 1824eb12144SAndrew Turner return (0); 1834eb12144SAndrew Turner } 184e53470feSOleksandr Tymoshenko 185e53470feSOleksandr Tymoshenko /** 186e53470feSOleksandr Tymoshenko * ti_gpio_mem_spec - Resource specification used when allocating resources 187e53470feSOleksandr Tymoshenko * ti_gpio_irq_spec - Resource specification used when allocating resources 188e53470feSOleksandr Tymoshenko * 189e53470feSOleksandr Tymoshenko * This driver module can have up to six independent memory regions, each 190e53470feSOleksandr Tymoshenko * region typically controls 32 GPIO pins. 191db8a14ecSLuiz Otavio O Souza * 192db8a14ecSLuiz Otavio O Souza * On OMAP3 and OMAP4 there is only one physical interrupt line per bank, 193db8a14ecSLuiz Otavio O Souza * but there are two set of registers which control the interrupt delivery 194db8a14ecSLuiz Otavio O Souza * to internal subsystems. The first set of registers control the 195db8a14ecSLuiz Otavio O Souza * interrupts delivery to the MPU and the second set control the 196db8a14ecSLuiz Otavio O Souza * interrupts delivery to the DSP. 197db8a14ecSLuiz Otavio O Souza * 198db8a14ecSLuiz Otavio O Souza * On AM335x there are two physical interrupt lines for each GPIO module. 199db8a14ecSLuiz Otavio O Souza * Each interrupt line is controlled by a set of registers. 200e53470feSOleksandr Tymoshenko */ 201e53470feSOleksandr Tymoshenko static struct resource_spec ti_gpio_mem_spec[] = { 202e53470feSOleksandr Tymoshenko { SYS_RES_MEMORY, 0, RF_ACTIVE }, 203e53470feSOleksandr Tymoshenko { SYS_RES_MEMORY, 1, RF_ACTIVE | RF_OPTIONAL }, 204e53470feSOleksandr Tymoshenko { SYS_RES_MEMORY, 2, RF_ACTIVE | RF_OPTIONAL }, 205e53470feSOleksandr Tymoshenko { SYS_RES_MEMORY, 3, RF_ACTIVE | RF_OPTIONAL }, 206e53470feSOleksandr Tymoshenko #if !defined(SOC_TI_AM335X) 207e53470feSOleksandr Tymoshenko { SYS_RES_MEMORY, 4, RF_ACTIVE | RF_OPTIONAL }, 208e53470feSOleksandr Tymoshenko { SYS_RES_MEMORY, 5, RF_ACTIVE | RF_OPTIONAL }, 209e53470feSOleksandr Tymoshenko #endif 210e53470feSOleksandr Tymoshenko { -1, 0, 0 } 211e53470feSOleksandr Tymoshenko }; 212e53470feSOleksandr Tymoshenko static struct resource_spec ti_gpio_irq_spec[] = { 213e53470feSOleksandr Tymoshenko { SYS_RES_IRQ, 0, RF_ACTIVE }, 214e53470feSOleksandr Tymoshenko { SYS_RES_IRQ, 1, RF_ACTIVE | RF_OPTIONAL }, 215e53470feSOleksandr Tymoshenko { SYS_RES_IRQ, 2, RF_ACTIVE | RF_OPTIONAL }, 216e53470feSOleksandr Tymoshenko { SYS_RES_IRQ, 3, RF_ACTIVE | RF_OPTIONAL }, 217e53470feSOleksandr Tymoshenko { SYS_RES_IRQ, 4, RF_ACTIVE | RF_OPTIONAL }, 218e53470feSOleksandr Tymoshenko { SYS_RES_IRQ, 5, RF_ACTIVE | RF_OPTIONAL }, 219db8a14ecSLuiz Otavio O Souza #if defined(SOC_TI_AM335X) 220db8a14ecSLuiz Otavio O Souza { SYS_RES_IRQ, 6, RF_ACTIVE | RF_OPTIONAL }, 221db8a14ecSLuiz Otavio O Souza { SYS_RES_IRQ, 7, RF_ACTIVE | RF_OPTIONAL }, 222e53470feSOleksandr Tymoshenko #endif 223e53470feSOleksandr Tymoshenko { -1, 0, 0 } 224e53470feSOleksandr Tymoshenko }; 225e53470feSOleksandr Tymoshenko 226e53470feSOleksandr Tymoshenko /** 227e53470feSOleksandr Tymoshenko * Macros for driver mutex locking 228e53470feSOleksandr Tymoshenko */ 229e53470feSOleksandr Tymoshenko #define TI_GPIO_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) 230e53470feSOleksandr Tymoshenko #define TI_GPIO_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) 231e53470feSOleksandr Tymoshenko #define TI_GPIO_LOCK_INIT(_sc) \ 232e53470feSOleksandr Tymoshenko mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), \ 233e53470feSOleksandr Tymoshenko "ti_gpio", MTX_DEF) 234ff5823beSLuiz Otavio O Souza #define TI_GPIO_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx) 235ff5823beSLuiz Otavio O Souza #define TI_GPIO_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED) 236ff5823beSLuiz Otavio O Souza #define TI_GPIO_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED) 237e53470feSOleksandr Tymoshenko 238e53470feSOleksandr Tymoshenko /** 239e53470feSOleksandr Tymoshenko * ti_gpio_read_4 - reads a 16-bit value from one of the PADCONFS registers 240e53470feSOleksandr Tymoshenko * @sc: GPIO device context 241e53470feSOleksandr Tymoshenko * @bank: The bank to read from 242e53470feSOleksandr Tymoshenko * @off: The offset of a register from the GPIO register address range 243e53470feSOleksandr Tymoshenko * 244e53470feSOleksandr Tymoshenko * 245e53470feSOleksandr Tymoshenko * RETURNS: 246e53470feSOleksandr Tymoshenko * 32-bit value read from the register. 247e53470feSOleksandr Tymoshenko */ 248e53470feSOleksandr Tymoshenko static inline uint32_t 249e53470feSOleksandr Tymoshenko ti_gpio_read_4(struct ti_gpio_softc *sc, unsigned int bank, bus_size_t off) 250e53470feSOleksandr Tymoshenko { 251e53470feSOleksandr Tymoshenko return (bus_read_4(sc->sc_mem_res[bank], off)); 252e53470feSOleksandr Tymoshenko } 253e53470feSOleksandr Tymoshenko 254e53470feSOleksandr Tymoshenko /** 255e53470feSOleksandr Tymoshenko * ti_gpio_write_4 - writes a 32-bit value to one of the PADCONFS registers 256e53470feSOleksandr Tymoshenko * @sc: GPIO device context 257e53470feSOleksandr Tymoshenko * @bank: The bank to write to 258e53470feSOleksandr Tymoshenko * @off: The offset of a register from the GPIO register address range 259e53470feSOleksandr Tymoshenko * @val: The value to write into the register 260e53470feSOleksandr Tymoshenko * 261e53470feSOleksandr Tymoshenko * RETURNS: 262e53470feSOleksandr Tymoshenko * nothing 263e53470feSOleksandr Tymoshenko */ 264e53470feSOleksandr Tymoshenko static inline void 265e53470feSOleksandr Tymoshenko ti_gpio_write_4(struct ti_gpio_softc *sc, unsigned int bank, bus_size_t off, 266e53470feSOleksandr Tymoshenko uint32_t val) 267e53470feSOleksandr Tymoshenko { 268e53470feSOleksandr Tymoshenko bus_write_4(sc->sc_mem_res[bank], off, val); 269e53470feSOleksandr Tymoshenko } 270e53470feSOleksandr Tymoshenko 271db8a14ecSLuiz Otavio O Souza static inline void 272db8a14ecSLuiz Otavio O Souza ti_gpio_intr_clr(struct ti_gpio_softc *sc, unsigned int bank, uint32_t mask) 273db8a14ecSLuiz Otavio O Souza { 274db8a14ecSLuiz Otavio O Souza 275db8a14ecSLuiz Otavio O Souza /* We clear both set of registers. */ 276db8a14ecSLuiz Otavio O Souza #if defined(SOC_OMAP4) || defined(SOC_TI_AM335X) 277db8a14ecSLuiz Otavio O Souza ti_gpio_write_4(sc, bank, TI_GPIO_IRQSTATUS_CLR_0, mask); 278db8a14ecSLuiz Otavio O Souza ti_gpio_write_4(sc, bank, TI_GPIO_IRQSTATUS_CLR_1, mask); 279db8a14ecSLuiz Otavio O Souza #else 280db8a14ecSLuiz Otavio O Souza ti_gpio_write_4(sc, bank, TI_GPIO_CLEARIRQENABLE1, mask); 281db8a14ecSLuiz Otavio O Souza ti_gpio_write_4(sc, bank, TI_GPIO_CLEARIRQENABLE2, mask); 282db8a14ecSLuiz Otavio O Souza #endif 283db8a14ecSLuiz Otavio O Souza } 284db8a14ecSLuiz Otavio O Souza 285e53470feSOleksandr Tymoshenko /** 286e53470feSOleksandr Tymoshenko * ti_gpio_pin_max - Returns the maximum number of GPIO pins 287e53470feSOleksandr Tymoshenko * @dev: gpio device handle 288e53470feSOleksandr Tymoshenko * @maxpin: pointer to a value that upon return will contain the maximum number 289e53470feSOleksandr Tymoshenko * of pins in the device. 290e53470feSOleksandr Tymoshenko * 291e53470feSOleksandr Tymoshenko * 292e53470feSOleksandr Tymoshenko * LOCKING: 293*f9de33d4SLuiz Otavio O Souza * No locking required, returns static data. 294e53470feSOleksandr Tymoshenko * 295e53470feSOleksandr Tymoshenko * RETURNS: 296e53470feSOleksandr Tymoshenko * Returns 0 on success otherwise an error code 297e53470feSOleksandr Tymoshenko */ 298e53470feSOleksandr Tymoshenko static int 299e53470feSOleksandr Tymoshenko ti_gpio_pin_max(device_t dev, int *maxpin) 300e53470feSOleksandr Tymoshenko { 301e53470feSOleksandr Tymoshenko struct ti_gpio_softc *sc = device_get_softc(dev); 302e53470feSOleksandr Tymoshenko unsigned int i; 303e53470feSOleksandr Tymoshenko unsigned int banks = 0; 304e53470feSOleksandr Tymoshenko 305e53470feSOleksandr Tymoshenko /* Calculate how many valid banks we have and then multiply that by 32 to 306e53470feSOleksandr Tymoshenko * give use the total number of pins. 307e53470feSOleksandr Tymoshenko */ 3084eb12144SAndrew Turner for (i = 0; i < ti_max_gpio_banks(); i++) { 309e53470feSOleksandr Tymoshenko if (sc->sc_mem_res[i] != NULL) 310e53470feSOleksandr Tymoshenko banks++; 311e53470feSOleksandr Tymoshenko } 312e53470feSOleksandr Tymoshenko 31397b405f1SOleksandr Tymoshenko *maxpin = (banks * PINS_PER_BANK) - 1; 314e53470feSOleksandr Tymoshenko 315e53470feSOleksandr Tymoshenko return (0); 316e53470feSOleksandr Tymoshenko } 317e53470feSOleksandr Tymoshenko 318e53470feSOleksandr Tymoshenko /** 319e53470feSOleksandr Tymoshenko * ti_gpio_pin_getcaps - Gets the capabilties of a given pin 320e53470feSOleksandr Tymoshenko * @dev: gpio device handle 321e53470feSOleksandr Tymoshenko * @pin: the number of the pin 322e53470feSOleksandr Tymoshenko * @caps: pointer to a value that upon return will contain the capabilities 323e53470feSOleksandr Tymoshenko * 324e53470feSOleksandr Tymoshenko * Currently all pins have the same capability, notably: 325e53470feSOleksandr Tymoshenko * - GPIO_PIN_INPUT 326e53470feSOleksandr Tymoshenko * - GPIO_PIN_OUTPUT 327e53470feSOleksandr Tymoshenko * - GPIO_PIN_PULLUP 328e53470feSOleksandr Tymoshenko * - GPIO_PIN_PULLDOWN 329e53470feSOleksandr Tymoshenko * 330e53470feSOleksandr Tymoshenko * LOCKING: 331*f9de33d4SLuiz Otavio O Souza * No locking required, returns static data. 332e53470feSOleksandr Tymoshenko * 333e53470feSOleksandr Tymoshenko * RETURNS: 334e53470feSOleksandr Tymoshenko * Returns 0 on success otherwise an error code 335e53470feSOleksandr Tymoshenko */ 336e53470feSOleksandr Tymoshenko static int 337e53470feSOleksandr Tymoshenko ti_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) 338e53470feSOleksandr Tymoshenko { 339e53470feSOleksandr Tymoshenko struct ti_gpio_softc *sc = device_get_softc(dev); 340e53470feSOleksandr Tymoshenko uint32_t bank = (pin / PINS_PER_BANK); 341e53470feSOleksandr Tymoshenko 342e53470feSOleksandr Tymoshenko /* Sanity check the pin number is valid */ 343*f9de33d4SLuiz Otavio O Souza if ((bank >= ti_max_gpio_banks()) || (sc->sc_mem_res[bank] == NULL)) 344e53470feSOleksandr Tymoshenko return (EINVAL); 345e53470feSOleksandr Tymoshenko 346e53470feSOleksandr Tymoshenko *caps = (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_PULLUP | 347e53470feSOleksandr Tymoshenko GPIO_PIN_PULLDOWN); 348e53470feSOleksandr Tymoshenko 349e53470feSOleksandr Tymoshenko return (0); 350e53470feSOleksandr Tymoshenko } 351e53470feSOleksandr Tymoshenko 352e53470feSOleksandr Tymoshenko /** 353e53470feSOleksandr Tymoshenko * ti_gpio_pin_getflags - Gets the current flags of a given pin 354e53470feSOleksandr Tymoshenko * @dev: gpio device handle 355e53470feSOleksandr Tymoshenko * @pin: the number of the pin 356e53470feSOleksandr Tymoshenko * @flags: upon return will contain the current flags of the pin 357e53470feSOleksandr Tymoshenko * 358e53470feSOleksandr Tymoshenko * Reads the current flags of a given pin, here we actually read the H/W 359e53470feSOleksandr Tymoshenko * registers to determine the flags, rather than storing the value in the 360e53470feSOleksandr Tymoshenko * setflags call. 361e53470feSOleksandr Tymoshenko * 362e53470feSOleksandr Tymoshenko * LOCKING: 363e53470feSOleksandr Tymoshenko * Internally locks the context 364e53470feSOleksandr Tymoshenko * 365e53470feSOleksandr Tymoshenko * RETURNS: 366e53470feSOleksandr Tymoshenko * Returns 0 on success otherwise an error code 367e53470feSOleksandr Tymoshenko */ 368e53470feSOleksandr Tymoshenko static int 369e53470feSOleksandr Tymoshenko ti_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) 370e53470feSOleksandr Tymoshenko { 371e53470feSOleksandr Tymoshenko struct ti_gpio_softc *sc = device_get_softc(dev); 372e53470feSOleksandr Tymoshenko uint32_t bank = (pin / PINS_PER_BANK); 373e53470feSOleksandr Tymoshenko 374e53470feSOleksandr Tymoshenko /* Sanity check the pin number is valid */ 375*f9de33d4SLuiz Otavio O Souza if ((bank >= ti_max_gpio_banks()) || (sc->sc_mem_res[bank] == NULL)) 376e53470feSOleksandr Tymoshenko return (EINVAL); 377e53470feSOleksandr Tymoshenko 378e53470feSOleksandr Tymoshenko /* Get the current pin state */ 379*f9de33d4SLuiz Otavio O Souza TI_GPIO_LOCK(sc); 380b6c7dacfSAndrew Turner TI_GPIO_GET_FLAGS(dev, pin, flags); 381e53470feSOleksandr Tymoshenko TI_GPIO_UNLOCK(sc); 382e53470feSOleksandr Tymoshenko 383e53470feSOleksandr Tymoshenko return (0); 384e53470feSOleksandr Tymoshenko } 385e53470feSOleksandr Tymoshenko 386e53470feSOleksandr Tymoshenko /** 387e53470feSOleksandr Tymoshenko * ti_gpio_pin_getname - Gets the name of a given pin 388e53470feSOleksandr Tymoshenko * @dev: gpio device handle 389e53470feSOleksandr Tymoshenko * @pin: the number of the pin 390e53470feSOleksandr Tymoshenko * @name: buffer to put the name in 391e53470feSOleksandr Tymoshenko * 392e53470feSOleksandr Tymoshenko * The driver simply calls the pins gpio_n, where 'n' is obviously the number 393e53470feSOleksandr Tymoshenko * of the pin. 394e53470feSOleksandr Tymoshenko * 395e53470feSOleksandr Tymoshenko * LOCKING: 396*f9de33d4SLuiz Otavio O Souza * No locking required, returns static data. 397e53470feSOleksandr Tymoshenko * 398e53470feSOleksandr Tymoshenko * RETURNS: 399e53470feSOleksandr Tymoshenko * Returns 0 on success otherwise an error code 400e53470feSOleksandr Tymoshenko */ 401e53470feSOleksandr Tymoshenko static int 402e53470feSOleksandr Tymoshenko ti_gpio_pin_getname(device_t dev, uint32_t pin, char *name) 403e53470feSOleksandr Tymoshenko { 404e53470feSOleksandr Tymoshenko struct ti_gpio_softc *sc = device_get_softc(dev); 405e53470feSOleksandr Tymoshenko uint32_t bank = (pin / PINS_PER_BANK); 406e53470feSOleksandr Tymoshenko 407e53470feSOleksandr Tymoshenko /* Sanity check the pin number is valid */ 408*f9de33d4SLuiz Otavio O Souza if ((bank >= ti_max_gpio_banks()) || (sc->sc_mem_res[bank] == NULL)) 409e53470feSOleksandr Tymoshenko return (EINVAL); 410e53470feSOleksandr Tymoshenko 411e53470feSOleksandr Tymoshenko /* Set a very simple name */ 412e53470feSOleksandr Tymoshenko snprintf(name, GPIOMAXNAME, "gpio_%u", pin); 413e53470feSOleksandr Tymoshenko name[GPIOMAXNAME - 1] = '\0'; 414e53470feSOleksandr Tymoshenko 415e53470feSOleksandr Tymoshenko return (0); 416e53470feSOleksandr Tymoshenko } 417e53470feSOleksandr Tymoshenko 418e53470feSOleksandr Tymoshenko /** 419e53470feSOleksandr Tymoshenko * ti_gpio_pin_setflags - Sets the flags for a given pin 420e53470feSOleksandr Tymoshenko * @dev: gpio device handle 421e53470feSOleksandr Tymoshenko * @pin: the number of the pin 422e53470feSOleksandr Tymoshenko * @flags: the flags to set 423e53470feSOleksandr Tymoshenko * 424e53470feSOleksandr Tymoshenko * The flags of the pin correspond to things like input/output mode, pull-ups, 425e53470feSOleksandr Tymoshenko * pull-downs, etc. This driver doesn't support all flags, only the following: 426e53470feSOleksandr Tymoshenko * - GPIO_PIN_INPUT 427e53470feSOleksandr Tymoshenko * - GPIO_PIN_OUTPUT 428e53470feSOleksandr Tymoshenko * - GPIO_PIN_PULLUP 429e53470feSOleksandr Tymoshenko * - GPIO_PIN_PULLDOWN 430e53470feSOleksandr Tymoshenko * 431e53470feSOleksandr Tymoshenko * LOCKING: 432e53470feSOleksandr Tymoshenko * Internally locks the context 433e53470feSOleksandr Tymoshenko * 434e53470feSOleksandr Tymoshenko * RETURNS: 435e53470feSOleksandr Tymoshenko * Returns 0 on success otherwise an error code 436e53470feSOleksandr Tymoshenko */ 437e53470feSOleksandr Tymoshenko static int 438e53470feSOleksandr Tymoshenko ti_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) 439e53470feSOleksandr Tymoshenko { 440e53470feSOleksandr Tymoshenko struct ti_gpio_softc *sc = device_get_softc(dev); 441e53470feSOleksandr Tymoshenko uint32_t bank = (pin / PINS_PER_BANK); 442e53470feSOleksandr Tymoshenko uint32_t mask = (1UL << (pin % PINS_PER_BANK)); 443*f9de33d4SLuiz Otavio O Souza uint32_t oe; 444e53470feSOleksandr Tymoshenko 445e53470feSOleksandr Tymoshenko /* Sanity check the pin number is valid */ 446*f9de33d4SLuiz Otavio O Souza if ((bank >= ti_max_gpio_banks()) || (sc->sc_mem_res[bank] == NULL)) 447e53470feSOleksandr Tymoshenko return (EINVAL); 448e53470feSOleksandr Tymoshenko 449e53470feSOleksandr Tymoshenko /* Set the GPIO mode and state */ 450*f9de33d4SLuiz Otavio O Souza TI_GPIO_LOCK(sc); 451b6c7dacfSAndrew Turner if (TI_GPIO_SET_FLAGS(dev, pin, flags) != 0) { 452e53470feSOleksandr Tymoshenko TI_GPIO_UNLOCK(sc); 453e53470feSOleksandr Tymoshenko return (EINVAL); 454e53470feSOleksandr Tymoshenko } 455e53470feSOleksandr Tymoshenko 456e53470feSOleksandr Tymoshenko /* If configuring as an output set the "output enable" bit */ 457*f9de33d4SLuiz Otavio O Souza oe = ti_gpio_read_4(sc, bank, TI_GPIO_OE); 458e53470feSOleksandr Tymoshenko if (flags & GPIO_PIN_INPUT) 459*f9de33d4SLuiz Otavio O Souza oe |= mask; 460e53470feSOleksandr Tymoshenko else 461*f9de33d4SLuiz Otavio O Souza oe &= ~mask; 462*f9de33d4SLuiz Otavio O Souza ti_gpio_write_4(sc, bank, TI_GPIO_OE, oe); 463e53470feSOleksandr Tymoshenko TI_GPIO_UNLOCK(sc); 464e53470feSOleksandr Tymoshenko 465e53470feSOleksandr Tymoshenko return (0); 466e53470feSOleksandr Tymoshenko } 467e53470feSOleksandr Tymoshenko 468e53470feSOleksandr Tymoshenko /** 469e53470feSOleksandr Tymoshenko * ti_gpio_pin_set - Sets the current level on a GPIO pin 470e53470feSOleksandr Tymoshenko * @dev: gpio device handle 471e53470feSOleksandr Tymoshenko * @pin: the number of the pin 472e53470feSOleksandr Tymoshenko * @value: non-zero value will drive the pin high, otherwise the pin is 473e53470feSOleksandr Tymoshenko * driven low. 474e53470feSOleksandr Tymoshenko * 475e53470feSOleksandr Tymoshenko * 476e53470feSOleksandr Tymoshenko * LOCKING: 477e53470feSOleksandr Tymoshenko * Internally locks the context 478e53470feSOleksandr Tymoshenko * 479e53470feSOleksandr Tymoshenko * RETURNS: 480e53470feSOleksandr Tymoshenko * Returns 0 on success otherwise a error code 481e53470feSOleksandr Tymoshenko */ 482e53470feSOleksandr Tymoshenko static int 483e53470feSOleksandr Tymoshenko ti_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value) 484e53470feSOleksandr Tymoshenko { 485e53470feSOleksandr Tymoshenko struct ti_gpio_softc *sc = device_get_softc(dev); 486e53470feSOleksandr Tymoshenko uint32_t bank = (pin / PINS_PER_BANK); 487e53470feSOleksandr Tymoshenko uint32_t mask = (1UL << (pin % PINS_PER_BANK)); 488*f9de33d4SLuiz Otavio O Souza uint32_t reg; 489e53470feSOleksandr Tymoshenko 490e53470feSOleksandr Tymoshenko /* Sanity check the pin number is valid */ 491*f9de33d4SLuiz Otavio O Souza if ((bank >= ti_max_gpio_banks()) || (sc->sc_mem_res[bank] == NULL)) 492e53470feSOleksandr Tymoshenko return (EINVAL); 493e53470feSOleksandr Tymoshenko 494*f9de33d4SLuiz Otavio O Souza TI_GPIO_LOCK(sc); 495*f9de33d4SLuiz Otavio O Souza if (value == GPIO_PIN_LOW) 496*f9de33d4SLuiz Otavio O Souza reg = TI_GPIO_CLEARDATAOUT; 497*f9de33d4SLuiz Otavio O Souza else 498*f9de33d4SLuiz Otavio O Souza reg = TI_GPIO_SETDATAOUT; 499*f9de33d4SLuiz Otavio O Souza ti_gpio_write_4(sc, bank, reg, mask); 500e53470feSOleksandr Tymoshenko TI_GPIO_UNLOCK(sc); 501e53470feSOleksandr Tymoshenko 502e53470feSOleksandr Tymoshenko return (0); 503e53470feSOleksandr Tymoshenko } 504e53470feSOleksandr Tymoshenko 505e53470feSOleksandr Tymoshenko /** 506e53470feSOleksandr Tymoshenko * ti_gpio_pin_get - Gets the current level on a GPIO pin 507e53470feSOleksandr Tymoshenko * @dev: gpio device handle 508e53470feSOleksandr Tymoshenko * @pin: the number of the pin 509e53470feSOleksandr Tymoshenko * @value: pointer to a value that upond return will contain the pin value 510e53470feSOleksandr Tymoshenko * 511e53470feSOleksandr Tymoshenko * The pin must be configured as an input pin beforehand, otherwise this 512e53470feSOleksandr Tymoshenko * function will fail. 513e53470feSOleksandr Tymoshenko * 514e53470feSOleksandr Tymoshenko * LOCKING: 515e53470feSOleksandr Tymoshenko * Internally locks the context 516e53470feSOleksandr Tymoshenko * 517e53470feSOleksandr Tymoshenko * RETURNS: 518e53470feSOleksandr Tymoshenko * Returns 0 on success otherwise a error code 519e53470feSOleksandr Tymoshenko */ 520e53470feSOleksandr Tymoshenko static int 521e53470feSOleksandr Tymoshenko ti_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *value) 522e53470feSOleksandr Tymoshenko { 523e53470feSOleksandr Tymoshenko struct ti_gpio_softc *sc = device_get_softc(dev); 524e53470feSOleksandr Tymoshenko uint32_t bank = (pin / PINS_PER_BANK); 525e53470feSOleksandr Tymoshenko uint32_t mask = (1UL << (pin % PINS_PER_BANK)); 526*f9de33d4SLuiz Otavio O Souza uint32_t oe, reg; 527e53470feSOleksandr Tymoshenko 528e53470feSOleksandr Tymoshenko /* Sanity check the pin number is valid */ 529*f9de33d4SLuiz Otavio O Souza if ((bank >= ti_max_gpio_banks()) || (sc->sc_mem_res[bank] == NULL)) 530e53470feSOleksandr Tymoshenko return (EINVAL); 531e53470feSOleksandr Tymoshenko 532*f9de33d4SLuiz Otavio O Souza /* 533*f9de33d4SLuiz Otavio O Souza * Return data from output latch when set as output and from the 534*f9de33d4SLuiz Otavio O Souza * input register otherwise. 535*f9de33d4SLuiz Otavio O Souza */ 536*f9de33d4SLuiz Otavio O Souza TI_GPIO_LOCK(sc); 537*f9de33d4SLuiz Otavio O Souza oe = ti_gpio_read_4(sc, bank, TI_GPIO_OE); 538*f9de33d4SLuiz Otavio O Souza if (oe & mask) 539*f9de33d4SLuiz Otavio O Souza reg = TI_GPIO_DATAIN; 5409f165184SLuiz Otavio O Souza else 541*f9de33d4SLuiz Otavio O Souza reg = TI_GPIO_DATAOUT; 542*f9de33d4SLuiz Otavio O Souza *value = (ti_gpio_read_4(sc, bank, reg) & mask) ? 1 : 0; 543e53470feSOleksandr Tymoshenko TI_GPIO_UNLOCK(sc); 544e53470feSOleksandr Tymoshenko 545e53470feSOleksandr Tymoshenko return (0); 546e53470feSOleksandr Tymoshenko } 547e53470feSOleksandr Tymoshenko 548e53470feSOleksandr Tymoshenko /** 549e53470feSOleksandr Tymoshenko * ti_gpio_pin_toggle - Toggles a given GPIO pin 550e53470feSOleksandr Tymoshenko * @dev: gpio device handle 551e53470feSOleksandr Tymoshenko * @pin: the number of the pin 552e53470feSOleksandr Tymoshenko * 553e53470feSOleksandr Tymoshenko * 554e53470feSOleksandr Tymoshenko * LOCKING: 555e53470feSOleksandr Tymoshenko * Internally locks the context 556e53470feSOleksandr Tymoshenko * 557e53470feSOleksandr Tymoshenko * RETURNS: 558e53470feSOleksandr Tymoshenko * Returns 0 on success otherwise a error code 559e53470feSOleksandr Tymoshenko */ 560e53470feSOleksandr Tymoshenko static int 561e53470feSOleksandr Tymoshenko ti_gpio_pin_toggle(device_t dev, uint32_t pin) 562e53470feSOleksandr Tymoshenko { 563e53470feSOleksandr Tymoshenko struct ti_gpio_softc *sc = device_get_softc(dev); 564e53470feSOleksandr Tymoshenko uint32_t bank = (pin / PINS_PER_BANK); 565e53470feSOleksandr Tymoshenko uint32_t mask = (1UL << (pin % PINS_PER_BANK)); 566*f9de33d4SLuiz Otavio O Souza uint32_t reg, val; 567e53470feSOleksandr Tymoshenko 568e53470feSOleksandr Tymoshenko /* Sanity check the pin number is valid */ 569*f9de33d4SLuiz Otavio O Souza if ((bank >= ti_max_gpio_banks()) || (sc->sc_mem_res[bank] == NULL)) 570e53470feSOleksandr Tymoshenko return (EINVAL); 571e53470feSOleksandr Tymoshenko 572e53470feSOleksandr Tymoshenko /* Toggle the pin */ 573*f9de33d4SLuiz Otavio O Souza TI_GPIO_LOCK(sc); 574e53470feSOleksandr Tymoshenko val = ti_gpio_read_4(sc, bank, TI_GPIO_DATAOUT); 575e53470feSOleksandr Tymoshenko if (val & mask) 576*f9de33d4SLuiz Otavio O Souza reg = TI_GPIO_CLEARDATAOUT; 577e53470feSOleksandr Tymoshenko else 578*f9de33d4SLuiz Otavio O Souza reg = TI_GPIO_SETDATAOUT; 579*f9de33d4SLuiz Otavio O Souza ti_gpio_write_4(sc, bank, reg, mask); 580e53470feSOleksandr Tymoshenko TI_GPIO_UNLOCK(sc); 581e53470feSOleksandr Tymoshenko 582e53470feSOleksandr Tymoshenko return (0); 583e53470feSOleksandr Tymoshenko } 584e53470feSOleksandr Tymoshenko 585e53470feSOleksandr Tymoshenko /** 586e53470feSOleksandr Tymoshenko * ti_gpio_intr - ISR for all GPIO modules 587e53470feSOleksandr Tymoshenko * @arg: the soft context pointer 588e53470feSOleksandr Tymoshenko * 589e53470feSOleksandr Tymoshenko * Unsused 590e53470feSOleksandr Tymoshenko * 591e53470feSOleksandr Tymoshenko * LOCKING: 592e53470feSOleksandr Tymoshenko * Internally locks the context 593e53470feSOleksandr Tymoshenko * 594e53470feSOleksandr Tymoshenko */ 595e53470feSOleksandr Tymoshenko static void 596e53470feSOleksandr Tymoshenko ti_gpio_intr(void *arg) 597e53470feSOleksandr Tymoshenko { 598e53470feSOleksandr Tymoshenko struct ti_gpio_softc *sc = arg; 599e53470feSOleksandr Tymoshenko 600e53470feSOleksandr Tymoshenko TI_GPIO_LOCK(sc); 601e53470feSOleksandr Tymoshenko /* TODO: something useful */ 602e53470feSOleksandr Tymoshenko TI_GPIO_UNLOCK(sc); 603e53470feSOleksandr Tymoshenko } 604e53470feSOleksandr Tymoshenko 6059b1cba84SLuiz Otavio O Souza static int 6069b1cba84SLuiz Otavio O Souza ti_gpio_attach_intr(device_t dev) 6079b1cba84SLuiz Otavio O Souza { 6089b1cba84SLuiz Otavio O Souza int i; 6099b1cba84SLuiz Otavio O Souza struct ti_gpio_softc *sc; 6109b1cba84SLuiz Otavio O Souza 6119b1cba84SLuiz Otavio O Souza sc = device_get_softc(dev); 6124eb12144SAndrew Turner for (i = 0; i < ti_max_gpio_intrs(); i++) { 6139b1cba84SLuiz Otavio O Souza if (sc->sc_irq_res[i] == NULL) 6149b1cba84SLuiz Otavio O Souza break; 6159b1cba84SLuiz Otavio O Souza 6169b1cba84SLuiz Otavio O Souza /* 6179b1cba84SLuiz Otavio O Souza * Register our interrupt handler for each of the IRQ resources. 6189b1cba84SLuiz Otavio O Souza */ 6199b1cba84SLuiz Otavio O Souza if (bus_setup_intr(dev, sc->sc_irq_res[i], 6209b1cba84SLuiz Otavio O Souza INTR_TYPE_MISC | INTR_MPSAFE, NULL, ti_gpio_intr, sc, 6219b1cba84SLuiz Otavio O Souza &sc->sc_irq_hdl[i]) != 0) { 6229b1cba84SLuiz Otavio O Souza device_printf(dev, 6239b1cba84SLuiz Otavio O Souza "WARNING: unable to register interrupt handler\n"); 6249b1cba84SLuiz Otavio O Souza return (-1); 6259b1cba84SLuiz Otavio O Souza } 6269b1cba84SLuiz Otavio O Souza } 6279b1cba84SLuiz Otavio O Souza 6289b1cba84SLuiz Otavio O Souza return (0); 6299b1cba84SLuiz Otavio O Souza } 6309b1cba84SLuiz Otavio O Souza 6319b1cba84SLuiz Otavio O Souza static int 6329b1cba84SLuiz Otavio O Souza ti_gpio_detach_intr(device_t dev) 6339b1cba84SLuiz Otavio O Souza { 6349b1cba84SLuiz Otavio O Souza int i; 6359b1cba84SLuiz Otavio O Souza struct ti_gpio_softc *sc; 6369b1cba84SLuiz Otavio O Souza 6379b1cba84SLuiz Otavio O Souza /* Teardown our interrupt handlers. */ 6389b1cba84SLuiz Otavio O Souza sc = device_get_softc(dev); 6394eb12144SAndrew Turner for (i = 0; i < ti_max_gpio_intrs(); i++) { 6409b1cba84SLuiz Otavio O Souza if (sc->sc_irq_res[i] == NULL) 6419b1cba84SLuiz Otavio O Souza break; 6429b1cba84SLuiz Otavio O Souza 6439b1cba84SLuiz Otavio O Souza if (sc->sc_irq_hdl[i]) { 6449b1cba84SLuiz Otavio O Souza bus_teardown_intr(dev, sc->sc_irq_res[i], 6459b1cba84SLuiz Otavio O Souza sc->sc_irq_hdl[i]); 6469b1cba84SLuiz Otavio O Souza } 6479b1cba84SLuiz Otavio O Souza } 6489b1cba84SLuiz Otavio O Souza 6499b1cba84SLuiz Otavio O Souza return (0); 6509b1cba84SLuiz Otavio O Souza } 6519b1cba84SLuiz Otavio O Souza 6529b1cba84SLuiz Otavio O Souza static int 6539b1cba84SLuiz Otavio O Souza ti_gpio_bank_init(device_t dev, int bank) 6549b1cba84SLuiz Otavio O Souza { 6551f1e8f16SLuiz Otavio O Souza int pin; 6569b1cba84SLuiz Otavio O Souza struct ti_gpio_softc *sc; 6579b1cba84SLuiz Otavio O Souza uint32_t flags, reg_oe; 6589b1cba84SLuiz Otavio O Souza 6599b1cba84SLuiz Otavio O Souza sc = device_get_softc(dev); 6609b1cba84SLuiz Otavio O Souza 6619b1cba84SLuiz Otavio O Souza /* Enable the interface and functional clocks for the module. */ 6624eb12144SAndrew Turner ti_prcm_clk_enable(GPIO0_CLK + ti_first_gpio_bank() + bank); 6639b1cba84SLuiz Otavio O Souza 6649b1cba84SLuiz Otavio O Souza /* 6659b1cba84SLuiz Otavio O Souza * Read the revision number of the module. TI don't publish the 6669b1cba84SLuiz Otavio O Souza * actual revision numbers, so instead the values have been 6679b1cba84SLuiz Otavio O Souza * determined by experimentation. 6689b1cba84SLuiz Otavio O Souza */ 6699b1cba84SLuiz Otavio O Souza sc->sc_revision[bank] = ti_gpio_read_4(sc, bank, TI_GPIO_REVISION); 6709b1cba84SLuiz Otavio O Souza 6719b1cba84SLuiz Otavio O Souza /* Check the revision. */ 6724eb12144SAndrew Turner if (sc->sc_revision[bank] != ti_gpio_rev()) { 6739b1cba84SLuiz Otavio O Souza device_printf(dev, "Warning: could not determine the revision " 6749b1cba84SLuiz Otavio O Souza "of %u GPIO module (revision:0x%08x)\n", 6759b1cba84SLuiz Otavio O Souza bank, sc->sc_revision[bank]); 6769b1cba84SLuiz Otavio O Souza return (EINVAL); 6779b1cba84SLuiz Otavio O Souza } 6789b1cba84SLuiz Otavio O Souza 6799b1cba84SLuiz Otavio O Souza /* Disable interrupts for all pins. */ 680db8a14ecSLuiz Otavio O Souza ti_gpio_intr_clr(sc, bank, 0xffffffff); 6819b1cba84SLuiz Otavio O Souza 6829b1cba84SLuiz Otavio O Souza /* Init OE register based on pads configuration. */ 6839b1cba84SLuiz Otavio O Souza reg_oe = 0xffffffff; 6849b1cba84SLuiz Otavio O Souza for (pin = 0; pin < PINS_PER_BANK; pin++) { 685b6c7dacfSAndrew Turner TI_GPIO_GET_FLAGS(dev, PINS_PER_BANK * bank + pin, &flags); 6869b1cba84SLuiz Otavio O Souza if (flags & GPIO_PIN_OUTPUT) 6879b1cba84SLuiz Otavio O Souza reg_oe &= ~(1UL << pin); 6889b1cba84SLuiz Otavio O Souza } 6899b1cba84SLuiz Otavio O Souza ti_gpio_write_4(sc, bank, TI_GPIO_OE, reg_oe); 6909b1cba84SLuiz Otavio O Souza 6919b1cba84SLuiz Otavio O Souza return (0); 6929b1cba84SLuiz Otavio O Souza } 6939b1cba84SLuiz Otavio O Souza 694e53470feSOleksandr Tymoshenko /** 695e53470feSOleksandr Tymoshenko * ti_gpio_attach - attach function for the driver 696e53470feSOleksandr Tymoshenko * @dev: gpio device handle 697e53470feSOleksandr Tymoshenko * 698e53470feSOleksandr Tymoshenko * Allocates and sets up the driver context for all GPIO banks. This function 699e53470feSOleksandr Tymoshenko * expects the memory ranges and IRQs to already be allocated to the driver. 700e53470feSOleksandr Tymoshenko * 701e53470feSOleksandr Tymoshenko * LOCKING: 702e53470feSOleksandr Tymoshenko * None 703e53470feSOleksandr Tymoshenko * 704e53470feSOleksandr Tymoshenko * RETURNS: 705e53470feSOleksandr Tymoshenko * Always returns 0 706e53470feSOleksandr Tymoshenko */ 707e53470feSOleksandr Tymoshenko static int 708e53470feSOleksandr Tymoshenko ti_gpio_attach(device_t dev) 709e53470feSOleksandr Tymoshenko { 7109b1cba84SLuiz Otavio O Souza struct ti_gpio_softc *sc; 711e53470feSOleksandr Tymoshenko unsigned int i; 7129b1cba84SLuiz Otavio O Souza int err; 713e53470feSOleksandr Tymoshenko 7149b1cba84SLuiz Otavio O Souza sc = device_get_softc(dev); 715e53470feSOleksandr Tymoshenko sc->sc_dev = dev; 716e53470feSOleksandr Tymoshenko 717e53470feSOleksandr Tymoshenko TI_GPIO_LOCK_INIT(sc); 718e53470feSOleksandr Tymoshenko 719e53470feSOleksandr Tymoshenko /* There are up to 6 different GPIO register sets located in different 720e53470feSOleksandr Tymoshenko * memory areas on the chip. The memory range should have been set for 721e53470feSOleksandr Tymoshenko * the driver when it was added as a child. 722e53470feSOleksandr Tymoshenko */ 7239b1cba84SLuiz Otavio O Souza if (bus_alloc_resources(dev, ti_gpio_mem_spec, sc->sc_mem_res) != 0) { 724e53470feSOleksandr Tymoshenko device_printf(dev, "Error: could not allocate mem resources\n"); 725e53470feSOleksandr Tymoshenko return (ENXIO); 726e53470feSOleksandr Tymoshenko } 727e53470feSOleksandr Tymoshenko 728e53470feSOleksandr Tymoshenko /* Request the IRQ resources */ 7299b1cba84SLuiz Otavio O Souza if (bus_alloc_resources(dev, ti_gpio_irq_spec, sc->sc_irq_res) != 0) { 7309b1cba84SLuiz Otavio O Souza bus_release_resources(dev, ti_gpio_mem_spec, sc->sc_mem_res); 731e53470feSOleksandr Tymoshenko device_printf(dev, "Error: could not allocate irq resources\n"); 732e53470feSOleksandr Tymoshenko return (ENXIO); 733e53470feSOleksandr Tymoshenko } 734e53470feSOleksandr Tymoshenko 735e53470feSOleksandr Tymoshenko /* Setup the IRQ resources */ 7369b1cba84SLuiz Otavio O Souza if (ti_gpio_attach_intr(dev) != 0) { 7379b1cba84SLuiz Otavio O Souza ti_gpio_detach_intr(dev); 7389b1cba84SLuiz Otavio O Souza bus_release_resources(dev, ti_gpio_irq_spec, sc->sc_irq_res); 7399b1cba84SLuiz Otavio O Souza bus_release_resources(dev, ti_gpio_mem_spec, sc->sc_mem_res); 740e53470feSOleksandr Tymoshenko return (ENXIO); 741e53470feSOleksandr Tymoshenko } 742e53470feSOleksandr Tymoshenko 743e53470feSOleksandr Tymoshenko /* We need to go through each block and ensure the clocks are running and 744e53470feSOleksandr Tymoshenko * the module is enabled. It might be better to do this only when the 745e53470feSOleksandr Tymoshenko * pins are configured which would result in less power used if the GPIO 746e53470feSOleksandr Tymoshenko * pins weren't used ... 747e53470feSOleksandr Tymoshenko */ 7484eb12144SAndrew Turner for (i = 0; i < ti_max_gpio_banks(); i++) { 749e53470feSOleksandr Tymoshenko if (sc->sc_mem_res[i] != NULL) { 7501f1e8f16SLuiz Otavio O Souza /* Initialize the GPIO module. */ 7519b1cba84SLuiz Otavio O Souza err = ti_gpio_bank_init(dev, i); 7529b1cba84SLuiz Otavio O Souza if (err != 0) { 7539b1cba84SLuiz Otavio O Souza ti_gpio_detach_intr(dev); 7549b1cba84SLuiz Otavio O Souza bus_release_resources(dev, ti_gpio_irq_spec, 7559b1cba84SLuiz Otavio O Souza sc->sc_irq_res); 7569b1cba84SLuiz Otavio O Souza bus_release_resources(dev, ti_gpio_mem_spec, 7579b1cba84SLuiz Otavio O Souza sc->sc_mem_res); 7589b1cba84SLuiz Otavio O Souza return (err); 759e53470feSOleksandr Tymoshenko } 760e53470feSOleksandr Tymoshenko } 761e53470feSOleksandr Tymoshenko } 762e53470feSOleksandr Tymoshenko 763e53470feSOleksandr Tymoshenko /* Finish of the probe call */ 7648839e0e9SLuiz Otavio O Souza device_add_child(dev, "gpioc", -1); 7658839e0e9SLuiz Otavio O Souza device_add_child(dev, "gpiobus", -1); 76697b405f1SOleksandr Tymoshenko 767e53470feSOleksandr Tymoshenko return (bus_generic_attach(dev)); 768e53470feSOleksandr Tymoshenko } 769e53470feSOleksandr Tymoshenko 770e53470feSOleksandr Tymoshenko /** 771e53470feSOleksandr Tymoshenko * ti_gpio_detach - detach function for the driver 772e53470feSOleksandr Tymoshenko * @dev: scm device handle 773e53470feSOleksandr Tymoshenko * 774e53470feSOleksandr Tymoshenko * Allocates and sets up the driver context, this simply entails creating a 775e53470feSOleksandr Tymoshenko * bus mappings for the SCM register set. 776e53470feSOleksandr Tymoshenko * 777e53470feSOleksandr Tymoshenko * LOCKING: 778e53470feSOleksandr Tymoshenko * None 779e53470feSOleksandr Tymoshenko * 780e53470feSOleksandr Tymoshenko * RETURNS: 781e53470feSOleksandr Tymoshenko * Always returns 0 782e53470feSOleksandr Tymoshenko */ 783e53470feSOleksandr Tymoshenko static int 784e53470feSOleksandr Tymoshenko ti_gpio_detach(device_t dev) 785e53470feSOleksandr Tymoshenko { 786e53470feSOleksandr Tymoshenko struct ti_gpio_softc *sc = device_get_softc(dev); 787e53470feSOleksandr Tymoshenko unsigned int i; 788e53470feSOleksandr Tymoshenko 789e53470feSOleksandr Tymoshenko KASSERT(mtx_initialized(&sc->sc_mtx), ("gpio mutex not initialized")); 790e53470feSOleksandr Tymoshenko 791e53470feSOleksandr Tymoshenko /* Disable all interrupts */ 7924eb12144SAndrew Turner for (i = 0; i < ti_max_gpio_banks(); i++) { 793db8a14ecSLuiz Otavio O Souza if (sc->sc_mem_res[i] != NULL) 794db8a14ecSLuiz Otavio O Souza ti_gpio_intr_clr(sc, i, 0xffffffff); 795e53470feSOleksandr Tymoshenko } 796e53470feSOleksandr Tymoshenko 797e53470feSOleksandr Tymoshenko bus_generic_detach(dev); 798e53470feSOleksandr Tymoshenko 7999b1cba84SLuiz Otavio O Souza /* Release the memory and IRQ resources. */ 8009b1cba84SLuiz Otavio O Souza ti_gpio_detach_intr(dev); 8019b1cba84SLuiz Otavio O Souza bus_release_resources(dev, ti_gpio_irq_spec, sc->sc_irq_res); 8029b1cba84SLuiz Otavio O Souza bus_release_resources(dev, ti_gpio_mem_spec, sc->sc_mem_res); 803e53470feSOleksandr Tymoshenko 804e53470feSOleksandr Tymoshenko TI_GPIO_LOCK_DESTROY(sc); 805e53470feSOleksandr Tymoshenko 806e53470feSOleksandr Tymoshenko return (0); 807e53470feSOleksandr Tymoshenko } 808e53470feSOleksandr Tymoshenko 8098c705c2cSLuiz Otavio O Souza static phandle_t 8108c705c2cSLuiz Otavio O Souza ti_gpio_get_node(device_t bus, device_t dev) 8118c705c2cSLuiz Otavio O Souza { 8128c705c2cSLuiz Otavio O Souza 8138c705c2cSLuiz Otavio O Souza /* We only have one child, the GPIO bus, which needs our own node. */ 8148c705c2cSLuiz Otavio O Souza return (ofw_bus_get_node(bus)); 8158c705c2cSLuiz Otavio O Souza } 8168c705c2cSLuiz Otavio O Souza 817e53470feSOleksandr Tymoshenko static device_method_t ti_gpio_methods[] = { 818e53470feSOleksandr Tymoshenko DEVMETHOD(device_attach, ti_gpio_attach), 819e53470feSOleksandr Tymoshenko DEVMETHOD(device_detach, ti_gpio_detach), 820e53470feSOleksandr Tymoshenko 821e53470feSOleksandr Tymoshenko /* GPIO protocol */ 822e53470feSOleksandr Tymoshenko DEVMETHOD(gpio_pin_max, ti_gpio_pin_max), 823e53470feSOleksandr Tymoshenko DEVMETHOD(gpio_pin_getname, ti_gpio_pin_getname), 824e53470feSOleksandr Tymoshenko DEVMETHOD(gpio_pin_getflags, ti_gpio_pin_getflags), 825e53470feSOleksandr Tymoshenko DEVMETHOD(gpio_pin_getcaps, ti_gpio_pin_getcaps), 826e53470feSOleksandr Tymoshenko DEVMETHOD(gpio_pin_setflags, ti_gpio_pin_setflags), 827e53470feSOleksandr Tymoshenko DEVMETHOD(gpio_pin_get, ti_gpio_pin_get), 828e53470feSOleksandr Tymoshenko DEVMETHOD(gpio_pin_set, ti_gpio_pin_set), 829e53470feSOleksandr Tymoshenko DEVMETHOD(gpio_pin_toggle, ti_gpio_pin_toggle), 8308c705c2cSLuiz Otavio O Souza 8318c705c2cSLuiz Otavio O Souza /* ofw_bus interface */ 8328c705c2cSLuiz Otavio O Souza DEVMETHOD(ofw_bus_get_node, ti_gpio_get_node), 8338c705c2cSLuiz Otavio O Souza 834e53470feSOleksandr Tymoshenko {0, 0}, 835e53470feSOleksandr Tymoshenko }; 836e53470feSOleksandr Tymoshenko 837b6c7dacfSAndrew Turner driver_t ti_gpio_driver = { 838e53470feSOleksandr Tymoshenko "gpio", 839e53470feSOleksandr Tymoshenko ti_gpio_methods, 840e53470feSOleksandr Tymoshenko sizeof(struct ti_gpio_softc), 841e53470feSOleksandr Tymoshenko }; 842