1 /*-
2 * Copyright (c) 2006 Benno Rice. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 */
24
25 #include <sys/cdefs.h>
26 __FBSDID("$FreeBSD: releng/10.0/sys/arm/xscale/pxa/pxa_gpio.c 179595 2008-06-06 05:08:09Z benno $");
27
28 #include <sys/param.h>
29 #include <sys/systm.h>
30 #include <sys/bus.h>
31 #include <sys/kernel.h>
32 #include <sys/lock.h>
33 #include <sys/interrupt.h>
34 #include <sys/module.h>
35 #include <sys/malloc.h>
36 #include <sys/mutex.h>
37 #include <sys/rman.h>
38 #include <sys/queue.h>
39 #include <sys/taskqueue.h>
40 #include <sys/timetc.h>
41 #include <machine/bus.h>
42 #include <machine/intr.h>
43
44 #include <arm/xscale/pxa/pxavar.h>
45 #include <arm/xscale/pxa/pxareg.h>
46
47 struct pxa_gpio_softc {
48 struct resource * pg_res[4];
49 bus_space_tag_t pg_bst;
50 bus_space_handle_t pg_bsh;
51 struct mtx pg_mtx;
52
53 uint32_t pg_intr[3];
54 };
55
56 static struct resource_spec pxa_gpio_spec[] = {
57 { SYS_RES_MEMORY, 0, RF_ACTIVE },
58 { SYS_RES_IRQ, 0, RF_ACTIVE },
59 { SYS_RES_IRQ, 1, RF_ACTIVE },
60 { SYS_RES_IRQ, 2, RF_ACTIVE },
61 { -1, 0 }
62 };
63
64 static struct pxa_gpio_softc *pxa_gpio_softc = NULL;
65
66 static int pxa_gpio_probe(device_t);
67 static int pxa_gpio_attach(device_t);
68
69 static driver_filter_t pxa_gpio_intr0;
70 static driver_filter_t pxa_gpio_intr1;
71 static driver_filter_t pxa_gpio_intrN;
72
73 static int
74 pxa_gpio_probe(device_t dev)
75 {
76
77 device_set_desc(dev, "GPIO Controller");
78 return (0);
79 }
80
81 static int
82 pxa_gpio_attach(device_t dev)
83 {
84 int error;
85 void *ihl;
86 struct pxa_gpio_softc *sc;
87
88 sc = (struct pxa_gpio_softc *)device_get_softc(dev);
89
90 if (pxa_gpio_softc != NULL)
91 return (ENXIO);
92 pxa_gpio_softc = sc;
93
94 error = bus_alloc_resources(dev, pxa_gpio_spec, sc->pg_res);
95 if (error) {
96 device_printf(dev, "could not allocate resources\n");
97 return (ENXIO);
98 }
99
100 sc->pg_bst = rman_get_bustag(sc->pg_res[0]);
101 sc->pg_bsh = rman_get_bushandle(sc->pg_res[0]);
102
103 /* Disable and clear all interrupts. */
104 bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GRER0, 0);
105 bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GRER1, 0);
106 bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GRER2, 0);
107 bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GFER0, 0);
108 bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GFER1, 0);
109 bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GFER2, 0);
110 bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR0, ~0);
111 bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR1, ~0);
112 bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR2, ~0);
113
114 mtx_init(&sc->pg_mtx, "GPIO mutex", NULL, MTX_SPIN);
115
116 if (bus_setup_intr(dev, sc->pg_res[1], INTR_TYPE_MISC|INTR_MPSAFE,
117 pxa_gpio_intr0, NULL, sc, &ihl) != 0) {
118 bus_release_resources(dev, pxa_gpio_spec, sc->pg_res);
119 device_printf(dev, "could not set up intr0\n");
120 return (ENXIO);
121 }
122
123 if (bus_setup_intr(dev, sc->pg_res[2], INTR_TYPE_MISC|INTR_MPSAFE,
124 pxa_gpio_intr1, NULL, sc, &ihl) != 0) {
125 bus_release_resources(dev, pxa_gpio_spec, sc->pg_res);
126 device_printf(dev, "could not set up intr1\n");
127 return (ENXIO);
128 }
129
130 if (bus_setup_intr(dev, sc->pg_res[3], INTR_TYPE_MISC|INTR_MPSAFE,
131 pxa_gpio_intrN, NULL, sc, &ihl) != 0) {
132 bus_release_resources(dev, pxa_gpio_spec, sc->pg_res);
133 device_printf(dev, "could not set up intrN\n");
134 return (ENXIO);
135 }
136
137 return (0);
138 }
139
140 static int
141 pxa_gpio_intr0(void *arg)
142 {
143 struct pxa_gpio_softc *sc;
144
145 sc = (struct pxa_gpio_softc *)arg;
146
147 bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR0, 0x1);
148 sc->pg_intr[0] |= 1;
149
150 return (FILTER_HANDLED);
151 }
152
153 static int
154 pxa_gpio_intr1(void *arg)
155 {
156 struct pxa_gpio_softc *sc;
157
158 sc = (struct pxa_gpio_softc *)arg;
159
160 bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR0, 0x2);
161 sc->pg_intr[1] |= 2;
162
163 return (FILTER_HANDLED);
164 }
165
166 static int
167 pxa_gpio_intrN(void *arg)
168 {
169 uint32_t gedr0, gedr1, gedr2;
170 struct pxa_gpio_softc *sc;
171
172 sc = (struct pxa_gpio_softc *)arg;
173
174 gedr0 = bus_space_read_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR0);
175 gedr0 &= 0xfffffffc;
176 bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR0, gedr0);
177
178 gedr1 = bus_space_read_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR1);
179 bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR1, gedr1);
180
181 gedr2 = bus_space_read_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR2);
182 gedr2 &= 0x001fffff;
183 bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR2, gedr2);
184
185 sc->pg_intr[0] |= gedr0;
186 sc->pg_intr[1] |= gedr1;
187 sc->pg_intr[2] |= gedr2;
188
189 return (FILTER_HANDLED);
190 }
191
192 static device_method_t pxa_gpio_methods[] = {
193 DEVMETHOD(device_probe, pxa_gpio_probe),
194 DEVMETHOD(device_attach, pxa_gpio_attach),
195
196 {0, 0}
197 };
198
199 static driver_t pxa_gpio_driver = {
200 "gpio",
201 pxa_gpio_methods,
202 sizeof(struct pxa_gpio_softc),
203 };
204
205 static devclass_t pxa_gpio_devclass;
206
207 DRIVER_MODULE(pxagpio, pxa, pxa_gpio_driver, pxa_gpio_devclass, 0, 0);
208
209 #define pxagpio_reg_read(softc, reg) \
210 bus_space_read_4(sc->pg_bst, sc->pg_bsh, reg)
211 #define pxagpio_reg_write(softc, reg, val) \
212 bus_space_write_4(sc->pg_bst, sc->pg_bsh, reg, val)
213
214 uint32_t
215 pxa_gpio_get_function(int gpio)
216 {
217 struct pxa_gpio_softc *sc;
218 uint32_t rv, io;
219
220 sc = pxa_gpio_softc;
221
222 rv = pxagpio_reg_read(sc, GPIO_FN_REG(gpio)) >> GPIO_FN_SHIFT(gpio);
223 rv = GPIO_FN(rv);
224
225 io = pxagpio_reg_read(sc, PXA250_GPIO_REG(GPIO_GPDR0, gpio));
226 if (io & GPIO_BIT(gpio))
227 rv |= GPIO_OUT;
228
229 io = pxagpio_reg_read(sc, PXA250_GPIO_REG(GPIO_GPLR0, gpio));
230 if (io & GPIO_BIT(gpio))
231 rv |= GPIO_SET;
232
233 return (rv);
234 }
235
236 uint32_t
237 pxa_gpio_set_function(int gpio, uint32_t fn)
238 {
239 struct pxa_gpio_softc *sc;
240 uint32_t rv, bit, oldfn;
241
242 sc = pxa_gpio_softc;
243
244 oldfn = pxa_gpio_get_function(gpio);
245
246 if (GPIO_FN(fn) == GPIO_FN(oldfn) &&
247 GPIO_FN_IS_OUT(fn) == GPIO_FN_IS_OUT(oldfn)) {
248 /*
249 * The pin's function is not changing.
250 * For Alternate Functions and GPIO input, we can just
251 * return now.
252 * For GPIO output pins, check the initial state is
253 * the same.
254 *
255 * Return 'fn' instead of 'oldfn' so the caller can
256 * reliably detect that we didn't change anything.
257 * (The initial state might be different for non-
258 * GPIO output pins).
259 */
260 if (!GPIO_IS_GPIO_OUT(fn) ||
261 GPIO_FN_IS_SET(fn) == GPIO_FN_IS_SET(oldfn))
262 return (fn);
263 }
264
265 /*
266 * See section 4.1.3.7 of the PXA2x0 Developer's Manual for
267 * the correct procedure for changing GPIO pin functions.
268 */
269
270 bit = GPIO_BIT(gpio);
271
272 /*
273 * 1. Configure the correct set/clear state of the pin
274 */
275 if (GPIO_FN_IS_SET(fn))
276 pxagpio_reg_write(sc, PXA250_GPIO_REG(GPIO_GPSR0, gpio), bit);
277 else
278 pxagpio_reg_write(sc, PXA250_GPIO_REG(GPIO_GPCR0, gpio), bit);
279
280 /*
281 * 2. Configure the pin as an input or output as appropriate
282 */
283 rv = pxagpio_reg_read(sc, PXA250_GPIO_REG(GPIO_GPDR0, gpio)) & ~bit;
284 if (GPIO_FN_IS_OUT(fn))
285 rv |= bit;
286 pxagpio_reg_write(sc, PXA250_GPIO_REG(GPIO_GPDR0, gpio), rv);
287
288 /*
289 * 3. Configure the pin's function
290 */
291 bit = GPIO_FN_MASK << GPIO_FN_SHIFT(gpio);
292 fn = GPIO_FN(fn) << GPIO_FN_SHIFT(gpio);
293 rv = pxagpio_reg_read(sc, GPIO_FN_REG(gpio)) & ~bit;
294 pxagpio_reg_write(sc, GPIO_FN_REG(gpio), rv | fn);
295
296 return (oldfn);
297 }
298
299 /*
300 * GPIO "interrupt" handling.
301 */
302
303 void
304 pxa_gpio_mask_irq(int irq)
305 {
306 uint32_t val;
307 struct pxa_gpio_softc *sc;
308 int gpio;
309
310 sc = pxa_gpio_softc;
311 gpio = IRQ_TO_GPIO(irq);
312
313 val = pxagpio_reg_read(sc, PXA250_GPIO_REG(GPIO_GRER0, gpio));
314 val &= ~GPIO_BIT(gpio);
315 pxagpio_reg_write(sc, PXA250_GPIO_REG(GPIO_GRER0, gpio), val);
316 }
317
318 void
319 pxa_gpio_unmask_irq(int irq)
320 {
321 uint32_t val;
322 struct pxa_gpio_softc *sc;
323 int gpio;
324
325 sc = pxa_gpio_softc;
326 gpio = IRQ_TO_GPIO(irq);
327
328 val = pxagpio_reg_read(sc, PXA250_GPIO_REG(GPIO_GRER0, gpio));
329 val |= GPIO_BIT(gpio);
330 pxagpio_reg_write(sc, PXA250_GPIO_REG(GPIO_GRER0, gpio), val);
331 }
332
333 int
334 pxa_gpio_get_next_irq()
335 {
336 struct pxa_gpio_softc *sc;
337 int gpio;
338
339 sc = pxa_gpio_softc;
340
341 if (sc->pg_intr[0] != 0) {
342 gpio = ffs(sc->pg_intr[0]) - 1;
343 sc->pg_intr[0] &= ~(1 << gpio);
344 return (GPIO_TO_IRQ(gpio));
345 }
346 if (sc->pg_intr[1] != 0) {
347 gpio = ffs(sc->pg_intr[1]) - 1;
348 sc->pg_intr[1] &= ~(1 << gpio);
349 return (GPIO_TO_IRQ(gpio + 32));
350 }
351 if (sc->pg_intr[2] != 0) {
352 gpio = ffs(sc->pg_intr[2]) - 1;
353 sc->pg_intr[2] &= ~(1 << gpio);
354 return (GPIO_TO_IRQ(gpio + 64));
355 }
356
357 return (-1);
358 }
Cache object: a755ac0338a34d549985804d769d1503
|