Annotation of sys/arch/arm/sa11x0/sa11x0_gpio.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: sa11x0_gpio.c,v 1.18 2005/06/16 21:57:29 drahn Exp $ */
2: /* $NetBSD: sa11x0_gpio.c,v 1.2 2003/07/15 00:24:55 lukem Exp $ */
3:
4: /*
5: * Copyright 2003 Wasabi Systems, Inc.
6: * All rights reserved.
7: *
8: * Written by Steve C. Woodford for Wasabi Systems, Inc.
9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
18: * 3. All advertising materials mentioning features or use of this software
19: * must display the following acknowledgement:
20: * This product includes software developed for the NetBSD Project by
21: * Wasabi Systems, Inc.
22: * 4. The name of Wasabi Systems, Inc. may not be used to endorse
23: * or promote products derived from this software without specific prior
24: * written permission.
25: *
26: * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
27: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
30: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36: * POSSIBILITY OF SUCH DAMAGE.
37: */
38: /*
39: * General Purpose Input-Output found on SA11[01]0.
40: * It features 28 GPIO lines but some are used for "alternate" functions.
41: * Pins 0-10 are independent interrupt sources in SA-11x0 Interrupt Controller.
42: * Remaining lines 11-27 are OR'ed together and act like one interrupt source.
43: */
44: #include <sys/cdefs.h>
45:
46: #include <sys/param.h>
47: #include <sys/systm.h>
48: #include <sys/device.h>
49: #include <sys/malloc.h>
50: #include <sys/evcount.h>
51:
52: #include <machine/intr.h>
53: #include <machine/bus.h>
54:
55: #include <arm/cpufunc.h>
56:
57: #include <arm/sa11x0/sa11x0_reg.h>
58: #include <arm/sa11x0/sa11x0_var.h>
59:
60: #include <arm/sa11x0/sa11x0_gpioreg.h>
61: #include <arm/sa11x0/sa11x0_gpiovar.h>
62:
63: struct gpio_irq_handler {
64: // struct gpio_irq_handler *gh_next;
65: int (*gh_func)(void *);
66: void *gh_arg;
67: int gh_spl;
68: u_int gh_gpio;
69: int gh_level;
70: int gh_irq; /* intrno in an INTC */
71: struct evcount gh_count;
72: };
73:
74: struct sagpio_softc {
75: struct device sc_dev;
76:
77: bus_space_tag_t sc_bust;
78: bus_space_handle_t sc_bush;
79:
80: // void *sc_irqcookie[4];
81: // u_int32_t sc_mask[3];
82: struct gpio_irq_handler *sc_handlers[SAGPIO_NPINS];
83: int sc_minipl;
84: int sc_maxipl;
85: int sc_npins;
86: };
87:
88: int sagpio_match(struct device *, void *, void *);
89: void sagpio_attach(struct device *, struct device *, void *);
90:
91: struct cfattach sagpio_ca = {
92: sizeof (struct sagpio_softc), sagpio_match, sagpio_attach
93: };
94:
95: struct cfdriver sagpio_cd = {
96: NULL, "sagpio", DV_DULL
97: };
98:
99:
100: static struct sagpio_softc *sagpio_softc;
101: static vaddr_t sagpio_regs;
102: #define GPIO_BOOTSTRAP_REG(reg) \
103: (*((volatile u_int32_t *)(sagpio_regs + (reg))))
104:
105: void sa11x0_gpio_set_intr_level(u_int, int);
106: int sagpio_dispatch(void *arg);
107: int sagpio_irq_handler(void *arg);
108: u_int32_t sagpio_reg_read(struct sagpio_softc *sc, int reg);
109: void sagpio_reg_write(struct sagpio_softc *sc, int reg, u_int32_t val);
110:
111: uint32_t
112: sagpio_reg_read(struct sagpio_softc *sc, int reg)
113: {
114: if (sc != NULL)
115: return (bus_space_read_4(sc->sc_bust, sc->sc_bush, reg));
116: else
117: if (sagpio_regs)
118: return (GPIO_BOOTSTRAP_REG(reg));
119: panic("sagpio_reg_read: not bootstrapped");
120: }
121:
122: void
123: sagpio_reg_write(struct sagpio_softc *sc, int reg, u_int32_t val)
124: {
125: if (sc != NULL)
126: bus_space_write_4(sc->sc_bust, sc->sc_bush, reg, val);
127: else
128: if (sagpio_regs)
129: GPIO_BOOTSTRAP_REG(reg) = val;
130: else
131: panic("sagpio_reg_write: not bootstrapped");
132: return;
133: }
134:
135: int
136: sagpio_match(struct device *parent, void *cf, void *aux)
137: {
138: struct saip_attach_args *saa = aux;
139:
140: if (sagpio_softc != NULL && saa->sai_addr != SAGPIO_BASE)
141: return (0);
142:
143: saa->sai_size = SAGPIO_NPORTS;
144:
145: return (1);
146: }
147:
148: void
149: sagpio_attach(struct device *parent, struct device *self, void *aux)
150: {
151: struct sagpio_softc *sc = (struct sagpio_softc *)self;
152: struct saip_attach_args *saa = aux;
153:
154: sc->sc_bust = saa->sai_iot;
155:
156: printf(": SA-11x0 GPIO Controller\n");
157:
158: if (cputype == CPU_ID_SA1110) {
159: sc->sc_npins = SAGPIO_NPINS;
160: } else {
161: /* XXX */
162: printf("%s: Attaching to non-SA1110 cputype\n", sc->sc_dev.dv_xname);
163: return;
164: }
165:
166: if (bus_space_map(sc->sc_bust, saa->sai_addr, saa->sai_size, 0,
167: &sc->sc_bush)) {
168: /* XXX panic here? */
169: printf("%s: Can't map registers!\n", sc->sc_dev.dv_xname);
170: return;
171: }
172:
173: /* NULLify */
174: memset(sc->sc_handlers, 0, sizeof(sc->sc_handlers));
175:
176: /* disable all Rising/Falling Edge detects */
177: // sagpio_reg_write(sc, SAGPIO_RER, 0);
178: // sagpio_reg_write(sc, SAGPIO_FER, 0);
179:
180: /* clear all previous Edge Detects */
181: sagpio_reg_write(sc, SAGPIO_EDR, 0);
182:
183: /* XXX do not touch pin directions? */
184:
185: sc->sc_minipl = IPL_NONE;
186: sc->sc_maxipl = IPL_NONE;
187:
188: // sc->sc_irqcookie[0] = sc->sc_irqcookie[1] = NULL;
189:
190: sagpio_softc = sc;
191: }
192:
193: /*
194: * This is called during bootstrap to inform us SAGPIO virtual address.
195: */
196: void
197: sa11x0_gpio_bootstrap(vaddr_t gpio_regs)
198: {
199:
200: sagpio_regs = gpio_regs;
201: }
202:
203: const char *
204: sa11x0_gpio_intr_string(void *cookie)
205: {
206: static char irqstr[32];
207: struct gpio_irq_handler *gh = cookie;
208:
209: if (gh == NULL)
210: snprintf(irqstr, sizeof irqstr, "couldn't establish interrupt");
211: else
212: snprintf(irqstr, sizeof irqstr, "irq %ld", gh->gh_irq);
213: return(irqstr);
214: }
215:
216: int
217: sagpio_dispatch(void *arg)
218: {
219: struct sagpio_softc *sc = sagpio_softc;
220: uint32_t ip, ipbit;
221:
222: /* multiplexed interrupt; see what pin(s) caused it */
223: ip = sagpio_reg_read(sc, SAGPIO_EDR);
224: /* check if activity has been detected on pins[11:27] */
225: if ((ip & 0x0ffff800) == 0) {
226: printf("%s: dispatch: stray interrupt (GEDR=0x%8.x)\n", sc->sc_dev.dv_xname, ip);
227: return(1);
228: }
229: for (ipbit = GPIO_PIN(11); ipbit < GPIO_PIN(28); ipbit <<= 1)
230: if (ip & ipbit) {
231: /* clear status */
232: sa11x0_gpio_clear_intr(ipbit);
233: if (sc->sc_handlers[ipbit] != NULL)
234: /* run! */
235: sc->sc_handlers[ipbit]->gh_func(sc->sc_handlers[ipbit]->gh_arg);
236: else
237: /* edge detect occured on this pin but handler is missing */
238: printf("%s: no registered intr handler for pin %d\n", sc->sc_dev.dv_xname, ip);
239: }
240: return(0);
241: }
242:
243: int
244: sagpio_irq_handler(void *arg)
245: {
246: struct sagpio_softc *sc = sagpio_softc;
247: struct gpio_irq_handler *gih = arg;
248: uint32_t ip;
249:
250: /*
251: * All we need to do is to clear status bit and call real handler.
252: */
253: ip = sagpio_reg_read(sc, SAGPIO_EDR);
254: if ((ip & GPIO_PIN(gih->gh_gpio)) == 0) {
255: printf("%s: irq_handler: stray interrupt (GEDR=0x%8.x)\n", sc->sc_dev.dv_xname, ip);
256: return(1);
257: }
258:
259: sa11x0_gpio_clear_intr(gih->gh_gpio);
260: gih->gh_func(gih->gh_arg);
261: return(0);
262: }
263:
264: u_int
265: sa11x0_gpio_get_function(u_int gpio)
266: {
267: struct sagpio_softc *sc = sagpio_softc;
268: u_int32_t rv;
269:
270: if (sc != NULL)
271: KDASSERT(gpio < sc->sc_npins);
272:
273: rv = sagpio_reg_read(sc, SAGPIO_AFR) & GPIO_PIN(gpio);
274: /* 0 == GPIO, 1 == Alt. func. */
275:
276: return (rv);
277: }
278:
279: u_int
280: sa11x0_gpio_set_function(u_int gpio, u_int fn)
281: {
282: struct sagpio_softc *sc = sagpio_softc;
283: u_int oldfn;
284:
285: if (sc != NULL)
286: KDASSERT(gpio < sc->sc_npins);
287:
288: oldfn = sa11x0_gpio_get_function(gpio);
289: switch (fn) {
290: case SAGPIO_FUNC_GPIO:
291: sagpio_reg_write(sc, SAGPIO_AFR, oldfn & ~(GPIO_PIN(gpio)));
292: break;
293: case SAGPIO_FUNC_ALT:
294: sagpio_reg_write(sc, SAGPIO_AFR, oldfn | GPIO_PIN(gpio));
295: break;
296: default:
297: panic("%s: bogus gpio function %d\n", sc->sc_dev.dv_xname, fn);
298: /* NOTREACHED */
299: }
300: return (oldfn);
301: }
302:
303: /*
304: * Quick function to read pin value
305: */
306: int
307: sa11x0_gpio_get_bit(u_int gpio)
308: {
309: struct sagpio_softc *sc = sagpio_softc;
310: int bit;
311:
312: if (sc != NULL)
313: KDASSERT(gpio < sc->sc_npins);
314:
315: bit = sagpio_reg_read(sc, SAGPIO_PLR) & GPIO_PIN(gpio);
316:
317: if (bit == 0)
318: return(SAGPIO_LEVEL_LOW);
319: else
320: return(SAGPIO_LEVEL_HIGH);
321: }
322:
323: /*
324: * Quick function to set pin to 1
325: */
326: void
327: sa11x0_gpio_set_bit(u_int gpio)
328: {
329: struct sagpio_softc *sc = sagpio_softc;
330:
331: sagpio_reg_write(sc, SAGPIO_PSR, GPIO_PIN(gpio));
332: }
333:
334: /*
335: * Quick function to set pin to 0
336: */
337: void
338: sa11x0_gpio_clear_bit(u_int gpio)
339: {
340: struct sagpio_softc *sc = sagpio_softc;
341:
342: sagpio_reg_write(sc, SAGPIO_PCR, GPIO_PIN(gpio));
343: }
344:
345: /*
346: * Quick function to change pin direction
347: */
348: void
349: sa11x0_gpio_set_dir(u_int gpio, int dir)
350: {
351: struct sagpio_softc *sc = sagpio_softc;
352: uint32_t reg;
353:
354: reg = sagpio_reg_read(sc, SAGPIO_PDR);
355: switch (dir) {
356: case SAGPIO_DIR_INPUT:
357: reg &= ~(GPIO_PIN(gpio));
358: break;
359: case SAGPIO_DIR_OUTPUT:
360: reg |= GPIO_PIN(gpio);
361: break;
362: default:
363: panic("%s: bogus pin direction %d", sc->sc_dev.dv_xname, dir);
364: /* NOTREACHED */
365: }
366: sagpio_reg_write(sc, SAGPIO_PDR, reg);
367: }
368:
369: /*
370: * Quick function to clear interrupt status on a pin
371: * GPIO pins may be toggle in an interrupt and we dont want
372: * extra spurious interrupts to occur.
373: * Suppose this causes a slight race if a key is pressed while
374: * the interrupt handler is running. (yes this is for the keyboard driver)
375: */
376: void
377: sa11x0_gpio_clear_intr(u_int gpio)
378: {
379: struct sagpio_softc *sc = sagpio_softc;
380:
381: sagpio_reg_write(sc, SAGPIO_EDR, GPIO_PIN(gpio));
382: }
383:
384: /*
385: * Quick function to mask (disable) a GPIO interrupt
386: */
387: void
388: sa11x0_gpio_intr_mask(void *v)
389: {
390: struct gpio_irq_handler *gh = v;
391:
392: sa11x0_gpio_set_intr_level(gh->gh_gpio, IST_NONE);
393: }
394:
395: /*
396: * Quick function to unmask (enable) a GPIO interrupt
397: */
398: void
399: sa11x0_gpio_intr_unmask(void *v)
400: {
401: struct gpio_irq_handler *gh = v;
402:
403: sa11x0_gpio_set_intr_level(gh->gh_gpio, gh->gh_level);
404: }
405:
406: /*
407: * Configure the edge sensitivity of interrupt pins
408: */
409: void
410: sa11x0_gpio_set_intr_level(u_int gpio, int level)
411: {
412: struct sagpio_softc *sc = sagpio_softc;
413: u_int32_t bit;
414: u_int32_t gfer; /* falling edge */
415: u_int32_t grer; /* rising edge */
416: int s;
417:
418: s = splhigh();
419:
420: bit = GPIO_PIN(gpio);
421: gfer = sagpio_reg_read(sc, SAGPIO_FER);
422: grer = sagpio_reg_read(sc, SAGPIO_RER);
423:
424: switch (level) {
425: case IST_NONE:
426: gfer &= ~bit;
427: grer &= ~bit;
428: break;
429: case IST_EDGE_FALLING:
430: gfer |= bit;
431: grer &= ~bit;
432: break;
433: case IST_EDGE_RISING:
434: gfer &= ~bit;
435: grer |= bit;
436: break;
437: case IST_EDGE_BOTH:
438: gfer |= bit;
439: grer |= bit;
440: break;
441: default:
442: panic("%s: bad level: %d", sc->sc_dev.dv_xname, level);
443: break;
444: }
445:
446: sagpio_reg_write(sc, SAGPIO_FER, gfer);
447: sagpio_reg_write(sc, SAGPIO_RER, grer);
448:
449: splx(s);
450: }
451:
452: void *
453: sa11x0_gpio_intr_establish(u_int gpio, int level, int spl, int (*func)(void *),
454: void *arg, char *name)
455: {
456: /*
457: * Establish an interrupt with given gpio intr level.
458: * XXX We do not support multiple handlers on one pin.
459: */
460: struct sagpio_softc *sc = sagpio_softc;
461: struct gpio_irq_handler *gih;
462: void *ih;
463:
464: if (gpio > SAGPIO_NPINS - 1)
465: panic("%s: intr_establish: pin %d out of range", sc->sc_dev.dv_xname, gpio);
466:
467: MALLOC(gih, struct gpio_irq_handler *, sizeof(struct gpio_irq_handler), M_DEVBUF, M_NOWAIT);
468:
469: gih->gh_func = func;
470: gih->gh_arg = arg;
471: gih->gh_spl = spl;
472: gih->gh_level = level;
473: gih->gh_gpio = gpio;
474: gih->gh_irq = gpio < 11 ? gpio : 11;
475: evcount_attach(&gih->gh_count, name, (void *)&gih->gh_irq, &evcount_intr);
476:
477: sc->sc_handlers[gpio] = gih;
478:
479: /*
480: * SA11x0 INTC has 11 (intno 0-10) interrupts reserved for GPIO[0:10] respectively.
481: * Pins [11:27] are OR'ed together and form intno 11 in an INTC.
482: * Here we just emulate all 28 gpio interrupts (multiplexing them in 12 intnos really).
483: */
484: sa11x0_gpio_set_intr_level(gpio, level);
485:
486: if (gih->gh_irq < 11)
487: /* individual (intc irq = gpio pin), register common gpio handler */
488: ih = sa11x0_intr_establish(NULL, gih->gh_irq, 0, level, sagpio_irq_handler, gih, NULL);
489: else
490: /* multiplexed, register dispatcher */
491: ih = sa11x0_intr_establish(NULL, gih->gh_irq, 0, level, sagpio_dispatch, NULL, NULL);
492: return(ih);
493: }
494:
CVSweb