Annotation of sys/arch/arm/xscale/pxa2x0_gpio.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: pxa2x0_gpio.c,v 1.18 2005/06/16 21:57:29 drahn Exp $ */
! 2: /* $NetBSD: pxa2x0_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: #include <sys/cdefs.h>
! 40: /*
! 41: __KERNEL_RCSID(0, "$NetBSD: pxa2x0_gpio.c,v 1.2 2003/07/15 00:24:55 lukem Exp $");
! 42: */
! 43:
! 44: #include <sys/param.h>
! 45: #include <sys/systm.h>
! 46: #include <sys/device.h>
! 47: #include <sys/malloc.h>
! 48: #include <sys/evcount.h>
! 49:
! 50: #include <machine/intr.h>
! 51: #include <machine/bus.h>
! 52:
! 53: #include <arm/cpufunc.h>
! 54:
! 55: #include <arm/xscale/pxa2x0reg.h>
! 56: #include <arm/xscale/pxa2x0var.h>
! 57: #include <arm/xscale/pxa2x0_gpio.h>
! 58:
! 59: struct gpio_irq_handler {
! 60: struct gpio_irq_handler *gh_next;
! 61: int (*gh_func)(void *);
! 62: void *gh_arg;
! 63: int gh_spl;
! 64: u_int gh_gpio;
! 65: int gh_level;
! 66: int gh_irq;
! 67: struct evcount gh_count;
! 68: };
! 69:
! 70: struct pxagpio_softc {
! 71: struct device sc_dev;
! 72: bus_space_tag_t sc_bust;
! 73: bus_space_handle_t sc_bush;
! 74: void *sc_irqcookie[4];
! 75: u_int32_t sc_mask[3];
! 76: #ifdef PXAGPIO_HAS_GPION_INTRS
! 77: struct gpio_irq_handler *sc_handlers[GPIO_NPINS];
! 78: int sc_minipl;
! 79: int sc_maxipl;
! 80: #else
! 81: struct gpio_irq_handler *sc_handlers[2];
! 82: #endif
! 83: int npins;
! 84: int pxa27x_pins;
! 85: };
! 86:
! 87: int pxagpio_match(struct device *, void *, void *);
! 88: void pxagpio_attach(struct device *, struct device *, void *);
! 89:
! 90: #ifdef __NetBSD__
! 91: CFATTACH_DECL(pxagpio, sizeof(struct pxagpio_softc),
! 92: pxagpio_match, pxagpio_attach, NULL, NULL);
! 93: #else
! 94: struct cfattach pxagpio_ca = {
! 95: sizeof (struct pxagpio_softc), pxagpio_match, pxagpio_attach
! 96: };
! 97:
! 98: struct cfdriver pxagpio_cd = {
! 99: NULL, "pxagpio", DV_DULL
! 100: };
! 101:
! 102: #endif
! 103:
! 104: static struct pxagpio_softc *pxagpio_softc;
! 105: static vaddr_t pxagpio_regs;
! 106: #define GPIO_BOOTSTRAP_REG(reg) \
! 107: (*((volatile u_int32_t *)(pxagpio_regs + (reg))))
! 108:
! 109: void pxa2x0_gpio_set_intr_level(u_int, int);
! 110: int pxagpio_intr0(void *);
! 111: int pxagpio_intr1(void *);
! 112: #ifdef PXAGPIO_HAS_GPION_INTRS
! 113: int pxagpio_dispatch(struct pxagpio_softc *, int);
! 114: int pxagpio_intrN(void *);
! 115: int pxagpio_intrlow(void *);
! 116: void pxa2x0_gpio_intr_fixup(int minipl, int maxipl);
! 117: #endif
! 118: u_int32_t pxagpio_reg_read(struct pxagpio_softc *sc, int reg);
! 119: void pxagpio_reg_write(struct pxagpio_softc *sc, int reg, u_int32_t val);
! 120:
! 121: u_int32_t
! 122: pxagpio_reg_read(struct pxagpio_softc *sc, int reg)
! 123: {
! 124: if (__predict_true(sc != NULL))
! 125: return (bus_space_read_4(sc->sc_bust, sc->sc_bush, reg));
! 126: else
! 127: if (pxagpio_regs)
! 128: return (GPIO_BOOTSTRAP_REG(reg));
! 129: panic("pxagpio_reg_read: not bootstrapped");
! 130: }
! 131:
! 132: void
! 133: pxagpio_reg_write(struct pxagpio_softc *sc, int reg, u_int32_t val)
! 134: {
! 135: if (__predict_true(sc != NULL))
! 136: bus_space_write_4(sc->sc_bust, sc->sc_bush, reg, val);
! 137: else
! 138: if (pxagpio_regs)
! 139: GPIO_BOOTSTRAP_REG(reg) = val;
! 140: else
! 141: panic("pxagpio_reg_write: not bootstrapped");
! 142: return;
! 143: }
! 144:
! 145: int
! 146: pxagpio_match(struct device *parent, void *cf, void *aux)
! 147: {
! 148: struct pxaip_attach_args *pxa = aux;
! 149:
! 150: if (pxagpio_softc != NULL || pxa->pxa_addr != PXA2X0_GPIO_BASE)
! 151: return (0);
! 152:
! 153: pxa->pxa_size = PXA2X0_GPIO_SIZE;
! 154:
! 155: return (1);
! 156: }
! 157:
! 158: void
! 159: pxagpio_attach(struct device *parent, struct device *self, void *aux)
! 160: {
! 161: struct pxagpio_softc *sc = (struct pxagpio_softc *)self;
! 162: struct pxaip_attach_args *pxa = aux;
! 163:
! 164: sc->sc_bust = pxa->pxa_iot;
! 165:
! 166: printf(": GPIO Controller\n");
! 167:
! 168: if ((cputype & ~CPU_ID_XSCALE_COREREV_MASK) == CPU_ID_PXA27X) {
! 169: sc->npins = GPIO_NPINS;
! 170: sc->pxa27x_pins = 1;
! 171: } else {
! 172: sc->npins = GPIO_NPINS_25x;
! 173: sc->pxa27x_pins = 0;
! 174: }
! 175:
! 176: if (bus_space_map(sc->sc_bust, pxa->pxa_addr, pxa->pxa_size, 0,
! 177: &sc->sc_bush)) {
! 178: printf("%s: Can't map registers!\n", sc->sc_dev.dv_xname);
! 179: return;
! 180: }
! 181:
! 182: memset(sc->sc_handlers, 0, sizeof(sc->sc_handlers));
! 183:
! 184: /*
! 185: * Disable all GPIO interrupts
! 186: */
! 187: pxagpio_reg_write(sc, GPIO_GRER0, 0);
! 188: pxagpio_reg_write(sc, GPIO_GRER1, 0);
! 189: pxagpio_reg_write(sc, GPIO_GRER2, 0);
! 190: pxagpio_reg_write(sc, GPIO_GRER3, 0);
! 191: pxagpio_reg_write(sc, GPIO_GFER0, 0);
! 192: pxagpio_reg_write(sc, GPIO_GFER1, 0);
! 193: pxagpio_reg_write(sc, GPIO_GFER2, 0);
! 194: pxagpio_reg_write(sc, GPIO_GFER3, 0);
! 195: pxagpio_reg_write(sc, GPIO_GEDR0, ~0);
! 196: pxagpio_reg_write(sc, GPIO_GEDR1, ~0);
! 197: pxagpio_reg_write(sc, GPIO_GEDR2, ~0);
! 198: pxagpio_reg_write(sc, GPIO_GEDR3, ~0);
! 199:
! 200: #ifdef PXAGPIO_HAS_GPION_INTRS
! 201: sc->sc_minipl = IPL_NONE;
! 202: sc->sc_maxipl = IPL_NONE;
! 203: #endif
! 204:
! 205: sc->sc_irqcookie[0] = sc->sc_irqcookie[1] = NULL;
! 206:
! 207: pxagpio_softc = sc;
! 208: }
! 209:
! 210: void
! 211: pxa2x0_gpio_bootstrap(vaddr_t gpio_regs)
! 212: {
! 213:
! 214: pxagpio_regs = gpio_regs;
! 215: }
! 216:
! 217: void *
! 218: pxa2x0_gpio_intr_establish(u_int gpio, int level, int spl, int (*func)(void *),
! 219: void *arg, char *name)
! 220: {
! 221: struct pxagpio_softc *sc = pxagpio_softc;
! 222: struct gpio_irq_handler *gh;
! 223: u_int32_t bit;
! 224:
! 225: #ifdef DEBUG
! 226: #ifdef PXAGPIO_HAS_GPION_INTRS
! 227: if (gpio >= sc->npins)
! 228: panic("pxa2x0_gpio_intr_establish: bad pin number: %d", gpio);
! 229: #else
! 230: if (gpio > 1)
! 231: panic("pxa2x0_gpio_intr_establish: bad pin number: %d", gpio);
! 232: #endif
! 233: #endif
! 234:
! 235: if (GPIO_FN_IS_OUT(pxa2x0_gpio_get_function(gpio)) != GPIO_IN)
! 236: panic("pxa2x0_gpio_intr_establish: Pin %d not GPIO_IN", gpio);
! 237:
! 238: MALLOC(gh, struct gpio_irq_handler *, sizeof(struct gpio_irq_handler),
! 239: M_DEVBUF, M_NOWAIT);
! 240:
! 241: gh->gh_func = func;
! 242: gh->gh_arg = arg;
! 243: gh->gh_spl = spl;
! 244: gh->gh_gpio = gpio;
! 245: gh->gh_irq = gpio+32;
! 246: gh->gh_level = level;
! 247: evcount_attach(&gh->gh_count, name, (void *)&gh->gh_irq, &evcount_intr);
! 248:
! 249: gh->gh_next = sc->sc_handlers[gpio];
! 250: sc->sc_handlers[gpio] = gh;
! 251:
! 252: if (gpio == 0) {
! 253: KDASSERT(sc->sc_irqcookie[0] == NULL);
! 254: sc->sc_irqcookie[0] = pxa2x0_intr_establish(PXA2X0_INT_GPIO0,
! 255: spl, pxagpio_intr0, sc, NULL);
! 256: KDASSERT(sc->sc_irqcookie[0]);
! 257: } else if (gpio == 1) {
! 258: KDASSERT(sc->sc_irqcookie[1] == NULL);
! 259: sc->sc_irqcookie[1] = pxa2x0_intr_establish(PXA2X0_INT_GPIO1,
! 260: spl, pxagpio_intr1, sc, NULL);
! 261: KDASSERT(sc->sc_irqcookie[1]);
! 262: } else {
! 263: #ifdef PXAGPIO_HAS_GPION_INTRS
! 264: int minipl, maxipl;
! 265:
! 266: if (sc->sc_maxipl == IPL_NONE || spl > sc->sc_maxipl) {
! 267: maxipl = spl;
! 268: } else {
! 269: maxipl = sc->sc_maxipl;
! 270: }
! 271:
! 272:
! 273: if (sc->sc_minipl == IPL_NONE || spl < sc->sc_minipl) {
! 274: minipl = spl;
! 275: } else {
! 276: minipl = sc->sc_minipl;
! 277: }
! 278: pxa2x0_gpio_intr_fixup(minipl, maxipl);
! 279: #endif
! 280: }
! 281:
! 282: bit = GPIO_BIT(gpio);
! 283: sc->sc_mask[GPIO_BANK(gpio)] |= bit;
! 284:
! 285: pxa2x0_gpio_set_intr_level(gpio, gh->gh_level);
! 286:
! 287: return (gh);
! 288: }
! 289:
! 290: void
! 291: pxa2x0_gpio_intr_disestablish(void *cookie)
! 292: {
! 293: struct pxagpio_softc *sc = pxagpio_softc;
! 294: struct gpio_irq_handler *gh = cookie;
! 295: u_int32_t bit, reg;
! 296:
! 297: evcount_detach(&gh->gh_count);
! 298:
! 299: bit = GPIO_BIT(gh->gh_gpio);
! 300:
! 301: reg = pxagpio_reg_read(sc, GPIO_REG(GPIO_GFER0, gh->gh_gpio));
! 302: reg &= ~bit;
! 303: pxagpio_reg_write(sc, GPIO_REG(GPIO_GFER0, gh->gh_gpio), reg);
! 304: reg = pxagpio_reg_read(sc, GPIO_REG(GPIO_GRER0, gh->gh_gpio));
! 305: reg &= ~bit;
! 306: pxagpio_reg_write(sc, GPIO_REG(GPIO_GRER0, gh->gh_gpio), reg);
! 307:
! 308: pxagpio_reg_write(sc, GPIO_REG(GPIO_GEDR0, gh->gh_gpio), bit);
! 309:
! 310: sc->sc_mask[GPIO_BANK(gh->gh_gpio)] &= ~bit;
! 311: sc->sc_handlers[gh->gh_gpio] = NULL;
! 312:
! 313: if (gh->gh_gpio == 0) {
! 314: pxa2x0_intr_disestablish(sc->sc_irqcookie[0]);
! 315: sc->sc_irqcookie[0] = NULL;
! 316: } else if (gh->gh_gpio == 1) {
! 317: pxa2x0_intr_disestablish(sc->sc_irqcookie[1]);
! 318: sc->sc_irqcookie[1] = NULL;
! 319: } else {
! 320: #ifdef PXAGPIO_HAS_GPION_INTRS
! 321: int i, minipl, maxipl, ipl;
! 322: minipl = IPL_HIGH;
! 323: maxipl = IPL_NONE;
! 324: for (i = 2; i < sc->npins; i++) {
! 325: if (sc->sc_handlers[i] != NULL) {
! 326: ipl = sc->sc_handlers[i]->gh_spl;
! 327: if (minipl > ipl)
! 328: minipl = ipl;
! 329:
! 330: if (maxipl < ipl)
! 331: maxipl = ipl;
! 332: }
! 333: }
! 334: pxa2x0_gpio_intr_fixup(minipl, maxipl);
! 335: #endif /* PXAGPIO_HAS_GPION_INTRS */
! 336: }
! 337:
! 338: FREE(gh, M_DEVBUF);
! 339: }
! 340:
! 341: #ifdef PXAGPIO_HAS_GPION_INTRS
! 342: void
! 343: pxa2x0_gpio_intr_fixup(int minipl, int maxipl)
! 344: {
! 345: struct pxagpio_softc *sc = pxagpio_softc;
! 346: int save = disable_interrupts(I32_bit);
! 347:
! 348: if (maxipl == IPL_NONE && minipl == IPL_HIGH) {
! 349: /* no remaining interrupts */
! 350: if (sc->sc_irqcookie[2])
! 351: pxa2x0_intr_disestablish(sc->sc_irqcookie[2]);
! 352: sc->sc_irqcookie[2] = NULL;
! 353: if (sc->sc_irqcookie[3])
! 354: pxa2x0_intr_disestablish(sc->sc_irqcookie[3]);
! 355: sc->sc_irqcookie[3] = NULL;
! 356: sc->sc_minipl = IPL_NONE;
! 357: sc->sc_maxipl = IPL_NONE;
! 358: restore_interrupts(save);
! 359: return;
! 360: }
! 361:
! 362: if (sc->sc_maxipl == IPL_NONE || maxipl > sc->sc_maxipl) {
! 363: if (sc->sc_irqcookie[2])
! 364: pxa2x0_intr_disestablish(sc->sc_irqcookie[2]);
! 365:
! 366: sc->sc_maxipl = maxipl;
! 367: sc->sc_irqcookie[2] =
! 368: pxa2x0_intr_establish(PXA2X0_INT_GPION,
! 369: maxipl, pxagpio_intrN, sc, NULL);
! 370:
! 371: if (sc->sc_irqcookie[2] == NULL) {
! 372: printf("%s: failed to hook main "
! 373: "GPIO interrupt\n",
! 374: sc->sc_dev.dv_xname);
! 375: /* XXX - panic? */
! 376: }
! 377: }
! 378: if (sc->sc_minipl == IPL_NONE || minipl < sc->sc_minipl) {
! 379: if (sc->sc_irqcookie[3])
! 380: pxa2x0_intr_disestablish(sc->sc_irqcookie[3]);
! 381:
! 382: sc->sc_minipl = minipl;
! 383: sc->sc_irqcookie[3] =
! 384: pxa2x0_intr_establish(PXA2X0_INT_GPION,
! 385: sc->sc_minipl, pxagpio_intrlow, sc, NULL);
! 386:
! 387: if (sc->sc_irqcookie[3] == NULL) {
! 388: printf("%s: failed to hook main "
! 389: "GPIO interrupt\n",
! 390: sc->sc_dev.dv_xname);
! 391: /* XXX - panic? */
! 392: }
! 393: }
! 394: restore_interrupts(save);
! 395: }
! 396: #endif /* PXAGPIO_HAS_GPION_INTRS */
! 397:
! 398: const char *
! 399: pxa2x0_gpio_intr_string(void *cookie)
! 400: {
! 401: static char irqstr[32];
! 402: struct gpio_irq_handler *gh = cookie;
! 403:
! 404: if (gh == NULL)
! 405: snprintf(irqstr, sizeof irqstr, "couldn't establish interrupt");
! 406: else
! 407: snprintf(irqstr, sizeof irqstr, "irq %ld", gh->gh_irq);
! 408: return(irqstr);
! 409: }
! 410:
! 411:
! 412: int
! 413: pxagpio_intr0(void *arg)
! 414: {
! 415: struct pxagpio_softc *sc = arg;
! 416: int ret;
! 417:
! 418: #ifdef DIAGNOSTIC
! 419: if (sc->sc_handlers[0] == NULL) {
! 420: printf("%s: stray GPIO#0 edge interrupt\n",
! 421: sc->sc_dev.dv_xname);
! 422: return (0);
! 423: }
! 424: #endif
! 425:
! 426: bus_space_write_4(sc->sc_bust, sc->sc_bush, GPIO_REG(GPIO_GEDR0, 0),
! 427: GPIO_BIT(0));
! 428:
! 429: ret = (sc->sc_handlers[0]->gh_func)(sc->sc_handlers[0]->gh_arg);
! 430: if (ret != 0)
! 431: sc->sc_handlers[0]->gh_count.ec_count++;
! 432: return ret;
! 433: }
! 434:
! 435: int
! 436: pxagpio_intr1(void *arg)
! 437: {
! 438: struct pxagpio_softc *sc = arg;
! 439: int ret;
! 440:
! 441: #ifdef DIAGNOSTIC
! 442: if (sc->sc_handlers[1] == NULL) {
! 443: printf("%s: stray GPIO#1 edge interrupt\n",
! 444: sc->sc_dev.dv_xname);
! 445: return (0);
! 446: }
! 447: #endif
! 448:
! 449: bus_space_write_4(sc->sc_bust, sc->sc_bush, GPIO_REG(GPIO_GEDR0, 1),
! 450: GPIO_BIT(1));
! 451:
! 452: ret = (sc->sc_handlers[1]->gh_func)(sc->sc_handlers[1]->gh_arg);
! 453: if (ret != 0)
! 454: sc->sc_handlers[1]->gh_count.ec_count++;
! 455: return ret;
! 456: }
! 457:
! 458: #ifdef PXAGPIO_HAS_GPION_INTRS
! 459: int
! 460: pxagpio_dispatch(struct pxagpio_softc *sc, int gpio_base)
! 461: {
! 462: struct gpio_irq_handler **ghp, *gh;
! 463: int i, s, nhandled, handled, pins;
! 464: u_int32_t gedr, mask;
! 465: int bank;
! 466:
! 467: /* Fetch bitmap of pending interrupts on this GPIO bank */
! 468: gedr = pxagpio_reg_read(sc, GPIO_REG(GPIO_GEDR0, gpio_base));
! 469:
! 470: /* Don't handle GPIO 0/1 here */
! 471: if (gpio_base == 0)
! 472: gedr &= ~(GPIO_BIT(0) | GPIO_BIT(1));
! 473:
! 474: /* Bail early if there are no pending interrupts in this bank */
! 475: if (gedr == 0)
! 476: return (0);
! 477:
! 478: /* Acknowledge pending interrupts. */
! 479: pxagpio_reg_write(sc, GPIO_REG(GPIO_GEDR0, gpio_base), gedr);
! 480:
! 481: bank = GPIO_BANK(gpio_base);
! 482:
! 483: /*
! 484: * We're only interested in those for which we have a handler
! 485: * registered
! 486: */
! 487: #ifdef DEBUG
! 488: if ((gedr & sc->sc_mask[bank]) == 0) {
! 489: printf("%s: stray GPIO interrupt. Bank %d, GEDR 0x%08x, mask 0x%08x\n",
! 490: sc->sc_dev.dv_xname, bank, gedr, sc->sc_mask[bank]);
! 491: return (1); /* XXX: Pretend we dealt with it */
! 492: }
! 493: #endif
! 494:
! 495: gedr &= sc->sc_mask[bank];
! 496: ghp = &sc->sc_handlers[gpio_base];
! 497: if (sc->pxa27x_pins == 1)
! 498: pins = (gpio_base < 96) ? 32 : 25;
! 499: else
! 500: pins = (gpio_base < 64) ? 32 : 17;
! 501: handled = 0;
! 502:
! 503: for (i = 0, mask = 1; i < pins && gedr; i++, ghp++, mask <<= 1) {
! 504: if ((gedr & mask) == 0)
! 505: continue;
! 506: gedr &= ~mask;
! 507:
! 508: if ((gh = *ghp) == NULL) {
! 509: printf("%s: unhandled GPIO interrupt. GPIO#%d\n",
! 510: sc->sc_dev.dv_xname, gpio_base + i);
! 511: continue;
! 512: }
! 513:
! 514: s = _splraise(gh->gh_spl);
! 515: do {
! 516: nhandled = (gh->gh_func)(gh->gh_arg);
! 517: if (nhandled != 0)
! 518: gh->gh_count.ec_count++;
! 519: handled |= nhandled;
! 520: gh = gh->gh_next;
! 521: } while (gh != NULL);
! 522: splx(s);
! 523: }
! 524:
! 525: return (handled);
! 526: }
! 527:
! 528: int
! 529: pxagpio_intrN(void *arg)
! 530: {
! 531: struct pxagpio_softc *sc = arg;
! 532: int handled;
! 533:
! 534: handled = pxagpio_dispatch(sc, 0);
! 535: handled |= pxagpio_dispatch(sc, 32);
! 536: handled |= pxagpio_dispatch(sc, 64);
! 537: handled |= pxagpio_dispatch(sc, 96);
! 538:
! 539: return (handled);
! 540: }
! 541:
! 542: int
! 543: pxagpio_intrlow(void *arg)
! 544: {
! 545: /* dummy */
! 546: return 0;
! 547: }
! 548: #endif /* PXAGPIO_HAS_GPION_INTRS */
! 549:
! 550: u_int
! 551: pxa2x0_gpio_get_function(u_int gpio)
! 552: {
! 553: struct pxagpio_softc *sc = pxagpio_softc;
! 554: u_int32_t rv, io;
! 555:
! 556: if (__predict_true(sc != NULL))
! 557: KDASSERT(gpio < sc->npins);
! 558:
! 559: rv = pxagpio_reg_read(sc, GPIO_FN_REG(gpio)) >> GPIO_FN_SHIFT(gpio);
! 560: rv = GPIO_FN(rv);
! 561:
! 562: io = pxagpio_reg_read(sc, GPIO_REG(GPIO_GPDR0, gpio));
! 563: if (io & GPIO_BIT(gpio))
! 564: rv |= GPIO_OUT;
! 565:
! 566: io = pxagpio_reg_read(sc, GPIO_REG(GPIO_GPLR0, gpio));
! 567: if (io & GPIO_BIT(gpio))
! 568: rv |= GPIO_SET;
! 569:
! 570: return (rv);
! 571: }
! 572:
! 573: u_int
! 574: pxa2x0_gpio_set_function(u_int gpio, u_int fn)
! 575: {
! 576: struct pxagpio_softc *sc = pxagpio_softc;
! 577: u_int32_t rv, bit;
! 578: u_int oldfn;
! 579:
! 580: if (__predict_true(sc != NULL))
! 581: KDASSERT(gpio < sc->npins);
! 582:
! 583: oldfn = pxa2x0_gpio_get_function(gpio);
! 584:
! 585: if (GPIO_FN(fn) == GPIO_FN(oldfn) &&
! 586: GPIO_FN_IS_OUT(fn) == GPIO_FN_IS_OUT(oldfn)) {
! 587: /*
! 588: * The pin's function is not changing.
! 589: * For Alternate Functions and GPIO input, we can just
! 590: * return now.
! 591: * For GPIO output pins, check the initial state is
! 592: * the same.
! 593: *
! 594: * Return 'fn' instead of 'oldfn' so the caller can
! 595: * reliably detect that we didn't change anything.
! 596: * (The initial state might be different for non-
! 597: * GPIO output pins).
! 598: */
! 599: if (!GPIO_IS_GPIO_OUT(fn) ||
! 600: GPIO_FN_IS_SET(fn) == GPIO_FN_IS_SET(oldfn))
! 601: return (fn);
! 602: }
! 603:
! 604: /*
! 605: * See section 4.1.3.7 of the PXA2x0 Developer's Manual for
! 606: * the correct procedure for changing GPIO pin functions.
! 607: */
! 608:
! 609: bit = GPIO_BIT(gpio);
! 610:
! 611: /*
! 612: * 1. Configure the correct set/clear state of the pin
! 613: */
! 614: if (GPIO_FN_IS_SET(fn))
! 615: pxagpio_reg_write(sc, GPIO_REG(GPIO_GPSR0, gpio), bit);
! 616: else
! 617: pxagpio_reg_write(sc, GPIO_REG(GPIO_GPCR0, gpio), bit);
! 618:
! 619: /*
! 620: * 2. Configure the pin as an input or output as appropriate
! 621: */
! 622: rv = pxagpio_reg_read(sc, GPIO_REG(GPIO_GPDR0, gpio)) & ~bit;
! 623: if (GPIO_FN_IS_OUT(fn))
! 624: rv |= bit;
! 625: pxagpio_reg_write(sc, GPIO_REG(GPIO_GPDR0, gpio), rv);
! 626:
! 627: /*
! 628: * 3. Configure the pin's function
! 629: */
! 630: bit = GPIO_FN_MASK << GPIO_FN_SHIFT(gpio);
! 631: fn = GPIO_FN(fn) << GPIO_FN_SHIFT(gpio);
! 632: rv = pxagpio_reg_read(sc, GPIO_FN_REG(gpio)) & ~bit;
! 633: pxagpio_reg_write(sc, GPIO_FN_REG(gpio), rv | fn);
! 634:
! 635: return (oldfn);
! 636: }
! 637:
! 638: /*
! 639: * Quick function to read pin value
! 640: */
! 641: int
! 642: pxa2x0_gpio_get_bit(u_int gpio)
! 643: {
! 644: struct pxagpio_softc *sc = pxagpio_softc;
! 645: int bit;
! 646:
! 647: bit = GPIO_BIT(gpio);
! 648: if (pxagpio_reg_read(sc, GPIO_REG(GPIO_GPLR0, gpio)) & bit)
! 649: return 1;
! 650: else
! 651: return 0;
! 652: }
! 653:
! 654: /*
! 655: * Quick function to set pin to 1
! 656: */
! 657: void
! 658: pxa2x0_gpio_set_bit(u_int gpio)
! 659: {
! 660: struct pxagpio_softc *sc = pxagpio_softc;
! 661: int bit;
! 662:
! 663: bit = GPIO_BIT(gpio);
! 664: pxagpio_reg_write(sc, GPIO_REG(GPIO_GPSR0, gpio), bit);
! 665: }
! 666:
! 667: /*
! 668: * Quick function to set pin to 0
! 669: */
! 670: void
! 671: pxa2x0_gpio_clear_bit(u_int gpio)
! 672: {
! 673: struct pxagpio_softc *sc = pxagpio_softc;
! 674: int bit;
! 675:
! 676: bit = GPIO_BIT(gpio);
! 677: pxagpio_reg_write(sc, GPIO_REG(GPIO_GPCR0, gpio), bit);
! 678: }
! 679:
! 680: /*
! 681: * Quick function to change pin direction
! 682: */
! 683: void
! 684: pxa2x0_gpio_set_dir(u_int gpio, int dir)
! 685: {
! 686: struct pxagpio_softc *sc = pxagpio_softc;
! 687: int bit;
! 688: u_int32_t reg;
! 689:
! 690: bit = GPIO_BIT(gpio);
! 691:
! 692: reg = pxagpio_reg_read(sc, GPIO_REG(GPIO_GPDR0, gpio)) & ~bit;
! 693: if (GPIO_FN_IS_OUT(dir))
! 694: reg |= bit;
! 695: pxagpio_reg_write(sc, GPIO_REG(GPIO_GPDR0, gpio), reg);
! 696: }
! 697:
! 698: /*
! 699: * Quick function to clear interrupt status on a pin
! 700: * GPIO pins may be toggle in an interrupt and we dont want
! 701: * extra spurious interrupts to occur.
! 702: * Suppose this causes a slight race if a key is pressed while
! 703: * the interrupt handler is running. (yes this is for the keyboard driver)
! 704: */
! 705: void
! 706: pxa2x0_gpio_clear_intr(u_int gpio)
! 707: {
! 708: struct pxagpio_softc *sc = pxagpio_softc;
! 709: int bit;
! 710:
! 711: bit = GPIO_BIT(gpio);
! 712: pxagpio_reg_write(sc, GPIO_REG(GPIO_GEDR0, gpio), bit);
! 713: }
! 714:
! 715: /*
! 716: * Quick function to mask (disable) a GPIO interrupt
! 717: */
! 718: void
! 719: pxa2x0_gpio_intr_mask(void *v)
! 720: {
! 721: struct gpio_irq_handler *gh = v;
! 722:
! 723: pxa2x0_gpio_set_intr_level(gh->gh_gpio, IPL_NONE);
! 724: }
! 725:
! 726: /*
! 727: * Quick function to unmask (enable) a GPIO interrupt
! 728: */
! 729: void
! 730: pxa2x0_gpio_intr_unmask(void *v)
! 731: {
! 732: struct gpio_irq_handler *gh = v;
! 733:
! 734: pxa2x0_gpio_set_intr_level(gh->gh_gpio, gh->gh_level);
! 735: }
! 736:
! 737: /*
! 738: * Configure the edge sensitivity of interrupt pins
! 739: */
! 740: void
! 741: pxa2x0_gpio_set_intr_level(u_int gpio, int level)
! 742: {
! 743: struct pxagpio_softc *sc = pxagpio_softc;
! 744: u_int32_t bit;
! 745: u_int32_t gfer;
! 746: u_int32_t grer;
! 747: int s;
! 748:
! 749: s = splhigh();
! 750:
! 751: bit = GPIO_BIT(gpio);
! 752: gfer = pxagpio_reg_read(sc, GPIO_REG(GPIO_GFER0, gpio));
! 753: grer = pxagpio_reg_read(sc, GPIO_REG(GPIO_GRER0, gpio));
! 754:
! 755: switch (level) {
! 756: case IST_NONE:
! 757: gfer &= ~bit;
! 758: grer &= ~bit;
! 759: break;
! 760: case IST_EDGE_FALLING:
! 761: gfer |= bit;
! 762: grer &= ~bit;
! 763: break;
! 764: case IST_EDGE_RISING:
! 765: gfer &= ~bit;
! 766: grer |= bit;
! 767: break;
! 768: case IST_EDGE_BOTH:
! 769: gfer |= bit;
! 770: grer |= bit;
! 771: break;
! 772: default:
! 773: panic("pxa2x0_gpio_set_intr_level: bad level: %d", level);
! 774: break;
! 775: }
! 776:
! 777: pxagpio_reg_write(sc, GPIO_REG(GPIO_GFER0, gpio), gfer);
! 778: pxagpio_reg_write(sc, GPIO_REG(GPIO_GRER0, gpio), grer);
! 779:
! 780: splx(s);
! 781: }
CVSweb