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 59e53470feSOleksandr Tymoshenko #include <arm/ti/ti_scm.h> 60e53470feSOleksandr Tymoshenko #include <arm/ti/ti_prcm.h> 61e53470feSOleksandr Tymoshenko 62e53470feSOleksandr Tymoshenko #include <dev/fdt/fdt_common.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" 68e53470feSOleksandr Tymoshenko 69e53470feSOleksandr Tymoshenko /* Register definitions */ 70e53470feSOleksandr Tymoshenko #define TI_GPIO_REVISION 0x0000 71e53470feSOleksandr Tymoshenko #define TI_GPIO_SYSCONFIG 0x0010 72e53470feSOleksandr Tymoshenko #if defined(SOC_OMAP3) 73e53470feSOleksandr Tymoshenko #define TI_GPIO_SYSSTATUS 0x0014 74e53470feSOleksandr Tymoshenko #define TI_GPIO_IRQSTATUS1 0x0018 75e53470feSOleksandr Tymoshenko #define TI_GPIO_IRQENABLE1 0x001C 76e53470feSOleksandr Tymoshenko #define TI_GPIO_WAKEUPENABLE 0x0020 77e53470feSOleksandr Tymoshenko #define TI_GPIO_IRQSTATUS2 0x0028 78e53470feSOleksandr Tymoshenko #define TI_GPIO_IRQENABLE2 0x002C 79e53470feSOleksandr Tymoshenko #define TI_GPIO_CTRL 0x0030 80e53470feSOleksandr Tymoshenko #define TI_GPIO_OE 0x0034 81e53470feSOleksandr Tymoshenko #define TI_GPIO_DATAIN 0x0038 82e53470feSOleksandr Tymoshenko #define TI_GPIO_DATAOUT 0x003C 83e53470feSOleksandr Tymoshenko #define TI_GPIO_LEVELDETECT0 0x0040 84e53470feSOleksandr Tymoshenko #define TI_GPIO_LEVELDETECT1 0x0044 85e53470feSOleksandr Tymoshenko #define TI_GPIO_RISINGDETECT 0x0048 86e53470feSOleksandr Tymoshenko #define TI_GPIO_FALLINGDETECT 0x004C 87e53470feSOleksandr Tymoshenko #define TI_GPIO_DEBOUNCENABLE 0x0050 88e53470feSOleksandr Tymoshenko #define TI_GPIO_DEBOUNCINGTIME 0x0054 89e53470feSOleksandr Tymoshenko #define TI_GPIO_CLEARIRQENABLE1 0x0060 90e53470feSOleksandr Tymoshenko #define TI_GPIO_SETIRQENABLE1 0x0064 91e53470feSOleksandr Tymoshenko #define TI_GPIO_CLEARIRQENABLE2 0x0070 92e53470feSOleksandr Tymoshenko #define TI_GPIO_SETIRQENABLE2 0x0074 93e53470feSOleksandr Tymoshenko #define TI_GPIO_CLEARWKUENA 0x0080 94e53470feSOleksandr Tymoshenko #define TI_GPIO_SETWKUENA 0x0084 95e53470feSOleksandr Tymoshenko #define TI_GPIO_CLEARDATAOUT 0x0090 96e53470feSOleksandr Tymoshenko #define TI_GPIO_SETDATAOUT 0x0094 97e53470feSOleksandr Tymoshenko #elif defined(SOC_OMAP4) || defined(SOC_TI_AM335X) 98e53470feSOleksandr Tymoshenko #define TI_GPIO_IRQSTATUS_RAW_0 0x0024 99e53470feSOleksandr Tymoshenko #define TI_GPIO_IRQSTATUS_RAW_1 0x0028 100e53470feSOleksandr Tymoshenko #define TI_GPIO_IRQSTATUS_0 0x002C 101e53470feSOleksandr Tymoshenko #define TI_GPIO_IRQSTATUS_1 0x0030 102e53470feSOleksandr Tymoshenko #define TI_GPIO_IRQSTATUS_SET_0 0x0034 103e53470feSOleksandr Tymoshenko #define TI_GPIO_IRQSTATUS_SET_1 0x0038 104e53470feSOleksandr Tymoshenko #define TI_GPIO_IRQSTATUS_CLR_0 0x003C 105e53470feSOleksandr Tymoshenko #define TI_GPIO_IRQSTATUS_CLR_1 0x0040 106e53470feSOleksandr Tymoshenko #define TI_GPIO_IRQWAKEN_0 0x0044 107e53470feSOleksandr Tymoshenko #define TI_GPIO_IRQWAKEN_1 0x0048 108e53470feSOleksandr Tymoshenko #define TI_GPIO_SYSSTATUS 0x0114 109e53470feSOleksandr Tymoshenko #define TI_GPIO_IRQSTATUS1 0x0118 110e53470feSOleksandr Tymoshenko #define TI_GPIO_IRQENABLE1 0x011C 111e53470feSOleksandr Tymoshenko #define TI_GPIO_WAKEUPENABLE 0x0120 112e53470feSOleksandr Tymoshenko #define TI_GPIO_IRQSTATUS2 0x0128 113e53470feSOleksandr Tymoshenko #define TI_GPIO_IRQENABLE2 0x012C 114e53470feSOleksandr Tymoshenko #define TI_GPIO_CTRL 0x0130 115e53470feSOleksandr Tymoshenko #define TI_GPIO_OE 0x0134 116e53470feSOleksandr Tymoshenko #define TI_GPIO_DATAIN 0x0138 117e53470feSOleksandr Tymoshenko #define TI_GPIO_DATAOUT 0x013C 118e53470feSOleksandr Tymoshenko #define TI_GPIO_LEVELDETECT0 0x0140 119e53470feSOleksandr Tymoshenko #define TI_GPIO_LEVELDETECT1 0x0144 120e53470feSOleksandr Tymoshenko #define TI_GPIO_RISINGDETECT 0x0148 121e53470feSOleksandr Tymoshenko #define TI_GPIO_FALLINGDETECT 0x014C 122e53470feSOleksandr Tymoshenko #define TI_GPIO_DEBOUNCENABLE 0x0150 123e53470feSOleksandr Tymoshenko #define TI_GPIO_DEBOUNCINGTIME 0x0154 124e53470feSOleksandr Tymoshenko #define TI_GPIO_CLEARWKUPENA 0x0180 125e53470feSOleksandr Tymoshenko #define TI_GPIO_SETWKUENA 0x0184 126e53470feSOleksandr Tymoshenko #define TI_GPIO_CLEARDATAOUT 0x0190 127e53470feSOleksandr Tymoshenko #define TI_GPIO_SETDATAOUT 0x0194 128e53470feSOleksandr Tymoshenko #else 129e53470feSOleksandr Tymoshenko #error "Unknown SoC" 130e53470feSOleksandr Tymoshenko #endif 131e53470feSOleksandr Tymoshenko 132e53470feSOleksandr Tymoshenko /* Other SoC Specific definitions */ 133e53470feSOleksandr Tymoshenko #if defined(SOC_OMAP3) 134e53470feSOleksandr Tymoshenko #define MAX_GPIO_BANKS 6 135e53470feSOleksandr Tymoshenko #define FIRST_GPIO_BANK 1 136db8a14ecSLuiz Otavio O Souza #define INTR_PER_BANK 1 137e53470feSOleksandr Tymoshenko #define TI_GPIO_REV 0x00000025 138e53470feSOleksandr Tymoshenko #elif defined(SOC_OMAP4) 139e53470feSOleksandr Tymoshenko #define MAX_GPIO_BANKS 6 140e53470feSOleksandr Tymoshenko #define FIRST_GPIO_BANK 1 141db8a14ecSLuiz Otavio O Souza #define INTR_PER_BANK 1 142e53470feSOleksandr Tymoshenko #define TI_GPIO_REV 0x50600801 143e53470feSOleksandr Tymoshenko #elif defined(SOC_TI_AM335X) 144e53470feSOleksandr Tymoshenko #define MAX_GPIO_BANKS 4 145e53470feSOleksandr Tymoshenko #define FIRST_GPIO_BANK 0 146db8a14ecSLuiz Otavio O Souza #define INTR_PER_BANK 2 147e53470feSOleksandr Tymoshenko #define TI_GPIO_REV 0x50600801 148e53470feSOleksandr Tymoshenko #endif 149ff5823beSLuiz Otavio O Souza #define PINS_PER_BANK 32 150db8a14ecSLuiz Otavio O Souza #define MAX_GPIO_INTRS MAX_GPIO_BANKS * INTR_PER_BANK 151e53470feSOleksandr Tymoshenko 152e53470feSOleksandr Tymoshenko /** 153e53470feSOleksandr Tymoshenko * ti_gpio_mem_spec - Resource specification used when allocating resources 154e53470feSOleksandr Tymoshenko * ti_gpio_irq_spec - Resource specification used when allocating resources 155e53470feSOleksandr Tymoshenko * 156e53470feSOleksandr Tymoshenko * This driver module can have up to six independent memory regions, each 157e53470feSOleksandr Tymoshenko * region typically controls 32 GPIO pins. 158db8a14ecSLuiz Otavio O Souza * 159db8a14ecSLuiz Otavio O Souza * On OMAP3 and OMAP4 there is only one physical interrupt line per bank, 160db8a14ecSLuiz Otavio O Souza * but there are two set of registers which control the interrupt delivery 161db8a14ecSLuiz Otavio O Souza * to internal subsystems. The first set of registers control the 162db8a14ecSLuiz Otavio O Souza * interrupts delivery to the MPU and the second set control the 163db8a14ecSLuiz Otavio O Souza * interrupts delivery to the DSP. 164db8a14ecSLuiz Otavio O Souza * 165db8a14ecSLuiz Otavio O Souza * On AM335x there are two physical interrupt lines for each GPIO module. 166db8a14ecSLuiz Otavio O Souza * Each interrupt line is controlled by a set of registers. 167e53470feSOleksandr Tymoshenko */ 168e53470feSOleksandr Tymoshenko static struct resource_spec ti_gpio_mem_spec[] = { 169e53470feSOleksandr Tymoshenko { SYS_RES_MEMORY, 0, RF_ACTIVE }, 170e53470feSOleksandr Tymoshenko { SYS_RES_MEMORY, 1, RF_ACTIVE | RF_OPTIONAL }, 171e53470feSOleksandr Tymoshenko { SYS_RES_MEMORY, 2, RF_ACTIVE | RF_OPTIONAL }, 172e53470feSOleksandr Tymoshenko { SYS_RES_MEMORY, 3, RF_ACTIVE | RF_OPTIONAL }, 173e53470feSOleksandr Tymoshenko #if !defined(SOC_TI_AM335X) 174e53470feSOleksandr Tymoshenko { SYS_RES_MEMORY, 4, RF_ACTIVE | RF_OPTIONAL }, 175e53470feSOleksandr Tymoshenko { SYS_RES_MEMORY, 5, RF_ACTIVE | RF_OPTIONAL }, 176e53470feSOleksandr Tymoshenko #endif 177e53470feSOleksandr Tymoshenko { -1, 0, 0 } 178e53470feSOleksandr Tymoshenko }; 179e53470feSOleksandr Tymoshenko static struct resource_spec ti_gpio_irq_spec[] = { 180e53470feSOleksandr Tymoshenko { SYS_RES_IRQ, 0, RF_ACTIVE }, 181e53470feSOleksandr Tymoshenko { SYS_RES_IRQ, 1, RF_ACTIVE | RF_OPTIONAL }, 182e53470feSOleksandr Tymoshenko { SYS_RES_IRQ, 2, RF_ACTIVE | RF_OPTIONAL }, 183e53470feSOleksandr Tymoshenko { SYS_RES_IRQ, 3, RF_ACTIVE | RF_OPTIONAL }, 184e53470feSOleksandr Tymoshenko { SYS_RES_IRQ, 4, RF_ACTIVE | RF_OPTIONAL }, 185e53470feSOleksandr Tymoshenko { SYS_RES_IRQ, 5, RF_ACTIVE | RF_OPTIONAL }, 186db8a14ecSLuiz Otavio O Souza #if defined(SOC_TI_AM335X) 187db8a14ecSLuiz Otavio O Souza { SYS_RES_IRQ, 6, RF_ACTIVE | RF_OPTIONAL }, 188db8a14ecSLuiz Otavio O Souza { SYS_RES_IRQ, 7, RF_ACTIVE | RF_OPTIONAL }, 189e53470feSOleksandr Tymoshenko #endif 190e53470feSOleksandr Tymoshenko { -1, 0, 0 } 191e53470feSOleksandr Tymoshenko }; 192e53470feSOleksandr Tymoshenko 193e53470feSOleksandr Tymoshenko /** 194e53470feSOleksandr Tymoshenko * Structure that stores the driver context. 195e53470feSOleksandr Tymoshenko * 196e53470feSOleksandr Tymoshenko * This structure is allocated during driver attach. 197e53470feSOleksandr Tymoshenko */ 198e53470feSOleksandr Tymoshenko struct ti_gpio_softc { 199e53470feSOleksandr Tymoshenko device_t sc_dev; 200e53470feSOleksandr Tymoshenko 201ff5823beSLuiz Otavio O Souza /* 202ff5823beSLuiz Otavio O Souza * The memory resource(s) for the PRCM register set, when the device is 203ff5823beSLuiz Otavio O Souza * created the caller can assign up to 6 memory regions depending on 204ff5823beSLuiz Otavio O Souza * the SoC type. 205e53470feSOleksandr Tymoshenko */ 206e53470feSOleksandr Tymoshenko struct resource *sc_mem_res[MAX_GPIO_BANKS]; 207db8a14ecSLuiz Otavio O Souza struct resource *sc_irq_res[MAX_GPIO_INTRS]; 208e53470feSOleksandr Tymoshenko 209ff5823beSLuiz Otavio O Souza /* The handle for the register IRQ handlers. */ 210db8a14ecSLuiz Otavio O Souza void *sc_irq_hdl[MAX_GPIO_INTRS]; 211e53470feSOleksandr Tymoshenko 212ff5823beSLuiz Otavio O Souza /* 213ff5823beSLuiz Otavio O Souza * The following describes the H/W revision of each of the GPIO banks. 214ff5823beSLuiz Otavio O Souza */ 215e53470feSOleksandr Tymoshenko uint32_t sc_revision[MAX_GPIO_BANKS]; 216e53470feSOleksandr Tymoshenko 217e53470feSOleksandr Tymoshenko struct mtx sc_mtx; 218e53470feSOleksandr Tymoshenko }; 219e53470feSOleksandr Tymoshenko 220e53470feSOleksandr Tymoshenko /** 221e53470feSOleksandr Tymoshenko * Macros for driver mutex locking 222e53470feSOleksandr Tymoshenko */ 223e53470feSOleksandr Tymoshenko #define TI_GPIO_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) 224e53470feSOleksandr Tymoshenko #define TI_GPIO_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) 225e53470feSOleksandr Tymoshenko #define TI_GPIO_LOCK_INIT(_sc) \ 226e53470feSOleksandr Tymoshenko mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), \ 227e53470feSOleksandr Tymoshenko "ti_gpio", MTX_DEF) 228ff5823beSLuiz Otavio O Souza #define TI_GPIO_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx) 229ff5823beSLuiz Otavio O Souza #define TI_GPIO_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED) 230ff5823beSLuiz Otavio O Souza #define TI_GPIO_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED) 231e53470feSOleksandr Tymoshenko 232e53470feSOleksandr Tymoshenko /** 233e53470feSOleksandr Tymoshenko * ti_gpio_read_4 - reads a 16-bit value from one of the PADCONFS registers 234e53470feSOleksandr Tymoshenko * @sc: GPIO device context 235e53470feSOleksandr Tymoshenko * @bank: The bank to read from 236e53470feSOleksandr Tymoshenko * @off: The offset of a register from the GPIO register address range 237e53470feSOleksandr Tymoshenko * 238e53470feSOleksandr Tymoshenko * 239e53470feSOleksandr Tymoshenko * RETURNS: 240e53470feSOleksandr Tymoshenko * 32-bit value read from the register. 241e53470feSOleksandr Tymoshenko */ 242e53470feSOleksandr Tymoshenko static inline uint32_t 243e53470feSOleksandr Tymoshenko ti_gpio_read_4(struct ti_gpio_softc *sc, unsigned int bank, bus_size_t off) 244e53470feSOleksandr Tymoshenko { 245e53470feSOleksandr Tymoshenko return (bus_read_4(sc->sc_mem_res[bank], off)); 246e53470feSOleksandr Tymoshenko } 247e53470feSOleksandr Tymoshenko 248e53470feSOleksandr Tymoshenko /** 249e53470feSOleksandr Tymoshenko * ti_gpio_write_4 - writes a 32-bit value to one of the PADCONFS registers 250e53470feSOleksandr Tymoshenko * @sc: GPIO device context 251e53470feSOleksandr Tymoshenko * @bank: The bank to write to 252e53470feSOleksandr Tymoshenko * @off: The offset of a register from the GPIO register address range 253e53470feSOleksandr Tymoshenko * @val: The value to write into the register 254e53470feSOleksandr Tymoshenko * 255e53470feSOleksandr Tymoshenko * RETURNS: 256e53470feSOleksandr Tymoshenko * nothing 257e53470feSOleksandr Tymoshenko */ 258e53470feSOleksandr Tymoshenko static inline void 259e53470feSOleksandr Tymoshenko ti_gpio_write_4(struct ti_gpio_softc *sc, unsigned int bank, bus_size_t off, 260e53470feSOleksandr Tymoshenko uint32_t val) 261e53470feSOleksandr Tymoshenko { 262e53470feSOleksandr Tymoshenko bus_write_4(sc->sc_mem_res[bank], off, val); 263e53470feSOleksandr Tymoshenko } 264e53470feSOleksandr Tymoshenko 265db8a14ecSLuiz Otavio O Souza static inline void 266db8a14ecSLuiz Otavio O Souza ti_gpio_intr_clr(struct ti_gpio_softc *sc, unsigned int bank, uint32_t mask) 267db8a14ecSLuiz Otavio O Souza { 268db8a14ecSLuiz Otavio O Souza 269db8a14ecSLuiz Otavio O Souza /* We clear both set of registers. */ 270db8a14ecSLuiz Otavio O Souza #if defined(SOC_OMAP4) || defined(SOC_TI_AM335X) 271db8a14ecSLuiz Otavio O Souza ti_gpio_write_4(sc, bank, TI_GPIO_IRQSTATUS_CLR_0, mask); 272db8a14ecSLuiz Otavio O Souza ti_gpio_write_4(sc, bank, TI_GPIO_IRQSTATUS_CLR_1, mask); 273db8a14ecSLuiz Otavio O Souza #else 274db8a14ecSLuiz Otavio O Souza ti_gpio_write_4(sc, bank, TI_GPIO_CLEARIRQENABLE1, mask); 275db8a14ecSLuiz Otavio O Souza ti_gpio_write_4(sc, bank, TI_GPIO_CLEARIRQENABLE2, mask); 276db8a14ecSLuiz Otavio O Souza #endif 277db8a14ecSLuiz Otavio O Souza } 278db8a14ecSLuiz Otavio O Souza 279e53470feSOleksandr Tymoshenko /** 280e53470feSOleksandr Tymoshenko * ti_gpio_pin_max - Returns the maximum number of GPIO pins 281e53470feSOleksandr Tymoshenko * @dev: gpio device handle 282e53470feSOleksandr Tymoshenko * @maxpin: pointer to a value that upon return will contain the maximum number 283e53470feSOleksandr Tymoshenko * of pins in the device. 284e53470feSOleksandr Tymoshenko * 285e53470feSOleksandr Tymoshenko * 286e53470feSOleksandr Tymoshenko * LOCKING: 287e53470feSOleksandr Tymoshenko * Internally locks the context 288e53470feSOleksandr Tymoshenko * 289e53470feSOleksandr Tymoshenko * RETURNS: 290e53470feSOleksandr Tymoshenko * Returns 0 on success otherwise an error code 291e53470feSOleksandr Tymoshenko */ 292e53470feSOleksandr Tymoshenko static int 293e53470feSOleksandr Tymoshenko ti_gpio_pin_max(device_t dev, int *maxpin) 294e53470feSOleksandr Tymoshenko { 295e53470feSOleksandr Tymoshenko struct ti_gpio_softc *sc = device_get_softc(dev); 296e53470feSOleksandr Tymoshenko unsigned int i; 297e53470feSOleksandr Tymoshenko unsigned int banks = 0; 298e53470feSOleksandr Tymoshenko 299e53470feSOleksandr Tymoshenko TI_GPIO_LOCK(sc); 300e53470feSOleksandr Tymoshenko 301e53470feSOleksandr Tymoshenko /* Calculate how many valid banks we have and then multiply that by 32 to 302e53470feSOleksandr Tymoshenko * give use the total number of pins. 303e53470feSOleksandr Tymoshenko */ 304e53470feSOleksandr Tymoshenko for (i = 0; i < MAX_GPIO_BANKS; i++) { 305e53470feSOleksandr Tymoshenko if (sc->sc_mem_res[i] != NULL) 306e53470feSOleksandr Tymoshenko banks++; 307e53470feSOleksandr Tymoshenko } 308e53470feSOleksandr Tymoshenko 30997b405f1SOleksandr Tymoshenko *maxpin = (banks * PINS_PER_BANK) - 1; 310e53470feSOleksandr Tymoshenko 311e53470feSOleksandr Tymoshenko TI_GPIO_UNLOCK(sc); 312e53470feSOleksandr Tymoshenko 313e53470feSOleksandr Tymoshenko return (0); 314e53470feSOleksandr Tymoshenko } 315e53470feSOleksandr Tymoshenko 316e53470feSOleksandr Tymoshenko /** 317e53470feSOleksandr Tymoshenko * ti_gpio_pin_getcaps - Gets the capabilties of a given pin 318e53470feSOleksandr Tymoshenko * @dev: gpio device handle 319e53470feSOleksandr Tymoshenko * @pin: the number of the pin 320e53470feSOleksandr Tymoshenko * @caps: pointer to a value that upon return will contain the capabilities 321e53470feSOleksandr Tymoshenko * 322e53470feSOleksandr Tymoshenko * Currently all pins have the same capability, notably: 323e53470feSOleksandr Tymoshenko * - GPIO_PIN_INPUT 324e53470feSOleksandr Tymoshenko * - GPIO_PIN_OUTPUT 325e53470feSOleksandr Tymoshenko * - GPIO_PIN_PULLUP 326e53470feSOleksandr Tymoshenko * - GPIO_PIN_PULLDOWN 327e53470feSOleksandr Tymoshenko * 328e53470feSOleksandr Tymoshenko * LOCKING: 329e53470feSOleksandr Tymoshenko * Internally locks the context 330e53470feSOleksandr Tymoshenko * 331e53470feSOleksandr Tymoshenko * RETURNS: 332e53470feSOleksandr Tymoshenko * Returns 0 on success otherwise an error code 333e53470feSOleksandr Tymoshenko */ 334e53470feSOleksandr Tymoshenko static int 335e53470feSOleksandr Tymoshenko ti_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) 336e53470feSOleksandr Tymoshenko { 337e53470feSOleksandr Tymoshenko struct ti_gpio_softc *sc = device_get_softc(dev); 338e53470feSOleksandr Tymoshenko uint32_t bank = (pin / PINS_PER_BANK); 339e53470feSOleksandr Tymoshenko 340e53470feSOleksandr Tymoshenko TI_GPIO_LOCK(sc); 341e53470feSOleksandr Tymoshenko 342e53470feSOleksandr Tymoshenko /* Sanity check the pin number is valid */ 3438f80e4e1SOleksandr Tymoshenko if ((bank >= MAX_GPIO_BANKS) || (sc->sc_mem_res[bank] == NULL)) { 344e53470feSOleksandr Tymoshenko TI_GPIO_UNLOCK(sc); 345e53470feSOleksandr Tymoshenko return (EINVAL); 346e53470feSOleksandr Tymoshenko } 347e53470feSOleksandr Tymoshenko 348e53470feSOleksandr Tymoshenko *caps = (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT |GPIO_PIN_PULLUP | 349e53470feSOleksandr Tymoshenko GPIO_PIN_PULLDOWN); 350e53470feSOleksandr Tymoshenko 351e53470feSOleksandr Tymoshenko TI_GPIO_UNLOCK(sc); 352e53470feSOleksandr Tymoshenko 353e53470feSOleksandr Tymoshenko return (0); 354e53470feSOleksandr Tymoshenko } 355e53470feSOleksandr Tymoshenko 356e53470feSOleksandr Tymoshenko /** 357e53470feSOleksandr Tymoshenko * ti_gpio_pin_getflags - Gets the current flags of a given pin 358e53470feSOleksandr Tymoshenko * @dev: gpio device handle 359e53470feSOleksandr Tymoshenko * @pin: the number of the pin 360e53470feSOleksandr Tymoshenko * @flags: upon return will contain the current flags of the pin 361e53470feSOleksandr Tymoshenko * 362e53470feSOleksandr Tymoshenko * Reads the current flags of a given pin, here we actually read the H/W 363e53470feSOleksandr Tymoshenko * registers to determine the flags, rather than storing the value in the 364e53470feSOleksandr Tymoshenko * setflags call. 365e53470feSOleksandr Tymoshenko * 366e53470feSOleksandr Tymoshenko * LOCKING: 367e53470feSOleksandr Tymoshenko * Internally locks the context 368e53470feSOleksandr Tymoshenko * 369e53470feSOleksandr Tymoshenko * RETURNS: 370e53470feSOleksandr Tymoshenko * Returns 0 on success otherwise an error code 371e53470feSOleksandr Tymoshenko */ 372e53470feSOleksandr Tymoshenko static int 373e53470feSOleksandr Tymoshenko ti_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) 374e53470feSOleksandr Tymoshenko { 375e53470feSOleksandr Tymoshenko struct ti_gpio_softc *sc = device_get_softc(dev); 376e53470feSOleksandr Tymoshenko uint32_t bank = (pin / PINS_PER_BANK); 377e53470feSOleksandr Tymoshenko 378e53470feSOleksandr Tymoshenko TI_GPIO_LOCK(sc); 379e53470feSOleksandr Tymoshenko 380e53470feSOleksandr Tymoshenko /* Sanity check the pin number is valid */ 3818f80e4e1SOleksandr Tymoshenko if ((bank >= MAX_GPIO_BANKS) || (sc->sc_mem_res[bank] == NULL)) { 382e53470feSOleksandr Tymoshenko TI_GPIO_UNLOCK(sc); 383e53470feSOleksandr Tymoshenko return (EINVAL); 384e53470feSOleksandr Tymoshenko } 385e53470feSOleksandr Tymoshenko 386e53470feSOleksandr Tymoshenko /* Get the current pin state */ 387e53470feSOleksandr Tymoshenko ti_scm_padconf_get_gpioflags(pin, flags); 388e53470feSOleksandr Tymoshenko 389e53470feSOleksandr Tymoshenko TI_GPIO_UNLOCK(sc); 390e53470feSOleksandr Tymoshenko 391e53470feSOleksandr Tymoshenko return (0); 392e53470feSOleksandr Tymoshenko } 393e53470feSOleksandr Tymoshenko 394e53470feSOleksandr Tymoshenko /** 395e53470feSOleksandr Tymoshenko * ti_gpio_pin_getname - Gets the name of a given pin 396e53470feSOleksandr Tymoshenko * @dev: gpio device handle 397e53470feSOleksandr Tymoshenko * @pin: the number of the pin 398e53470feSOleksandr Tymoshenko * @name: buffer to put the name in 399e53470feSOleksandr Tymoshenko * 400e53470feSOleksandr Tymoshenko * The driver simply calls the pins gpio_n, where 'n' is obviously the number 401e53470feSOleksandr Tymoshenko * of the pin. 402e53470feSOleksandr Tymoshenko * 403e53470feSOleksandr Tymoshenko * LOCKING: 404e53470feSOleksandr Tymoshenko * Internally locks the context 405e53470feSOleksandr Tymoshenko * 406e53470feSOleksandr Tymoshenko * RETURNS: 407e53470feSOleksandr Tymoshenko * Returns 0 on success otherwise an error code 408e53470feSOleksandr Tymoshenko */ 409e53470feSOleksandr Tymoshenko static int 410e53470feSOleksandr Tymoshenko ti_gpio_pin_getname(device_t dev, uint32_t pin, char *name) 411e53470feSOleksandr Tymoshenko { 412e53470feSOleksandr Tymoshenko struct ti_gpio_softc *sc = device_get_softc(dev); 413e53470feSOleksandr Tymoshenko uint32_t bank = (pin / PINS_PER_BANK); 414e53470feSOleksandr Tymoshenko 415e53470feSOleksandr Tymoshenko TI_GPIO_LOCK(sc); 416e53470feSOleksandr Tymoshenko 417e53470feSOleksandr Tymoshenko /* Sanity check the pin number is valid */ 4188f80e4e1SOleksandr Tymoshenko if ((bank >= MAX_GPIO_BANKS) || (sc->sc_mem_res[bank] == NULL)) { 419e53470feSOleksandr Tymoshenko TI_GPIO_UNLOCK(sc); 420e53470feSOleksandr Tymoshenko return (EINVAL); 421e53470feSOleksandr Tymoshenko } 422e53470feSOleksandr Tymoshenko 423e53470feSOleksandr Tymoshenko /* Set a very simple name */ 424e53470feSOleksandr Tymoshenko snprintf(name, GPIOMAXNAME, "gpio_%u", pin); 425e53470feSOleksandr Tymoshenko name[GPIOMAXNAME - 1] = '\0'; 426e53470feSOleksandr Tymoshenko 427e53470feSOleksandr Tymoshenko TI_GPIO_UNLOCK(sc); 428e53470feSOleksandr Tymoshenko 429e53470feSOleksandr Tymoshenko return (0); 430e53470feSOleksandr Tymoshenko } 431e53470feSOleksandr Tymoshenko 432e53470feSOleksandr Tymoshenko /** 433e53470feSOleksandr Tymoshenko * ti_gpio_pin_setflags - Sets the flags for a given pin 434e53470feSOleksandr Tymoshenko * @dev: gpio device handle 435e53470feSOleksandr Tymoshenko * @pin: the number of the pin 436e53470feSOleksandr Tymoshenko * @flags: the flags to set 437e53470feSOleksandr Tymoshenko * 438e53470feSOleksandr Tymoshenko * The flags of the pin correspond to things like input/output mode, pull-ups, 439e53470feSOleksandr Tymoshenko * pull-downs, etc. This driver doesn't support all flags, only the following: 440e53470feSOleksandr Tymoshenko * - GPIO_PIN_INPUT 441e53470feSOleksandr Tymoshenko * - GPIO_PIN_OUTPUT 442e53470feSOleksandr Tymoshenko * - GPIO_PIN_PULLUP 443e53470feSOleksandr Tymoshenko * - GPIO_PIN_PULLDOWN 444e53470feSOleksandr Tymoshenko * 445e53470feSOleksandr Tymoshenko * LOCKING: 446e53470feSOleksandr Tymoshenko * Internally locks the context 447e53470feSOleksandr Tymoshenko * 448e53470feSOleksandr Tymoshenko * RETURNS: 449e53470feSOleksandr Tymoshenko * Returns 0 on success otherwise an error code 450e53470feSOleksandr Tymoshenko */ 451e53470feSOleksandr Tymoshenko static int 452e53470feSOleksandr Tymoshenko ti_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) 453e53470feSOleksandr Tymoshenko { 454e53470feSOleksandr Tymoshenko struct ti_gpio_softc *sc = device_get_softc(dev); 455e53470feSOleksandr Tymoshenko uint32_t bank = (pin / PINS_PER_BANK); 456e53470feSOleksandr Tymoshenko uint32_t mask = (1UL << (pin % PINS_PER_BANK)); 457e53470feSOleksandr Tymoshenko uint32_t reg_val; 458e53470feSOleksandr Tymoshenko 459e53470feSOleksandr Tymoshenko /* Sanity check the flags supplied are valid, i.e. not input and output */ 460e53470feSOleksandr Tymoshenko if ((flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) == 0x0000) 461e53470feSOleksandr Tymoshenko return (EINVAL); 462e53470feSOleksandr Tymoshenko if ((flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) == 463e53470feSOleksandr Tymoshenko (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) 464e53470feSOleksandr Tymoshenko return (EINVAL); 465e53470feSOleksandr Tymoshenko if ((flags & (GPIO_PIN_PULLUP|GPIO_PIN_PULLDOWN)) == 466e53470feSOleksandr Tymoshenko (GPIO_PIN_PULLUP|GPIO_PIN_PULLDOWN)) 467e53470feSOleksandr Tymoshenko return (EINVAL); 468e53470feSOleksandr Tymoshenko 469e53470feSOleksandr Tymoshenko TI_GPIO_LOCK(sc); 470e53470feSOleksandr Tymoshenko 471e53470feSOleksandr Tymoshenko /* Sanity check the pin number is valid */ 4728f80e4e1SOleksandr Tymoshenko if ((bank >= MAX_GPIO_BANKS) || (sc->sc_mem_res[bank] == NULL)) { 473e53470feSOleksandr Tymoshenko TI_GPIO_UNLOCK(sc); 474e53470feSOleksandr Tymoshenko return (EINVAL); 475e53470feSOleksandr Tymoshenko } 476e53470feSOleksandr Tymoshenko 477e53470feSOleksandr Tymoshenko /* Set the GPIO mode and state */ 478e53470feSOleksandr Tymoshenko if (ti_scm_padconf_set_gpioflags(pin, flags) != 0) { 479e53470feSOleksandr Tymoshenko TI_GPIO_UNLOCK(sc); 480e53470feSOleksandr Tymoshenko return (EINVAL); 481e53470feSOleksandr Tymoshenko } 482e53470feSOleksandr Tymoshenko 483e53470feSOleksandr Tymoshenko /* If configuring as an output set the "output enable" bit */ 484e53470feSOleksandr Tymoshenko reg_val = ti_gpio_read_4(sc, bank, TI_GPIO_OE); 485e53470feSOleksandr Tymoshenko if (flags & GPIO_PIN_INPUT) 486e53470feSOleksandr Tymoshenko reg_val |= mask; 487e53470feSOleksandr Tymoshenko else 488e53470feSOleksandr Tymoshenko reg_val &= ~mask; 489e53470feSOleksandr Tymoshenko ti_gpio_write_4(sc, bank, TI_GPIO_OE, reg_val); 490e53470feSOleksandr Tymoshenko 491e53470feSOleksandr Tymoshenko TI_GPIO_UNLOCK(sc); 492e53470feSOleksandr Tymoshenko 493e53470feSOleksandr Tymoshenko return (0); 494e53470feSOleksandr Tymoshenko } 495e53470feSOleksandr Tymoshenko 496e53470feSOleksandr Tymoshenko /** 497e53470feSOleksandr Tymoshenko * ti_gpio_pin_set - Sets the current level on a GPIO pin 498e53470feSOleksandr Tymoshenko * @dev: gpio device handle 499e53470feSOleksandr Tymoshenko * @pin: the number of the pin 500e53470feSOleksandr Tymoshenko * @value: non-zero value will drive the pin high, otherwise the pin is 501e53470feSOleksandr Tymoshenko * driven low. 502e53470feSOleksandr Tymoshenko * 503e53470feSOleksandr Tymoshenko * 504e53470feSOleksandr Tymoshenko * LOCKING: 505e53470feSOleksandr Tymoshenko * Internally locks the context 506e53470feSOleksandr Tymoshenko * 507e53470feSOleksandr Tymoshenko * RETURNS: 508e53470feSOleksandr Tymoshenko * Returns 0 on success otherwise a error code 509e53470feSOleksandr Tymoshenko */ 510e53470feSOleksandr Tymoshenko static int 511e53470feSOleksandr Tymoshenko ti_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value) 512e53470feSOleksandr Tymoshenko { 513e53470feSOleksandr Tymoshenko struct ti_gpio_softc *sc = device_get_softc(dev); 514e53470feSOleksandr Tymoshenko uint32_t bank = (pin / PINS_PER_BANK); 515e53470feSOleksandr Tymoshenko uint32_t mask = (1UL << (pin % PINS_PER_BANK)); 516e53470feSOleksandr Tymoshenko 517e53470feSOleksandr Tymoshenko TI_GPIO_LOCK(sc); 518e53470feSOleksandr Tymoshenko 519e53470feSOleksandr Tymoshenko /* Sanity check the pin number is valid */ 5208f80e4e1SOleksandr Tymoshenko if ((bank >= MAX_GPIO_BANKS) || (sc->sc_mem_res[bank] == NULL)) { 521e53470feSOleksandr Tymoshenko TI_GPIO_UNLOCK(sc); 522e53470feSOleksandr Tymoshenko return (EINVAL); 523e53470feSOleksandr Tymoshenko } 524e53470feSOleksandr Tymoshenko 525e53470feSOleksandr Tymoshenko ti_gpio_write_4(sc, bank, (value == GPIO_PIN_LOW) ? TI_GPIO_CLEARDATAOUT 526e53470feSOleksandr Tymoshenko : TI_GPIO_SETDATAOUT, mask); 527e53470feSOleksandr Tymoshenko 528e53470feSOleksandr Tymoshenko TI_GPIO_UNLOCK(sc); 529e53470feSOleksandr Tymoshenko 530e53470feSOleksandr Tymoshenko return (0); 531e53470feSOleksandr Tymoshenko } 532e53470feSOleksandr Tymoshenko 533e53470feSOleksandr Tymoshenko /** 534e53470feSOleksandr Tymoshenko * ti_gpio_pin_get - Gets the current level on a GPIO pin 535e53470feSOleksandr Tymoshenko * @dev: gpio device handle 536e53470feSOleksandr Tymoshenko * @pin: the number of the pin 537e53470feSOleksandr Tymoshenko * @value: pointer to a value that upond return will contain the pin value 538e53470feSOleksandr Tymoshenko * 539e53470feSOleksandr Tymoshenko * The pin must be configured as an input pin beforehand, otherwise this 540e53470feSOleksandr Tymoshenko * function will fail. 541e53470feSOleksandr Tymoshenko * 542e53470feSOleksandr Tymoshenko * LOCKING: 543e53470feSOleksandr Tymoshenko * Internally locks the context 544e53470feSOleksandr Tymoshenko * 545e53470feSOleksandr Tymoshenko * RETURNS: 546e53470feSOleksandr Tymoshenko * Returns 0 on success otherwise a error code 547e53470feSOleksandr Tymoshenko */ 548e53470feSOleksandr Tymoshenko static int 549e53470feSOleksandr Tymoshenko ti_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *value) 550e53470feSOleksandr Tymoshenko { 551e53470feSOleksandr Tymoshenko struct ti_gpio_softc *sc = device_get_softc(dev); 552e53470feSOleksandr Tymoshenko uint32_t bank = (pin / PINS_PER_BANK); 553e53470feSOleksandr Tymoshenko uint32_t mask = (1UL << (pin % PINS_PER_BANK)); 554e53470feSOleksandr Tymoshenko uint32_t val = 0; 555e53470feSOleksandr Tymoshenko 556e53470feSOleksandr Tymoshenko TI_GPIO_LOCK(sc); 557e53470feSOleksandr Tymoshenko 558e53470feSOleksandr Tymoshenko /* Sanity check the pin number is valid */ 5598f80e4e1SOleksandr Tymoshenko if ((bank >= MAX_GPIO_BANKS) || (sc->sc_mem_res[bank] == NULL)) { 560e53470feSOleksandr Tymoshenko TI_GPIO_UNLOCK(sc); 561e53470feSOleksandr Tymoshenko return (EINVAL); 562e53470feSOleksandr Tymoshenko } 563e53470feSOleksandr Tymoshenko 564e53470feSOleksandr Tymoshenko /* Sanity check the pin is not configured as an output */ 565e53470feSOleksandr Tymoshenko val = ti_gpio_read_4(sc, bank, TI_GPIO_OE); 566e53470feSOleksandr Tymoshenko 567e53470feSOleksandr Tymoshenko /* Read the value on the pin */ 56897b405f1SOleksandr Tymoshenko if (val & mask) 569e53470feSOleksandr Tymoshenko *value = (ti_gpio_read_4(sc, bank, TI_GPIO_DATAIN) & mask) ? 1 : 0; 5709f165184SLuiz Otavio O Souza else 5719f165184SLuiz Otavio O Souza *value = (ti_gpio_read_4(sc, bank, TI_GPIO_DATAOUT) & mask) ? 1 : 0; 572e53470feSOleksandr Tymoshenko 573e53470feSOleksandr Tymoshenko TI_GPIO_UNLOCK(sc); 574e53470feSOleksandr Tymoshenko 575e53470feSOleksandr Tymoshenko return (0); 576e53470feSOleksandr Tymoshenko } 577e53470feSOleksandr Tymoshenko 578e53470feSOleksandr Tymoshenko /** 579e53470feSOleksandr Tymoshenko * ti_gpio_pin_toggle - Toggles a given GPIO pin 580e53470feSOleksandr Tymoshenko * @dev: gpio device handle 581e53470feSOleksandr Tymoshenko * @pin: the number of the pin 582e53470feSOleksandr Tymoshenko * 583e53470feSOleksandr Tymoshenko * 584e53470feSOleksandr Tymoshenko * LOCKING: 585e53470feSOleksandr Tymoshenko * Internally locks the context 586e53470feSOleksandr Tymoshenko * 587e53470feSOleksandr Tymoshenko * RETURNS: 588e53470feSOleksandr Tymoshenko * Returns 0 on success otherwise a error code 589e53470feSOleksandr Tymoshenko */ 590e53470feSOleksandr Tymoshenko static int 591e53470feSOleksandr Tymoshenko ti_gpio_pin_toggle(device_t dev, uint32_t pin) 592e53470feSOleksandr Tymoshenko { 593e53470feSOleksandr Tymoshenko struct ti_gpio_softc *sc = device_get_softc(dev); 594e53470feSOleksandr Tymoshenko uint32_t bank = (pin / PINS_PER_BANK); 595e53470feSOleksandr Tymoshenko uint32_t mask = (1UL << (pin % PINS_PER_BANK)); 596e53470feSOleksandr Tymoshenko uint32_t val; 597e53470feSOleksandr Tymoshenko 598e53470feSOleksandr Tymoshenko TI_GPIO_LOCK(sc); 599e53470feSOleksandr Tymoshenko 600e53470feSOleksandr Tymoshenko /* Sanity check the pin number is valid */ 6018f80e4e1SOleksandr Tymoshenko if ((bank >= MAX_GPIO_BANKS) || (sc->sc_mem_res[bank] == NULL)) { 602e53470feSOleksandr Tymoshenko TI_GPIO_UNLOCK(sc); 603e53470feSOleksandr Tymoshenko return (EINVAL); 604e53470feSOleksandr Tymoshenko } 605e53470feSOleksandr Tymoshenko 606e53470feSOleksandr Tymoshenko /* Toggle the pin */ 607e53470feSOleksandr Tymoshenko val = ti_gpio_read_4(sc, bank, TI_GPIO_DATAOUT); 608e53470feSOleksandr Tymoshenko if (val & mask) 609e53470feSOleksandr Tymoshenko ti_gpio_write_4(sc, bank, TI_GPIO_CLEARDATAOUT, mask); 610e53470feSOleksandr Tymoshenko else 611e53470feSOleksandr Tymoshenko ti_gpio_write_4(sc, bank, TI_GPIO_SETDATAOUT, mask); 612e53470feSOleksandr Tymoshenko 613e53470feSOleksandr Tymoshenko TI_GPIO_UNLOCK(sc); 614e53470feSOleksandr Tymoshenko 615e53470feSOleksandr Tymoshenko return (0); 616e53470feSOleksandr Tymoshenko } 617e53470feSOleksandr Tymoshenko 618e53470feSOleksandr Tymoshenko /** 619e53470feSOleksandr Tymoshenko * ti_gpio_intr - ISR for all GPIO modules 620e53470feSOleksandr Tymoshenko * @arg: the soft context pointer 621e53470feSOleksandr Tymoshenko * 622e53470feSOleksandr Tymoshenko * Unsused 623e53470feSOleksandr Tymoshenko * 624e53470feSOleksandr Tymoshenko * LOCKING: 625e53470feSOleksandr Tymoshenko * Internally locks the context 626e53470feSOleksandr Tymoshenko * 627e53470feSOleksandr Tymoshenko */ 628e53470feSOleksandr Tymoshenko static void 629e53470feSOleksandr Tymoshenko ti_gpio_intr(void *arg) 630e53470feSOleksandr Tymoshenko { 631e53470feSOleksandr Tymoshenko struct ti_gpio_softc *sc = arg; 632e53470feSOleksandr Tymoshenko 633e53470feSOleksandr Tymoshenko TI_GPIO_LOCK(sc); 634e53470feSOleksandr Tymoshenko /* TODO: something useful */ 635e53470feSOleksandr Tymoshenko TI_GPIO_UNLOCK(sc); 636e53470feSOleksandr Tymoshenko } 637e53470feSOleksandr Tymoshenko 638e53470feSOleksandr Tymoshenko /** 639e53470feSOleksandr Tymoshenko * ti_gpio_probe - probe function for the driver 640e53470feSOleksandr Tymoshenko * @dev: gpio device handle 641e53470feSOleksandr Tymoshenko * 642e53470feSOleksandr Tymoshenko * Simply sets the name of the driver 643e53470feSOleksandr Tymoshenko * 644e53470feSOleksandr Tymoshenko * LOCKING: 645e53470feSOleksandr Tymoshenko * None 646e53470feSOleksandr Tymoshenko * 647e53470feSOleksandr Tymoshenko * RETURNS: 648e53470feSOleksandr Tymoshenko * Always returns 0 649e53470feSOleksandr Tymoshenko */ 650e53470feSOleksandr Tymoshenko static int 651e53470feSOleksandr Tymoshenko ti_gpio_probe(device_t dev) 652e53470feSOleksandr Tymoshenko { 653add35ed5SIan Lepore 654add35ed5SIan Lepore if (!ofw_bus_status_okay(dev)) 655add35ed5SIan Lepore return (ENXIO); 656add35ed5SIan Lepore 657e53470feSOleksandr Tymoshenko if (!ofw_bus_is_compatible(dev, "ti,gpio")) 658e53470feSOleksandr Tymoshenko return (ENXIO); 659e53470feSOleksandr Tymoshenko 660e53470feSOleksandr Tymoshenko device_set_desc(dev, "TI General Purpose I/O (GPIO)"); 661ff5823beSLuiz Otavio O Souza 662e53470feSOleksandr Tymoshenko return (0); 663e53470feSOleksandr Tymoshenko } 664e53470feSOleksandr Tymoshenko 6659b1cba84SLuiz Otavio O Souza static int 6669b1cba84SLuiz Otavio O Souza ti_gpio_attach_intr(device_t dev) 6679b1cba84SLuiz Otavio O Souza { 6689b1cba84SLuiz Otavio O Souza int i; 6699b1cba84SLuiz Otavio O Souza struct ti_gpio_softc *sc; 6709b1cba84SLuiz Otavio O Souza 6719b1cba84SLuiz Otavio O Souza sc = device_get_softc(dev); 672db8a14ecSLuiz Otavio O Souza for (i = 0; i < MAX_GPIO_INTRS; i++) { 6739b1cba84SLuiz Otavio O Souza if (sc->sc_irq_res[i] == NULL) 6749b1cba84SLuiz Otavio O Souza break; 6759b1cba84SLuiz Otavio O Souza 6769b1cba84SLuiz Otavio O Souza /* 6779b1cba84SLuiz Otavio O Souza * Register our interrupt handler for each of the IRQ resources. 6789b1cba84SLuiz Otavio O Souza */ 6799b1cba84SLuiz Otavio O Souza if (bus_setup_intr(dev, sc->sc_irq_res[i], 6809b1cba84SLuiz Otavio O Souza INTR_TYPE_MISC | INTR_MPSAFE, NULL, ti_gpio_intr, sc, 6819b1cba84SLuiz Otavio O Souza &sc->sc_irq_hdl[i]) != 0) { 6829b1cba84SLuiz Otavio O Souza device_printf(dev, 6839b1cba84SLuiz Otavio O Souza "WARNING: unable to register interrupt handler\n"); 6849b1cba84SLuiz Otavio O Souza return (-1); 6859b1cba84SLuiz Otavio O Souza } 6869b1cba84SLuiz Otavio O Souza } 6879b1cba84SLuiz Otavio O Souza 6889b1cba84SLuiz Otavio O Souza return (0); 6899b1cba84SLuiz Otavio O Souza } 6909b1cba84SLuiz Otavio O Souza 6919b1cba84SLuiz Otavio O Souza static int 6929b1cba84SLuiz Otavio O Souza ti_gpio_detach_intr(device_t dev) 6939b1cba84SLuiz Otavio O Souza { 6949b1cba84SLuiz Otavio O Souza int i; 6959b1cba84SLuiz Otavio O Souza struct ti_gpio_softc *sc; 6969b1cba84SLuiz Otavio O Souza 6979b1cba84SLuiz Otavio O Souza /* Teardown our interrupt handlers. */ 6989b1cba84SLuiz Otavio O Souza sc = device_get_softc(dev); 699db8a14ecSLuiz Otavio O Souza for (i = 0; i < MAX_GPIO_INTRS; i++) { 7009b1cba84SLuiz Otavio O Souza if (sc->sc_irq_res[i] == NULL) 7019b1cba84SLuiz Otavio O Souza break; 7029b1cba84SLuiz Otavio O Souza 7039b1cba84SLuiz Otavio O Souza if (sc->sc_irq_hdl[i]) { 7049b1cba84SLuiz Otavio O Souza bus_teardown_intr(dev, sc->sc_irq_res[i], 7059b1cba84SLuiz Otavio O Souza sc->sc_irq_hdl[i]); 7069b1cba84SLuiz Otavio O Souza } 7079b1cba84SLuiz Otavio O Souza } 7089b1cba84SLuiz Otavio O Souza 7099b1cba84SLuiz Otavio O Souza return (0); 7109b1cba84SLuiz Otavio O Souza } 7119b1cba84SLuiz Otavio O Souza 7129b1cba84SLuiz Otavio O Souza static int 7139b1cba84SLuiz Otavio O Souza ti_gpio_bank_init(device_t dev, int bank) 7149b1cba84SLuiz Otavio O Souza { 715*1f1e8f16SLuiz Otavio O Souza int pin; 7169b1cba84SLuiz Otavio O Souza struct ti_gpio_softc *sc; 7179b1cba84SLuiz Otavio O Souza uint32_t flags, reg_oe; 7189b1cba84SLuiz Otavio O Souza 7199b1cba84SLuiz Otavio O Souza sc = device_get_softc(dev); 7209b1cba84SLuiz Otavio O Souza 7219b1cba84SLuiz Otavio O Souza /* Enable the interface and functional clocks for the module. */ 7229b1cba84SLuiz Otavio O Souza ti_prcm_clk_enable(GPIO0_CLK + FIRST_GPIO_BANK + bank); 7239b1cba84SLuiz Otavio O Souza 7249b1cba84SLuiz Otavio O Souza /* 7259b1cba84SLuiz Otavio O Souza * Read the revision number of the module. TI don't publish the 7269b1cba84SLuiz Otavio O Souza * actual revision numbers, so instead the values have been 7279b1cba84SLuiz Otavio O Souza * determined by experimentation. 7289b1cba84SLuiz Otavio O Souza */ 7299b1cba84SLuiz Otavio O Souza sc->sc_revision[bank] = ti_gpio_read_4(sc, bank, TI_GPIO_REVISION); 7309b1cba84SLuiz Otavio O Souza 7319b1cba84SLuiz Otavio O Souza /* Check the revision. */ 7329b1cba84SLuiz Otavio O Souza if (sc->sc_revision[bank] != TI_GPIO_REV) { 7339b1cba84SLuiz Otavio O Souza device_printf(dev, "Warning: could not determine the revision " 7349b1cba84SLuiz Otavio O Souza "of %u GPIO module (revision:0x%08x)\n", 7359b1cba84SLuiz Otavio O Souza bank, sc->sc_revision[bank]); 7369b1cba84SLuiz Otavio O Souza return (EINVAL); 7379b1cba84SLuiz Otavio O Souza } 7389b1cba84SLuiz Otavio O Souza 7399b1cba84SLuiz Otavio O Souza /* Disable interrupts for all pins. */ 740db8a14ecSLuiz Otavio O Souza ti_gpio_intr_clr(sc, bank, 0xffffffff); 7419b1cba84SLuiz Otavio O Souza 7429b1cba84SLuiz Otavio O Souza /* Init OE register based on pads configuration. */ 7439b1cba84SLuiz Otavio O Souza reg_oe = 0xffffffff; 7449b1cba84SLuiz Otavio O Souza for (pin = 0; pin < PINS_PER_BANK; pin++) { 7459b1cba84SLuiz Otavio O Souza ti_scm_padconf_get_gpioflags(PINS_PER_BANK * bank + pin, 7469b1cba84SLuiz Otavio O Souza &flags); 7479b1cba84SLuiz Otavio O Souza if (flags & GPIO_PIN_OUTPUT) 7489b1cba84SLuiz Otavio O Souza reg_oe &= ~(1UL << pin); 7499b1cba84SLuiz Otavio O Souza } 7509b1cba84SLuiz Otavio O Souza ti_gpio_write_4(sc, bank, TI_GPIO_OE, reg_oe); 7519b1cba84SLuiz Otavio O Souza 7529b1cba84SLuiz Otavio O Souza return (0); 7539b1cba84SLuiz Otavio O Souza } 7549b1cba84SLuiz Otavio O Souza 755e53470feSOleksandr Tymoshenko /** 756e53470feSOleksandr Tymoshenko * ti_gpio_attach - attach function for the driver 757e53470feSOleksandr Tymoshenko * @dev: gpio device handle 758e53470feSOleksandr Tymoshenko * 759e53470feSOleksandr Tymoshenko * Allocates and sets up the driver context for all GPIO banks. This function 760e53470feSOleksandr Tymoshenko * expects the memory ranges and IRQs to already be allocated to the driver. 761e53470feSOleksandr Tymoshenko * 762e53470feSOleksandr Tymoshenko * LOCKING: 763e53470feSOleksandr Tymoshenko * None 764e53470feSOleksandr Tymoshenko * 765e53470feSOleksandr Tymoshenko * RETURNS: 766e53470feSOleksandr Tymoshenko * Always returns 0 767e53470feSOleksandr Tymoshenko */ 768e53470feSOleksandr Tymoshenko static int 769e53470feSOleksandr Tymoshenko ti_gpio_attach(device_t dev) 770e53470feSOleksandr Tymoshenko { 7719b1cba84SLuiz Otavio O Souza struct ti_gpio_softc *sc; 772e53470feSOleksandr Tymoshenko unsigned int i; 7739b1cba84SLuiz Otavio O Souza int err; 774e53470feSOleksandr Tymoshenko 7759b1cba84SLuiz Otavio O Souza sc = device_get_softc(dev); 776e53470feSOleksandr Tymoshenko sc->sc_dev = dev; 777e53470feSOleksandr Tymoshenko 778e53470feSOleksandr Tymoshenko TI_GPIO_LOCK_INIT(sc); 779e53470feSOleksandr Tymoshenko 780e53470feSOleksandr Tymoshenko /* There are up to 6 different GPIO register sets located in different 781e53470feSOleksandr Tymoshenko * memory areas on the chip. The memory range should have been set for 782e53470feSOleksandr Tymoshenko * the driver when it was added as a child. 783e53470feSOleksandr Tymoshenko */ 7849b1cba84SLuiz Otavio O Souza if (bus_alloc_resources(dev, ti_gpio_mem_spec, sc->sc_mem_res) != 0) { 785e53470feSOleksandr Tymoshenko device_printf(dev, "Error: could not allocate mem resources\n"); 786e53470feSOleksandr Tymoshenko return (ENXIO); 787e53470feSOleksandr Tymoshenko } 788e53470feSOleksandr Tymoshenko 789e53470feSOleksandr Tymoshenko /* Request the IRQ resources */ 7909b1cba84SLuiz Otavio O Souza if (bus_alloc_resources(dev, ti_gpio_irq_spec, sc->sc_irq_res) != 0) { 7919b1cba84SLuiz Otavio O Souza bus_release_resources(dev, ti_gpio_mem_spec, sc->sc_mem_res); 792e53470feSOleksandr Tymoshenko device_printf(dev, "Error: could not allocate irq resources\n"); 793e53470feSOleksandr Tymoshenko return (ENXIO); 794e53470feSOleksandr Tymoshenko } 795e53470feSOleksandr Tymoshenko 796e53470feSOleksandr Tymoshenko /* Setup the IRQ resources */ 7979b1cba84SLuiz Otavio O Souza if (ti_gpio_attach_intr(dev) != 0) { 7989b1cba84SLuiz Otavio O Souza ti_gpio_detach_intr(dev); 7999b1cba84SLuiz Otavio O Souza bus_release_resources(dev, ti_gpio_irq_spec, sc->sc_irq_res); 8009b1cba84SLuiz Otavio O Souza bus_release_resources(dev, ti_gpio_mem_spec, sc->sc_mem_res); 801e53470feSOleksandr Tymoshenko return (ENXIO); 802e53470feSOleksandr Tymoshenko } 803e53470feSOleksandr Tymoshenko 804e53470feSOleksandr Tymoshenko /* We need to go through each block and ensure the clocks are running and 805e53470feSOleksandr Tymoshenko * the module is enabled. It might be better to do this only when the 806e53470feSOleksandr Tymoshenko * pins are configured which would result in less power used if the GPIO 807e53470feSOleksandr Tymoshenko * pins weren't used ... 808e53470feSOleksandr Tymoshenko */ 809e53470feSOleksandr Tymoshenko for (i = 0; i < MAX_GPIO_BANKS; i++) { 810e53470feSOleksandr Tymoshenko if (sc->sc_mem_res[i] != NULL) { 811*1f1e8f16SLuiz Otavio O Souza /* Initialize the GPIO module. */ 8129b1cba84SLuiz Otavio O Souza err = ti_gpio_bank_init(dev, i); 8139b1cba84SLuiz Otavio O Souza if (err != 0) { 8149b1cba84SLuiz Otavio O Souza ti_gpio_detach_intr(dev); 8159b1cba84SLuiz Otavio O Souza bus_release_resources(dev, ti_gpio_irq_spec, 8169b1cba84SLuiz Otavio O Souza sc->sc_irq_res); 8179b1cba84SLuiz Otavio O Souza bus_release_resources(dev, ti_gpio_mem_spec, 8189b1cba84SLuiz Otavio O Souza sc->sc_mem_res); 8199b1cba84SLuiz Otavio O Souza return (err); 820e53470feSOleksandr Tymoshenko } 821e53470feSOleksandr Tymoshenko } 822e53470feSOleksandr Tymoshenko } 823e53470feSOleksandr Tymoshenko 824e53470feSOleksandr Tymoshenko /* Finish of the probe call */ 825e53470feSOleksandr Tymoshenko device_add_child(dev, "gpioc", device_get_unit(dev)); 826e53470feSOleksandr Tymoshenko device_add_child(dev, "gpiobus", device_get_unit(dev)); 82797b405f1SOleksandr Tymoshenko 828e53470feSOleksandr Tymoshenko return (bus_generic_attach(dev)); 829e53470feSOleksandr Tymoshenko } 830e53470feSOleksandr Tymoshenko 831e53470feSOleksandr Tymoshenko /** 832e53470feSOleksandr Tymoshenko * ti_gpio_detach - detach function for the driver 833e53470feSOleksandr Tymoshenko * @dev: scm device handle 834e53470feSOleksandr Tymoshenko * 835e53470feSOleksandr Tymoshenko * Allocates and sets up the driver context, this simply entails creating a 836e53470feSOleksandr Tymoshenko * bus mappings for the SCM register set. 837e53470feSOleksandr Tymoshenko * 838e53470feSOleksandr Tymoshenko * LOCKING: 839e53470feSOleksandr Tymoshenko * None 840e53470feSOleksandr Tymoshenko * 841e53470feSOleksandr Tymoshenko * RETURNS: 842e53470feSOleksandr Tymoshenko * Always returns 0 843e53470feSOleksandr Tymoshenko */ 844e53470feSOleksandr Tymoshenko static int 845e53470feSOleksandr Tymoshenko ti_gpio_detach(device_t dev) 846e53470feSOleksandr Tymoshenko { 847e53470feSOleksandr Tymoshenko struct ti_gpio_softc *sc = device_get_softc(dev); 848e53470feSOleksandr Tymoshenko unsigned int i; 849e53470feSOleksandr Tymoshenko 850e53470feSOleksandr Tymoshenko KASSERT(mtx_initialized(&sc->sc_mtx), ("gpio mutex not initialized")); 851e53470feSOleksandr Tymoshenko 852e53470feSOleksandr Tymoshenko /* Disable all interrupts */ 853e53470feSOleksandr Tymoshenko for (i = 0; i < MAX_GPIO_BANKS; i++) { 854db8a14ecSLuiz Otavio O Souza if (sc->sc_mem_res[i] != NULL) 855db8a14ecSLuiz Otavio O Souza ti_gpio_intr_clr(sc, i, 0xffffffff); 856e53470feSOleksandr Tymoshenko } 857e53470feSOleksandr Tymoshenko 858e53470feSOleksandr Tymoshenko bus_generic_detach(dev); 859e53470feSOleksandr Tymoshenko 8609b1cba84SLuiz Otavio O Souza /* Release the memory and IRQ resources. */ 8619b1cba84SLuiz Otavio O Souza ti_gpio_detach_intr(dev); 8629b1cba84SLuiz Otavio O Souza bus_release_resources(dev, ti_gpio_irq_spec, sc->sc_irq_res); 8639b1cba84SLuiz Otavio O Souza bus_release_resources(dev, ti_gpio_mem_spec, sc->sc_mem_res); 864e53470feSOleksandr Tymoshenko 865e53470feSOleksandr Tymoshenko TI_GPIO_LOCK_DESTROY(sc); 866e53470feSOleksandr Tymoshenko 867e53470feSOleksandr Tymoshenko return (0); 868e53470feSOleksandr Tymoshenko } 869e53470feSOleksandr Tymoshenko 8708c705c2cSLuiz Otavio O Souza static phandle_t 8718c705c2cSLuiz Otavio O Souza ti_gpio_get_node(device_t bus, device_t dev) 8728c705c2cSLuiz Otavio O Souza { 8738c705c2cSLuiz Otavio O Souza 8748c705c2cSLuiz Otavio O Souza /* We only have one child, the GPIO bus, which needs our own node. */ 8758c705c2cSLuiz Otavio O Souza return (ofw_bus_get_node(bus)); 8768c705c2cSLuiz Otavio O Souza } 8778c705c2cSLuiz Otavio O Souza 878e53470feSOleksandr Tymoshenko static device_method_t ti_gpio_methods[] = { 879e53470feSOleksandr Tymoshenko DEVMETHOD(device_probe, ti_gpio_probe), 880e53470feSOleksandr Tymoshenko DEVMETHOD(device_attach, ti_gpio_attach), 881e53470feSOleksandr Tymoshenko DEVMETHOD(device_detach, ti_gpio_detach), 882e53470feSOleksandr Tymoshenko 883e53470feSOleksandr Tymoshenko /* GPIO protocol */ 884e53470feSOleksandr Tymoshenko DEVMETHOD(gpio_pin_max, ti_gpio_pin_max), 885e53470feSOleksandr Tymoshenko DEVMETHOD(gpio_pin_getname, ti_gpio_pin_getname), 886e53470feSOleksandr Tymoshenko DEVMETHOD(gpio_pin_getflags, ti_gpio_pin_getflags), 887e53470feSOleksandr Tymoshenko DEVMETHOD(gpio_pin_getcaps, ti_gpio_pin_getcaps), 888e53470feSOleksandr Tymoshenko DEVMETHOD(gpio_pin_setflags, ti_gpio_pin_setflags), 889e53470feSOleksandr Tymoshenko DEVMETHOD(gpio_pin_get, ti_gpio_pin_get), 890e53470feSOleksandr Tymoshenko DEVMETHOD(gpio_pin_set, ti_gpio_pin_set), 891e53470feSOleksandr Tymoshenko DEVMETHOD(gpio_pin_toggle, ti_gpio_pin_toggle), 8928c705c2cSLuiz Otavio O Souza 8938c705c2cSLuiz Otavio O Souza /* ofw_bus interface */ 8948c705c2cSLuiz Otavio O Souza DEVMETHOD(ofw_bus_get_node, ti_gpio_get_node), 8958c705c2cSLuiz Otavio O Souza 896e53470feSOleksandr Tymoshenko {0, 0}, 897e53470feSOleksandr Tymoshenko }; 898e53470feSOleksandr Tymoshenko 899e53470feSOleksandr Tymoshenko static driver_t ti_gpio_driver = { 900e53470feSOleksandr Tymoshenko "gpio", 901e53470feSOleksandr Tymoshenko ti_gpio_methods, 902e53470feSOleksandr Tymoshenko sizeof(struct ti_gpio_softc), 903e53470feSOleksandr Tymoshenko }; 904e53470feSOleksandr Tymoshenko static devclass_t ti_gpio_devclass; 905e53470feSOleksandr Tymoshenko 906e53470feSOleksandr Tymoshenko DRIVER_MODULE(ti_gpio, simplebus, ti_gpio_driver, ti_gpio_devclass, 0, 0); 907