1179595Sbenno/*-
2179595Sbenno * Copyright (c) 2006 Benno Rice.  All rights reserved.
3179595Sbenno *
4179595Sbenno * Redistribution and use in source and binary forms, with or without
5179595Sbenno * modification, are permitted provided that the following conditions
6179595Sbenno * are met:
7179595Sbenno * 1. Redistributions of source code must retain the above copyright
8179595Sbenno *    notice, this list of conditions and the following disclaimer.
9179595Sbenno * 2. Redistributions in binary form must reproduce the above copyright
10179595Sbenno *    notice, this list of conditions and the following disclaimer in the
11179595Sbenno *    documentation and/or other materials provided with the distribution.
12179595Sbenno *
13179595Sbenno * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14179595Sbenno * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15179595Sbenno * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16179595Sbenno * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17179595Sbenno * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18179595Sbenno * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19179595Sbenno * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20179595Sbenno * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21179595Sbenno * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22179595Sbenno * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23179595Sbenno */
24179595Sbenno
25179595Sbenno#include <sys/cdefs.h>
26179595Sbenno__FBSDID("$FreeBSD$");
27179595Sbenno
28179595Sbenno#include <sys/param.h>
29179595Sbenno#include <sys/systm.h>
30179595Sbenno#include <sys/bus.h>
31179595Sbenno#include <sys/kernel.h>
32179595Sbenno#include <sys/lock.h>
33179595Sbenno#include <sys/interrupt.h>
34179595Sbenno#include <sys/module.h>
35179595Sbenno#include <sys/malloc.h>
36179595Sbenno#include <sys/mutex.h>
37179595Sbenno#include <sys/rman.h>
38179595Sbenno#include <sys/queue.h>
39179595Sbenno#include <sys/taskqueue.h>
40179595Sbenno#include <sys/timetc.h>
41179595Sbenno#include <machine/bus.h>
42179595Sbenno#include <machine/intr.h>
43179595Sbenno
44179595Sbenno#include <arm/xscale/pxa/pxavar.h>
45179595Sbenno#include <arm/xscale/pxa/pxareg.h>
46179595Sbenno
47179595Sbennostruct pxa_gpio_softc {
48179595Sbenno	struct resource *	pg_res[4];
49179595Sbenno	bus_space_tag_t		pg_bst;
50179595Sbenno	bus_space_handle_t	pg_bsh;
51179595Sbenno	struct mtx		pg_mtx;
52179595Sbenno
53179595Sbenno	uint32_t		pg_intr[3];
54179595Sbenno};
55179595Sbenno
56179595Sbennostatic struct resource_spec pxa_gpio_spec[] = {
57179595Sbenno	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
58179595Sbenno	{ SYS_RES_IRQ,		0,	RF_ACTIVE },
59179595Sbenno	{ SYS_RES_IRQ,		1,	RF_ACTIVE },
60179595Sbenno	{ SYS_RES_IRQ,		2,	RF_ACTIVE },
61179595Sbenno	{ -1, 0 }
62179595Sbenno};
63179595Sbenno
64179595Sbennostatic struct pxa_gpio_softc *pxa_gpio_softc = NULL;
65179595Sbenno
66179595Sbennostatic int	pxa_gpio_probe(device_t);
67179595Sbennostatic int	pxa_gpio_attach(device_t);
68179595Sbenno
69179595Sbennostatic driver_filter_t	pxa_gpio_intr0;
70179595Sbennostatic driver_filter_t	pxa_gpio_intr1;
71179595Sbennostatic driver_filter_t	pxa_gpio_intrN;
72179595Sbenno
73179595Sbennostatic int
74179595Sbennopxa_gpio_probe(device_t dev)
75179595Sbenno{
76179595Sbenno
77179595Sbenno	device_set_desc(dev, "GPIO Controller");
78179595Sbenno	return (0);
79179595Sbenno}
80179595Sbenno
81179595Sbennostatic int
82179595Sbennopxa_gpio_attach(device_t dev)
83179595Sbenno{
84179595Sbenno	int	error;
85179595Sbenno	void	*ihl;
86179595Sbenno	struct	pxa_gpio_softc *sc;
87179595Sbenno
88179595Sbenno	sc = (struct pxa_gpio_softc *)device_get_softc(dev);
89179595Sbenno
90179595Sbenno	if (pxa_gpio_softc != NULL)
91179595Sbenno		return (ENXIO);
92179595Sbenno	pxa_gpio_softc = sc;
93179595Sbenno
94179595Sbenno	error = bus_alloc_resources(dev, pxa_gpio_spec, sc->pg_res);
95179595Sbenno	if (error) {
96179595Sbenno		device_printf(dev, "could not allocate resources\n");
97179595Sbenno		return (ENXIO);
98179595Sbenno	}
99179595Sbenno
100179595Sbenno	sc->pg_bst = rman_get_bustag(sc->pg_res[0]);
101179595Sbenno	sc->pg_bsh = rman_get_bushandle(sc->pg_res[0]);
102179595Sbenno
103179595Sbenno	/* Disable and clear all interrupts. */
104179595Sbenno	bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GRER0, 0);
105179595Sbenno	bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GRER1, 0);
106179595Sbenno	bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GRER2, 0);
107179595Sbenno	bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GFER0, 0);
108179595Sbenno	bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GFER1, 0);
109179595Sbenno	bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GFER2, 0);
110179595Sbenno	bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR0, ~0);
111179595Sbenno	bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR1, ~0);
112179595Sbenno	bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR2, ~0);
113179595Sbenno
114179595Sbenno	mtx_init(&sc->pg_mtx, "GPIO mutex", NULL, MTX_SPIN);
115179595Sbenno
116179595Sbenno	if (bus_setup_intr(dev, sc->pg_res[1], INTR_TYPE_MISC|INTR_MPSAFE,
117179595Sbenno	    pxa_gpio_intr0, NULL, sc, &ihl) != 0) {
118179595Sbenno		bus_release_resources(dev, pxa_gpio_spec, sc->pg_res);
119179595Sbenno		device_printf(dev, "could not set up intr0\n");
120179595Sbenno		return (ENXIO);
121179595Sbenno	}
122179595Sbenno
123179595Sbenno	if (bus_setup_intr(dev, sc->pg_res[2], INTR_TYPE_MISC|INTR_MPSAFE,
124179595Sbenno	    pxa_gpio_intr1, NULL, sc, &ihl) != 0) {
125179595Sbenno		bus_release_resources(dev, pxa_gpio_spec, sc->pg_res);
126179595Sbenno		device_printf(dev, "could not set up intr1\n");
127179595Sbenno		return (ENXIO);
128179595Sbenno	}
129179595Sbenno
130179595Sbenno	if (bus_setup_intr(dev, sc->pg_res[3], INTR_TYPE_MISC|INTR_MPSAFE,
131179595Sbenno	    pxa_gpio_intrN, NULL, sc, &ihl) != 0) {
132179595Sbenno		bus_release_resources(dev, pxa_gpio_spec, sc->pg_res);
133179595Sbenno		device_printf(dev, "could not set up intrN\n");
134179595Sbenno		return (ENXIO);
135179595Sbenno	}
136179595Sbenno
137179595Sbenno	return (0);
138179595Sbenno}
139179595Sbenno
140179595Sbennostatic int
141179595Sbennopxa_gpio_intr0(void *arg)
142179595Sbenno{
143179595Sbenno	struct	pxa_gpio_softc *sc;
144179595Sbenno
145179595Sbenno	sc = (struct pxa_gpio_softc *)arg;
146179595Sbenno
147179595Sbenno	bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR0, 0x1);
148179595Sbenno	sc->pg_intr[0] |= 1;
149179595Sbenno
150179595Sbenno	return (FILTER_HANDLED);
151179595Sbenno}
152179595Sbenno
153179595Sbennostatic int
154179595Sbennopxa_gpio_intr1(void *arg)
155179595Sbenno{
156179595Sbenno	struct	pxa_gpio_softc *sc;
157179595Sbenno
158179595Sbenno	sc = (struct pxa_gpio_softc *)arg;
159179595Sbenno
160179595Sbenno	bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR0, 0x2);
161179595Sbenno	sc->pg_intr[1] |= 2;
162179595Sbenno
163179595Sbenno	return (FILTER_HANDLED);
164179595Sbenno}
165179595Sbenno
166179595Sbennostatic int
167179595Sbennopxa_gpio_intrN(void *arg)
168179595Sbenno{
169179595Sbenno	uint32_t	gedr0, gedr1, gedr2;
170179595Sbenno	struct		pxa_gpio_softc *sc;
171179595Sbenno
172179595Sbenno	sc = (struct pxa_gpio_softc *)arg;
173179595Sbenno
174179595Sbenno	gedr0 = bus_space_read_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR0);
175179595Sbenno	gedr0 &= 0xfffffffc;
176179595Sbenno	bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR0, gedr0);
177179595Sbenno
178179595Sbenno	gedr1 = bus_space_read_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR1);
179179595Sbenno	bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR1, gedr1);
180179595Sbenno
181179595Sbenno	gedr2 = bus_space_read_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR2);
182179595Sbenno	gedr2 &= 0x001fffff;
183179595Sbenno	bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR2, gedr2);
184179595Sbenno
185179595Sbenno	sc->pg_intr[0] |= gedr0;
186179595Sbenno	sc->pg_intr[1] |= gedr1;
187179595Sbenno	sc->pg_intr[2] |= gedr2;
188179595Sbenno
189179595Sbenno	return (FILTER_HANDLED);
190179595Sbenno}
191179595Sbenno
192179595Sbennostatic device_method_t pxa_gpio_methods[] = {
193179595Sbenno	DEVMETHOD(device_probe, pxa_gpio_probe),
194179595Sbenno	DEVMETHOD(device_attach, pxa_gpio_attach),
195179595Sbenno
196179595Sbenno	{0, 0}
197179595Sbenno};
198179595Sbenno
199179595Sbennostatic driver_t pxa_gpio_driver = {
200179595Sbenno	"gpio",
201179595Sbenno	pxa_gpio_methods,
202179595Sbenno	sizeof(struct pxa_gpio_softc),
203179595Sbenno};
204179595Sbenno
205179595Sbennostatic devclass_t pxa_gpio_devclass;
206179595Sbenno
207179595SbennoDRIVER_MODULE(pxagpio, pxa, pxa_gpio_driver, pxa_gpio_devclass, 0, 0);
208179595Sbenno
209179595Sbenno#define	pxagpio_reg_read(softc, reg)		\
210179595Sbenno	bus_space_read_4(sc->pg_bst, sc->pg_bsh, reg)
211179595Sbenno#define	pxagpio_reg_write(softc, reg, val)	\
212179595Sbenno	bus_space_write_4(sc->pg_bst, sc->pg_bsh, reg, val)
213179595Sbenno
214179595Sbennouint32_t
215179595Sbennopxa_gpio_get_function(int gpio)
216179595Sbenno{
217179595Sbenno	struct		pxa_gpio_softc *sc;
218179595Sbenno	uint32_t	rv, io;
219179595Sbenno
220179595Sbenno	sc = pxa_gpio_softc;
221179595Sbenno
222179595Sbenno	rv = pxagpio_reg_read(sc, GPIO_FN_REG(gpio)) >> GPIO_FN_SHIFT(gpio);
223179595Sbenno	rv = GPIO_FN(rv);
224179595Sbenno
225179595Sbenno	io = pxagpio_reg_read(sc, PXA250_GPIO_REG(GPIO_GPDR0, gpio));
226179595Sbenno	if (io & GPIO_BIT(gpio))
227179595Sbenno		rv |= GPIO_OUT;
228179595Sbenno
229179595Sbenno	io = pxagpio_reg_read(sc, PXA250_GPIO_REG(GPIO_GPLR0, gpio));
230179595Sbenno	if (io & GPIO_BIT(gpio))
231179595Sbenno		rv |= GPIO_SET;
232179595Sbenno
233179595Sbenno	return (rv);
234179595Sbenno}
235179595Sbenno
236179595Sbennouint32_t
237179595Sbennopxa_gpio_set_function(int gpio, uint32_t fn)
238179595Sbenno{
239179595Sbenno	struct		pxa_gpio_softc *sc;
240179595Sbenno	uint32_t	rv, bit, oldfn;
241179595Sbenno
242179595Sbenno	sc = pxa_gpio_softc;
243179595Sbenno
244179595Sbenno	oldfn = pxa_gpio_get_function(gpio);
245179595Sbenno
246179595Sbenno	if (GPIO_FN(fn) == GPIO_FN(oldfn) &&
247179595Sbenno	    GPIO_FN_IS_OUT(fn) == GPIO_FN_IS_OUT(oldfn)) {
248179595Sbenno		/*
249179595Sbenno		 * The pin's function is not changing.
250179595Sbenno		 * For Alternate Functions and GPIO input, we can just
251179595Sbenno		 * return now.
252179595Sbenno		 * For GPIO output pins, check the initial state is
253179595Sbenno		 * the same.
254179595Sbenno		 *
255179595Sbenno		 * Return 'fn' instead of 'oldfn' so the caller can
256179595Sbenno		 * reliably detect that we didn't change anything.
257179595Sbenno		 * (The initial state might be different for non-
258179595Sbenno		 * GPIO output pins).
259179595Sbenno		 */
260179595Sbenno		if (!GPIO_IS_GPIO_OUT(fn) ||
261179595Sbenno		    GPIO_FN_IS_SET(fn) == GPIO_FN_IS_SET(oldfn))
262179595Sbenno			return (fn);
263179595Sbenno	}
264179595Sbenno
265179595Sbenno	/*
266179595Sbenno	 * See section 4.1.3.7 of the PXA2x0 Developer's Manual for
267179595Sbenno	 * the correct procedure for changing GPIO pin functions.
268179595Sbenno	 */
269179595Sbenno
270179595Sbenno	bit = GPIO_BIT(gpio);
271179595Sbenno
272179595Sbenno	/*
273179595Sbenno	 * 1. Configure the correct set/clear state of the pin
274179595Sbenno	 */
275179595Sbenno	if (GPIO_FN_IS_SET(fn))
276179595Sbenno		pxagpio_reg_write(sc, PXA250_GPIO_REG(GPIO_GPSR0, gpio), bit);
277179595Sbenno	else
278179595Sbenno		pxagpio_reg_write(sc, PXA250_GPIO_REG(GPIO_GPCR0, gpio), bit);
279179595Sbenno
280179595Sbenno	/*
281179595Sbenno	 * 2. Configure the pin as an input or output as appropriate
282179595Sbenno	 */
283179595Sbenno	rv = pxagpio_reg_read(sc, PXA250_GPIO_REG(GPIO_GPDR0, gpio)) & ~bit;
284179595Sbenno	if (GPIO_FN_IS_OUT(fn))
285179595Sbenno		rv |= bit;
286179595Sbenno	pxagpio_reg_write(sc, PXA250_GPIO_REG(GPIO_GPDR0, gpio), rv);
287179595Sbenno
288179595Sbenno	/*
289179595Sbenno	 * 3. Configure the pin's function
290179595Sbenno	 */
291179595Sbenno	bit = GPIO_FN_MASK << GPIO_FN_SHIFT(gpio);
292179595Sbenno	fn = GPIO_FN(fn) << GPIO_FN_SHIFT(gpio);
293179595Sbenno	rv = pxagpio_reg_read(sc, GPIO_FN_REG(gpio)) & ~bit;
294179595Sbenno	pxagpio_reg_write(sc, GPIO_FN_REG(gpio), rv | fn);
295179595Sbenno
296179595Sbenno	return (oldfn);
297179595Sbenno}
298179595Sbenno
299179595Sbenno/*
300179595Sbenno * GPIO "interrupt" handling.
301179595Sbenno */
302179595Sbenno
303179595Sbennovoid
304179595Sbennopxa_gpio_mask_irq(int irq)
305179595Sbenno{
306179595Sbenno	uint32_t	val;
307179595Sbenno	struct		pxa_gpio_softc *sc;
308179595Sbenno	int		gpio;
309179595Sbenno
310179595Sbenno	sc = pxa_gpio_softc;
311179595Sbenno	gpio = IRQ_TO_GPIO(irq);
312179595Sbenno
313179595Sbenno	val = pxagpio_reg_read(sc, PXA250_GPIO_REG(GPIO_GRER0, gpio));
314179595Sbenno	val &= ~GPIO_BIT(gpio);
315179595Sbenno	pxagpio_reg_write(sc, PXA250_GPIO_REG(GPIO_GRER0, gpio), val);
316179595Sbenno}
317179595Sbenno
318179595Sbennovoid
319179595Sbennopxa_gpio_unmask_irq(int irq)
320179595Sbenno{
321179595Sbenno	uint32_t	val;
322179595Sbenno	struct		pxa_gpio_softc *sc;
323179595Sbenno	int		gpio;
324179595Sbenno
325179595Sbenno	sc = pxa_gpio_softc;
326179595Sbenno	gpio = IRQ_TO_GPIO(irq);
327179595Sbenno
328179595Sbenno	val = pxagpio_reg_read(sc, PXA250_GPIO_REG(GPIO_GRER0, gpio));
329179595Sbenno	val |= GPIO_BIT(gpio);
330179595Sbenno	pxagpio_reg_write(sc, PXA250_GPIO_REG(GPIO_GRER0, gpio), val);
331179595Sbenno}
332179595Sbenno
333179595Sbennoint
334179595Sbennopxa_gpio_get_next_irq()
335179595Sbenno{
336179595Sbenno	struct  pxa_gpio_softc *sc;
337179595Sbenno	int     gpio;
338179595Sbenno
339179595Sbenno	sc = pxa_gpio_softc;
340179595Sbenno
341179595Sbenno	if (sc->pg_intr[0] != 0) {
342179595Sbenno		gpio = ffs(sc->pg_intr[0]) - 1;
343179595Sbenno		sc->pg_intr[0] &= ~(1 << gpio);
344179595Sbenno		return (GPIO_TO_IRQ(gpio));
345179595Sbenno	}
346179595Sbenno	if (sc->pg_intr[1] != 0) {
347179595Sbenno		gpio = ffs(sc->pg_intr[1]) - 1;
348179595Sbenno		sc->pg_intr[1] &= ~(1 << gpio);
349179595Sbenno		return (GPIO_TO_IRQ(gpio + 32));
350179595Sbenno	}
351179595Sbenno	if (sc->pg_intr[2] != 0) {
352179595Sbenno		gpio = ffs(sc->pg_intr[2]) - 1;
353179595Sbenno		sc->pg_intr[2] &= ~(1 << gpio);
354179595Sbenno		return (GPIO_TO_IRQ(gpio + 64));
355179595Sbenno	}
356179595Sbenno
357179595Sbenno	return (-1);
358179595Sbenno}
359