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