b0VIM 7.1PGa&nbrkdev.my.domain/usr/src/sys/arch/arm/sa11x0/sa11x0_gpio.c 3210#"! UtpklDad kxwtM52j^ C z /  j g $ S u * rnk7NJ32mlI&%~obRCg2"o-*' QP#int sagpio_irq_handler(void *arg);int sagpio_dispatch(void *arg);void sa11x0_gpio_set_intr_level(u_int, int); (*((volatile u_int32_t *)(sagpio_regs + (reg))))#define GPIO_BOOTSTRAP_REG(reg) \static vaddr_t sagpio_regs;static struct sagpio_softc *sagpio_softc;}; NULL, "sagpio", DV_DULLstruct cfdriver sagpio_cd = { }; sizeof (struct sagpio_softc), sagpio_match, sagpio_attachstruct cfattach sagpio_ca = {void sagpio_attach(struct device *, struct device *, void *);int sagpio_match(struct device *, void *, void *);}; int sc_npins; int sc_maxipl; int sc_minipl; struct gpio_irq_handler *sc_handlers[SAGPIO_NPINS];// u_int32_t sc_mask[3];// void *sc_irqcookie[4]; bus_space_handle_t sc_bush; bus_space_tag_t sc_bust; struct device sc_dev;struct sagpio_softc {}; struct evcount gh_count; int gh_irq; /* intrno in an INTC */ int gh_level; u_int gh_gpio; int gh_spl; void *gh_arg; int (*gh_func)(void *);// struct gpio_irq_handler *gh_next;struct gpio_irq_handler {#include #include #include #include #include #include #include #include #include #include #include #include #include */ * Remaining lines 11-27 are OR'ed together and act like one interrupt source. * Pins 0-10 are independent interrupt sources in SA-11x0 Interrupt Controller. * It features 28 GPIO lines but some are used for "alternate" functions. * General Purpose Input-Output found on SA11[01]0./* */ * POSSIBILITY OF SUCH DAMAGE. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND * * written permission. * or promote products derived from this software without specific prior * 4. The name of Wasabi Systems, Inc. may not be used to endorse * Wasabi Systems, Inc. * This product includes software developed for the NetBSD Project by * must display the following acknowledgement: * 3. All advertising materials mentioning features or use of this software * documentation and/or other materials provided with the distribution. * notice, this list of conditions and the following disclaimer in the * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer. * 1. Redistributions of source code must retain the above copyright * are met: * modification, are permitted provided that the following conditions * Redistribution and use in source and binary forms, with or without * * Written by Steve C. Woodford for Wasabi Systems, Inc. * * All rights reserved. * Copyright 2003 Wasabi Systems, Inc./*/* $NetBSD: sa11x0_gpio.c,v 1.2 2003/07/15 00:24:55 lukem Exp $ *//* $OpenBSD: sa11x0_gpio.c,v 1.18 2005/06/16 21:57:29 drahn Exp $ */adDqhSD5,"~|{t$  f G < ;  o n X D 0   q p l  | w M L 5 e } return(ih); ih = sa11x0_intr_establish(NULL, gih->gh_irq, 0, level, sagpio_dispatch, NULL, NULL); /* multiplexed, register dispatcher */ else ih = sa11x0_intr_establish(NULL, gih->gh_irq, 0, level, sagpio_irq_handler, gih, NULL); /* individual (intc irq = gpio pin), register common gpio handler */ if (gih->gh_irq < 11) sa11x0_gpio_set_intr_level(gpio, level); */ * Here we just emulate all 28 gpio interrupts (multiplexing them in 12 intnos really). * Pins [11:27] are OR'ed together and form intno 11 in an INTC. * SA11x0 INTC has 11 (intno 0-10) interrupts reserved for GPIO[0:10] respectively. /* sc->sc_handlers[gpio] = gih; evcount_attach(&gih->gh_count, name, (void *)&gih->gh_irq, &evcount_intr); gih->gh_irq = gpio < 11 ? gpio : 11; gih->gh_gpio = gpio; gih->gh_level = level; gih->gh_spl = spl; gih->gh_arg = arg; gih->gh_func = func; MALLOC(gih, struct gpio_irq_handler *, sizeof(struct gpio_irq_handler), M_DEVBUF, M_NOWAIT); panic("%s: intr_establish: pin %d out of range", sc->sc_dev.dv_xname, gpio); if (gpio > SAGPIO_NPINS - 1) void *ih; struct gpio_irq_handler *gih; struct sagpio_softc *sc = sagpio_softc; */ * XXX We do not support multiple handlers on one pin. * Establish an interrupt with given gpio intr level. /*{ void *arg, char *name)sa11x0_gpio_intr_establish(u_int gpio, int level, int spl, int (*func)(void *),void *} splx(s); sagpio_reg_write(sc, SAGPIO_RER, grer); sagpio_reg_write(sc, SAGPIO_FER, gfer); } break; panic("%s: bad level: %d", sc->sc_dev.dv_xname, level); default: break; grer |= bit; gfer |= bit; case IST_EDGE_BOTH: break; grer |= bit; gfer &= ~bit; case IST_EDGE_RISING: break; grer &= ~bit; gfer |= bit; case IST_EDGE_FALLING: break; grer &= ~bit;adp{zq?=,=;* z x w s : 8   M K  f [ O  M C @ ? 0 z y R , +   ~{3/*lkZxcb*VIF@8nlC p if ((ip & GPIO_PIN(gih->gh_gpio)) == 0) { ip = sagpio_reg_read(sc, SAGPIO_EDR); */ * All we need to do is to clear status bit and call real handler. /* uint32_t ip; struct gpio_irq_handler *gih = arg; struct sagpio_softc *sc = sagpio_softc;{sagpio_irq_handler(void *arg)int} return(0); } printf("%s: no registered intr handler for pin %d\n", sc->sc_dev.dv_xname, ip); /* edge detect occured on this pin but handler is missing */ else sc->sc_handlers[ipbit]->gh_func(sc->sc_handlers[ipbit]->gh_arg); /* run! */ if (sc->sc_handlers[ipbit] != NULL) sa11x0_gpio_clear_intr(ipbit); /* clear status */ if (ip & ipbit) { for (ipbit = GPIO_PIN(11); ipbit < GPIO_PIN(28); ipbit <<= 1) } return(1); printf("%s: dispatch: stray interrupt (GEDR=0x%8.x)\n", sc->sc_dev.dv_xname, ip); if ((ip & 0x0ffff800) == 0) { /* check if activity has been detected on pins[11:27] */ ip = sagpio_reg_read(sc, SAGPIO_EDR); /* multiplexed interrupt; see what pin(s) caused it */ uint32_t ip, ipbit; struct sagpio_softc *sc = sagpio_softc;{sagpio_dispatch(void *arg)int} return(irqstr); snprintf(irqstr, sizeof irqstr, "irq %ld", gh->gh_irq); else snprintf(irqstr, sizeof irqstr, "couldn't establish interrupt"); if (gh == NULL) struct gpio_irq_handler *gh = cookie; static char irqstr[32];{sa11x0_gpio_intr_string(void *cookie)const char *} sagpio_regs = gpio_regs;{sa11x0_gpio_bootstrap(vaddr_t gpio_regs)void */ * This is called during bootstrap to inform us SAGPIO virtual address./*} sagpio_softc = sc;// sc->sc_irqcookie[0] = sc->sc_irqcookie[1] = NULL; sc->sc_maxipl = IPL_NONE; sc->sc_minipl = IPL_NONE; /* XXX do not touch pin directions? */ sagpio_reg_write(sc, SAGPIO_EDR, 0); /* clear all previous Edge Detects */// sagpio_reg_write(sc, SAGPIO_FER, 0);// sagpio_reg_write(sc, SAGPIO_RER, 0); /* disable all Rising/Falling Edge detects */ memset(sc->sc_handlers, 0, sizeof(sc->sc_handlers)); /* NULLify */ } return; printf("%s: Can't map registers!\n", sc->sc_dev.dv_xname); /* XXX panic here? */ &sc->sc_bush)) { if (bus_space_map(sc->sc_bust, saa->sai_addr, saa->sai_size, 0, } return; printf("%s: Attaching to non-SA1110 cputype\n", sc->sc_dev.dv_xname); /* XXX */ } else { sc->sc_npins = SAGPIO_NPINS; if (cputype == CPU_ID_SA1110) { printf(": SA-11x0 GPIO Controller\n"); sc->sc_bust = saa->sai_iot; struct saip_attach_args *saa = aux; struct sagpio_softc *sc = (struct sagpio_softc *)self;{sagpio_attach(struct device *parent, struct device *self, void *aux)void} return (1); saa->sai_size = SAGPIO_NPORTS; return (0); if (sagpio_softc != NULL && saa->sai_addr != SAGPIO_BASE) struct saip_attach_args *saa = aux;{sagpio_match(struct device *parent, void *cf, void *aux)int} return; panic("sagpio_reg_write: not bootstrapped"); else GPIO_BOOTSTRAP_REG(reg) = val; if (sagpio_regs) else bus_space_write_4(sc->sc_bust, sc->sc_bush, reg, val); if (sc != NULL){sagpio_reg_write(struct sagpio_softc *sc, int reg, u_int32_t val)void} panic("sagpio_reg_read: not bootstrapped"); return (GPIO_BOOTSTRAP_REG(reg)); if (sagpio_regs) else return (bus_space_read_4(sc->sc_bust, sc->sc_bush, reg)); if (sc != NULL){sagpio_reg_read(struct sagpio_softc *sc, int reg)uint32_tvoid sagpio_reg_write(struct sagpio_softc *sc, int reg, u_int32_t val);u_int32_t sagpio_reg_read(struct sagpio_softc *sc, int reg);adqUIGF@uSRDBA;   t e L  U A > - + * &  r q 8 7 (  l k 8 6 5 1   ~ T P K " yoU;1&i-|xsPN%$ji532/rpol84/{srbaJ! gfer &= ~bit; case IST_NONE: switch (level) { grer = sagpio_reg_read(sc, SAGPIO_RER); gfer = sagpio_reg_read(sc, SAGPIO_FER); bit = GPIO_PIN(gpio); s = splhigh(); int s; u_int32_t grer; /* rising edge */ u_int32_t gfer; /* falling edge */ u_int32_t bit; struct sagpio_softc *sc = sagpio_softc;{sa11x0_gpio_set_intr_level(u_int gpio, int level)void */ * Configure the edge sensitivity of interrupt pins/*} sa11x0_gpio_set_intr_level(gh->gh_gpio, gh->gh_level); struct gpio_irq_handler *gh = v;{sa11x0_gpio_intr_unmask(void *v)void */ * Quick function to unmask (enable) a GPIO interrupt/*} sa11x0_gpio_set_intr_level(gh->gh_gpio, IST_NONE); struct gpio_irq_handler *gh = v;{sa11x0_gpio_intr_mask(void *v)void */ * Quick function to mask (disable) a GPIO interrupt/*} sagpio_reg_write(sc, SAGPIO_EDR, GPIO_PIN(gpio)); struct sagpio_softc *sc = sagpio_softc;{sa11x0_gpio_clear_intr(u_int gpio)void */ * the interrupt handler is running. (yes this is for the keyboard driver) * Suppose this causes a slight race if a key is pressed while * extra spurious interrupts to occur. * GPIO pins may be toggle in an interrupt and we dont want * Quick function to clear interrupt status on a pin/* } sagpio_reg_write(sc, SAGPIO_PDR, reg); } /* NOTREACHED */ panic("%s: bogus pin direction %d", sc->sc_dev.dv_xname, dir); default: break; reg |= GPIO_PIN(gpio); case SAGPIO_DIR_OUTPUT: break; reg &= ~(GPIO_PIN(gpio)); case SAGPIO_DIR_INPUT: switch (dir) { reg = sagpio_reg_read(sc, SAGPIO_PDR); uint32_t reg; struct sagpio_softc *sc = sagpio_softc;{sa11x0_gpio_set_dir(u_int gpio, int dir)void */ * Quick function to change pin direction/* } sagpio_reg_write(sc, SAGPIO_PCR, GPIO_PIN(gpio)); struct sagpio_softc *sc = sagpio_softc;{sa11x0_gpio_clear_bit(u_int gpio)void */ * Quick function to set pin to 0/* } sagpio_reg_write(sc, SAGPIO_PSR, GPIO_PIN(gpio)); struct sagpio_softc *sc = sagpio_softc;{sa11x0_gpio_set_bit(u_int gpio)void */ * Quick function to set pin to 1/* } return(SAGPIO_LEVEL_HIGH); else return(SAGPIO_LEVEL_LOW); if (bit == 0) bit = sagpio_reg_read(sc, SAGPIO_PLR) & GPIO_PIN(gpio); KDASSERT(gpio < sc->sc_npins); if (sc != NULL) int bit; struct sagpio_softc *sc = sagpio_softc;{sa11x0_gpio_get_bit(u_int gpio)int */ * Quick function to read pin value/* } return (oldfn); } /* NOTREACHED */ panic("%s: bogus gpio function %d\n", sc->sc_dev.dv_xname, fn); default: break; sagpio_reg_write(sc, SAGPIO_AFR, oldfn | GPIO_PIN(gpio)); case SAGPIO_FUNC_ALT: break; sagpio_reg_write(sc, SAGPIO_AFR, oldfn & ~(GPIO_PIN(gpio))); case SAGPIO_FUNC_GPIO: switch (fn) { oldfn = sa11x0_gpio_get_function(gpio); KDASSERT(gpio < sc->sc_npins); if (sc != NULL) u_int oldfn; struct sagpio_softc *sc = sagpio_softc;{sa11x0_gpio_set_function(u_int gpio, u_int fn)u_int} return (rv); /* 0 == GPIO, 1 == Alt. func. */ rv = sagpio_reg_read(sc, SAGPIO_AFR) & GPIO_PIN(gpio); KDASSERT(gpio < sc->sc_npins); if (sc != NULL) u_int32_t rv; struct sagpio_softc *sc = sagpio_softc;{sa11x0_gpio_get_function(u_int gpio)u_int} return(0); gih->gh_func(gih->gh_arg); sa11x0_gpio_clear_intr(gih->gh_gpio); } return(1); printf("%s: irq_handler: stray interrupt (GEDR=0x%8.x)\n", sc->sc_dev.dv_xname, ip);