summaryrefslogtreecommitdiff
path: root/nuttx/arch/avr/src/at91uc3/at91uc3_gpioirq.c
diff options
context:
space:
mode:
Diffstat (limited to 'nuttx/arch/avr/src/at91uc3/at91uc3_gpioirq.c')
-rw-r--r--nuttx/arch/avr/src/at91uc3/at91uc3_gpioirq.c428
1 files changed, 428 insertions, 0 deletions
diff --git a/nuttx/arch/avr/src/at91uc3/at91uc3_gpioirq.c b/nuttx/arch/avr/src/at91uc3/at91uc3_gpioirq.c
new file mode 100644
index 000000000..0a74225ec
--- /dev/null
+++ b/nuttx/arch/avr/src/at91uc3/at91uc3_gpioirq.c
@@ -0,0 +1,428 @@
+/****************************************************************************
+ * arch/avr/src/at91uc3/at91uc3_gpioirq.c
+ * arch/avr/src/chip/at91uc3_gpioirq.c
+ *
+ * Copyright (C) 2010 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include "at91uc3_config.h"
+
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <arch/irq.h>
+
+#include "up_arch.h"
+#include "os_internal.h"
+#include "irq_internal.h"
+#include "at91uc3_internal.h"
+#include "at91uc3_gpio.h"
+
+#ifdef CONFIG_AVR32_GPIOIRQ
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* A table of handlers for each GPIO interrupt */
+
+static FAR xcpt_t g_gpiohandler[NR_GPIO_IRQS];
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: gpio_baseaddress
+ *
+ * Input:
+ * irq - A IRQ number in the range of 0 to NR_GPIO_IRQS.
+ *
+ * Description:
+ * Given a IRQ number, return the base address of the associated GPIO
+ * registers.
+ *
+ ****************************************************************************/
+
+static inline uint32_t gpio_baseaddress(unsigned int irq)
+{
+#if CONFIG_AVR32_GPIOIRQSETA != 0
+ if (irq < __IRQ_GPIO_PB0)
+ {
+ return AVR32_GPIO0_BASE;
+ }
+ else
+#endif
+#if CONFIG_AVR32_GPIOIRQSETB != 0
+ if (irq < NR_GPIO_IRQS)
+ {
+ return AVR32_GPIO1_BASE;
+ }
+ else
+#endif
+ {
+ return 0;
+ }
+}
+
+/****************************************************************************
+ * Name: gpio_pin
+ *
+ * Input:
+ * irq - A IRQ number in the range of 0 to NR_GPIO_IRQS.
+ *
+ * Description:
+ * Given a GPIO number, return the pin number in the range of 0-31 on the
+ * corresponding port
+ *
+ ****************************************************************************/
+
+static inline int gpio_pin(unsigned int irq)
+{
+ uint32_t pinset;
+ int pinirq;
+ int pin;
+
+#if CONFIG_AVR32_GPIOIRQSETA != 0
+ if (irq < __IRQ_GPIO_PB0)
+ {
+ pinset = CONFIG_AVR32_GPIOIRQSETA;
+ pinirq = __IRQ_GPIO_PA0;
+ }
+ else
+#endif
+#if CONFIG_AVR32_GPIOIRQSETB != 0
+ if (irq < NR_GPIO_IRQS)
+ {
+ pinset = CONFIG_AVR32_GPIOIRQSETB;
+ pinirq = __IRQ_GPIO_PB0;
+ }
+ else
+#endif
+ {
+ return -EINVAL;
+ }
+
+ /* Now we have to search for the pin with matching IRQ. Yech! We made
+ * life difficult here by choosing a sparse representation of IRQs on
+ * GPIO pins.
+ */
+
+ for (pin = 0; pin < 32 && pinset != 0; pin++)
+ {
+ /* Is this pin at bit 0 configured for interrupt support? */
+
+ if ((pinset & 1) != 0)
+ {
+ /* Is it the on IRQ we are looking for? */
+
+ if (pinirq == irq)
+ {
+ /* Yes, return the associated pin number */
+
+ return pin;
+ }
+
+ /* No.. Increment the IRQ number for the next configured pin */
+
+ pinirq++;
+ }
+
+ /* Shift the next pin to position bit 0 */
+
+ pinset >>= 1;
+ }
+
+ return -EINVAL;
+}
+
+/****************************************************************************
+ * Name: gpio_porthandler
+ *
+ * Description:
+ * Dispatch GPIO interrupts on a specific GPIO port
+ *
+ ****************************************************************************/
+
+static void gpio_porthandler(uint32_t regbase, int irqbase, uint32_t irqset, void *context)
+{
+ uint32_t ifr;
+ int irq;
+ int pin;
+
+ /* Check each bit and dispatch each pending interrupt in the interrupt flag
+ * register for this port.
+ */
+
+ ifr = getreg32(regbase + AVR32_GPIO_IFR_OFFSET);
+
+ /* Dispatch each pending interrupt */
+
+ irq = irqbase;
+ for (pin = 0; pin < 32 && ifr != 0; pin++)
+ {
+ /* Is this pin configured for interrupt support? */
+
+ uint32_t bit = (1 << pin);
+ if ((irqset & bit) != 0)
+ {
+ /* Is an interrupt pending on this pin? */
+
+ if ((ifr & bit) != 0)
+ {
+ /* Yes.. Clear the pending interrupt */
+
+ putreg32(bit, regbase + AVR32_GPIO_IFRC_OFFSET);
+ ifr &= ~bit;
+
+ /* Dispatch handling for this pin */
+
+ xcpt_t handler = g_gpiohandler[irq];
+ if (handler)
+ {
+ handler(irq, context);
+ }
+ else
+ {
+ lldbg("No handler: pin=%d ifr=%08x irqset=%08x",
+ pin, ifr, irqset);
+ }
+ }
+
+ /* Increment the IRQ number on all configured pins */
+
+ irq++;
+ }
+
+ /* Not configured. An interrupt on this pin would be an error. */
+
+ else if ((ifr & bit) != 0)
+ {
+ /* Clear the pending interrupt */
+
+ putreg32(bit, regbase + AVR32_GPIO_IFRC_OFFSET);
+ ifr &= ~bit;
+
+ lldbg("IRQ on unconfigured pin: pin=%d ifr=%08x irqset=%08x",
+ pin, ifr, irqset);
+ }
+ }
+}
+
+/****************************************************************************
+ * Name: gpio0/1_interrupt
+ *
+ * Description:
+ * Handle GPIO0/1 interrupts
+ *
+ ****************************************************************************/
+
+#if CONFIG_AVR32_GPIOIRQSETA != 0
+static int gpio0_interrupt(int irq, FAR void *context)
+{
+ gpio_porthandler(AVR32_GPIO0_BASE, __IRQ_GPIO_PA0,
+ CONFIG_AVR32_GPIOIRQSETA, context);
+ return 0;
+}
+#endif
+
+#if CONFIG_AVR32_GPIOIRQSETB != 0
+static int gpio1_interrupt(int irq, FAR void *context)
+{
+ gpio_porthandler(AVR32_GPIO1_BASE, __IRQ_GPIO_PB0,
+ CONFIG_AVR32_GPIOIRQSETB, context);
+
+ return 0;
+}
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: gpio_irqinitialize
+ *
+ * Description:
+ * Initialize all vectors to the unexpected interrupt handler.
+ *
+ * Assumptions:
+ * Called during the early boot sequence before global interrupts have
+ * been enabled.
+ *
+ ****************************************************************************/
+
+void gpio_irqinitialize(void)
+{
+ int i;
+
+ /* Point all interrupt vectors to the unexpected interrupt */
+
+ for (i = 0; i < NR_GPIO_IRQS; i++)
+ {
+ g_gpiohandler[i] = irq_unexpected_isr;
+ }
+
+ /* Then attach the GPIO interrupt handlers */
+
+#if CONFIG_AVR32_GPIOIRQSETA != 0
+ irq_attach(AVR32_IRQ_GPIO0, gpio0_interrupt);
+#endif
+#if CONFIG_AVR32_GPIOIRQSETB != 0
+ irq_attach(AVR32_IRQ_GPIO1, gpio1_interrupt);
+#endif
+}
+
+/****************************************************************************
+ * Name: gpio_irqattach
+ *
+ * Description:
+ * Attach in GPIO interrupt to the provide 'isr'
+ *
+ ****************************************************************************/
+
+int gpio_irqattach(int irq, xcpt_t newisr, xcpt_t *oldisr)
+{
+ irqstate_t flags;
+ int ret = -EINVAL;
+
+ if ((unsigned)irq < NR_GPIO_IRQS)
+ {
+ /* If the new ISR is NULL, then the ISR is being detached. In this
+ * case, disable the ISR and direct any interrupts
+ * to the unexpected interrupt handler.
+ */
+
+ flags = irqsave();
+ if (newisr == NULL)
+ {
+ gpio_irqdisable(irq);
+ newisr = irq_unexpected_isr;
+ }
+
+ /* Return the old ISR (in case the caller ever wants to restore it) */
+
+ if (oldisr)
+ {
+ *oldisr = g_gpiohandler[irq];
+ }
+
+ /* Then save the new ISR in the table. */
+
+ g_gpiohandler[irq] = newisr;
+ irqrestore(flags);
+ ret = OK;
+ }
+ return ret;
+}
+
+/****************************************************************************
+ * Name: gpio_irqenable
+ *
+ * Description:
+ * Enable the GPIO IRQ specified by 'irq'
+ *
+ ****************************************************************************/
+
+void gpio_irqenable(int irq)
+{
+ uint32_t base;
+ int pin;
+
+ if ((unsigned)irq < NR_GPIO_IRQS)
+ {
+ /* Get the base address of the GPIO module associated with this IRQ */
+
+ base = gpio_baseaddress(irq);
+
+ /* Get the pin number associated with this IRQ. We made life difficult
+ * here by choosing a sparse representation of IRQs on GPIO pins.
+ */
+
+ pin = gpio_pin(irq);
+ DEBUGASSERT(pin >= 0);
+
+ /* Enable the GPIO interrupt. */
+
+ putreg32((1 << pin), base + AVR32_GPIO_IERS_OFFSET);
+ }
+}
+
+/****************************************************************************
+ * Name: gpio_irqdisable
+ *
+ * Description:
+ * Disable the GPIO IRQ specified by 'irq'
+ *
+ ****************************************************************************/
+
+void gpio_irqdisable(int irq)
+{
+ uint32_t base;
+ int pin;
+
+ if ((unsigned)irq < NR_GPIO_IRQS)
+ {
+ /* Get the base address of the GPIO module associated with this IRQ */
+
+ base = gpio_baseaddress(irq);
+
+ /* Get the pin number associated with this IRQ. We made life difficult
+ * here by choosing a sparse representation of IRQs on GPIO pins.
+ */
+
+ pin = gpio_pin(irq);
+ DEBUGASSERT(pin >= 0);
+
+ /* Disable the GPIO interrupt. */
+
+ putreg32((1 << pin), base + AVR32_GPIO_IERC_OFFSET);
+ }
+}
+
+#endif /* CONFIG_AVR32_GPIOIRQ */