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