/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id$ * * Copyright (c) 2008 by Michael Sevakis * * IMX31 GPIO event manager * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ****************************************************************************/ #include "config.h" #include "system.h" #include "avic-imx31.h" #include "gpio-imx31.h" /* UIE vector found in avic-imx31.c */ extern void UIE_VECTOR(void); /* Event lists are allocated for the specific target */ #if (GPIO_EVENT_MASK & USE_GPIO1_EVENTS) static __attribute__((interrupt("IRQ"))) void GPIO1_HANDLER(void); extern const struct gpio_event_list gpio1_event_list; #endif #if (GPIO_EVENT_MASK & USE_GPIO2_EVENTS) static __attribute__((interrupt("IRQ"))) void GPIO2_HANDLER(void); extern const struct gpio_event_list gpio2_event_list; #endif #if (GPIO_EVENT_MASK & USE_GPIO3_EVENTS) static __attribute__((interrupt("IRQ"))) void GPIO3_HANDLER(void); extern const struct gpio_event_list gpio3_event_list; #endif static struct gpio_module_descriptor { struct gpio_map * const base; /* Module base address */ enum IMX31_INT_LIST ints; /* AVIC int number */ void (*handler)(void); /* Interrupt function */ const struct gpio_event_list *list; /* Event handler list */ } gpio_descs[GPIO_NUM_GPIO] = { #if (GPIO_EVENT_MASK & USE_GPIO1_EVENTS) { .base = (struct gpio_map *)GPIO1_BASE_ADDR, .ints = INT_GPIO1, .handler = GPIO1_HANDLER, }, #endif #if (GPIO_EVENT_MASK & USE_GPIO2_EVENTS) { .base = (struct gpio_map *)GPIO2_BASE_ADDR, .ints = INT_GPIO2, .handler = GPIO2_HANDLER, }, #endif #if (GPIO_EVENT_MASK & USE_GPIO3_EVENTS) { .base = (struct gpio_map *)GPIO3_BASE_ADDR, .ints = INT_GPIO3, .handler = GPIO3_HANDLER, }, #endif }; static void gpio_call_events(const struct gpio_module_descriptor * const desc) { const struct gpio_event_list * const list = desc->list; struct gpio_map * const base = desc->base; const struct gpio_event * event, *event_last; /* Intersect pending and unmasked bits */ uint32_t pnd = base->isr & base->imr; event = list->events; event_last = event + list->count; /* Call each event handler in order */ /* .count is surely expected to be > 0 */ do { uint32_t mask = event->mask; if (pnd & mask) { event->callback(); pnd &= ~mask; } if (pnd == 0) break; /* Teminate early if nothing more to service */ } while (++event < event_last); if (pnd != 0) { /* One or more weren't handled */ UIE_VECTOR(); } } #if (GPIO_EVENT_MASK & USE_GPIO1_EVENTS) static __attribute__((interrupt("IRQ"))) void GPIO1_HANDLER(void) { gpio_call_events(&gpio_descs[GPIO1_NUM]); } #endif #if (GPIO_EVENT_MASK & USE_GPIO2_EVENTS) static __attribute__((interrupt("IRQ"))) void GPIO2_HANDLER(void) { gpio_call_events(&gpio_descs[GPIO2_NUM]); } #endif #if (GPIO_EVENT_MASK & USE_GPIO3_EVENTS) static __attribute__((interrupt("IRQ"))) void GPIO3_HANDLER(void) { gpio_call_events(&gpio_descs[GPIO3_NUM]); } #endif void gpio_init(void) { /* Mask-out GPIO interrupts - enable what's wanted later */ GPIO1_IMR = 0; GPIO2_IMR = 0; GPIO3_IMR = 0; /* Init the externally-defined event lists for each port */ #if (GPIO_EVENT_MASK & USE_GPIO1_EVENTS) gpio_descs[GPIO1_NUM].list = &gpio1_event_list; #endif #if (GPIO_EVENT_MASK & USE_GPIO2_EVENTS) gpio_descs[GPIO2_NUM].list = &gpio2_event_list; #endif #if (GPIO_EVENT_MASK & USE_GPIO3_EVENTS) gpio_descs[GPIO3_NUM].list = &gpio3_event_list; #endif } bool gpio_enable_event(enum gpio_event_ids id) { const struct gpio_module_descriptor * const desc = &gpio_descs[id >> 5]; const struct gpio_event * const event = &desc->list->events[id & 31]; struct gpio_map * const base = desc->base; volatile uint32_t *icr; uint32_t mask, line; uint32_t imr; int shift; int oldlevel = disable_irq_save(); imr = base->imr; if (imr == 0) { /* First enabled interrupt for this GPIO */ avic_enable_int(desc->ints, INT_TYPE_IRQ, desc->list->ints_priority, desc->handler); } /* Set the line sense */ line = find_first_set_bit(event->mask); icr = &base->icr[line >> 4]; shift = (line & 15) << 1; mask = GPIO_SENSE_CONFIG_MASK << shift; *icr = (*icr & ~mask) | ((event->sense << shift) & mask); /* Unmask the line */ base->imr = imr | event->mask; restore_irq(oldlevel); return true; } void gpio_disable_event(enum gpio_event_ids id) { const struct gpio_module_descriptor * const desc = &gpio_descs[id >> 5]; const struct gpio_event * const event = &desc->list->events[id & 31]; struct gpio_map * const base = desc->base; uint32_t imr; int oldlevel = disable_irq_save(); /* Remove bit from mask */ imr = base->imr & ~event->mask; /* Mask the line */ base->imr = imr; if (imr == 0) { /* No events remain enabled */ avic_disable_int(desc->ints); } restore_irq(oldlevel); }