2014-08-27 18:47:31 +02:00
|
|
|
/*
|
|
|
|
* Copyright 2009, Freie Universitaet Berlin (FUB). All rights reserved.
|
|
|
|
*
|
|
|
|
* This file is subject to the terms and conditions of the GNU Lesser
|
|
|
|
* General Public License v2.1. See the file LICENSE in the top level
|
|
|
|
* directory for more details.
|
|
|
|
*/
|
2010-09-22 15:10:42 +02:00
|
|
|
|
|
|
|
/**
|
2013-11-27 17:54:30 +01:00
|
|
|
* @ingroup lpc2387
|
2010-09-22 15:10:42 +02:00
|
|
|
* @{
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @file
|
2013-11-27 17:54:30 +01:00
|
|
|
* @brief LPC2387 GPIO Interrupt Multiplexer implementation
|
2010-09-22 15:10:42 +02:00
|
|
|
*
|
2013-11-27 17:54:30 +01:00
|
|
|
* @author Michael Baar <michael.baar@fu-berlin.de>
|
2010-09-22 15:10:42 +02:00
|
|
|
* @version $Revision: 1508 $
|
|
|
|
*
|
2013-11-27 17:54:30 +01:00
|
|
|
* @note $Id: lpc2387-gpioint.c 1508 2009-10-26 15:10:02Z baar $
|
|
|
|
* @see dev_gpioint
|
2010-09-22 15:10:42 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include "lpc2387.h"
|
|
|
|
#include "gpioint.h"
|
|
|
|
#include "cpu.h"
|
2013-12-16 17:54:58 +01:00
|
|
|
#include "irq.h"
|
2010-09-22 15:10:42 +02:00
|
|
|
|
2011-03-08 11:43:21 +01:00
|
|
|
struct irq_callback_t {
|
2013-11-27 17:54:30 +01:00
|
|
|
fp_irqcb callback;
|
2010-09-22 15:10:42 +02:00
|
|
|
};
|
|
|
|
|
2011-03-08 11:43:21 +01:00
|
|
|
static struct irq_callback_t gpioint0[32];
|
|
|
|
static struct irq_callback_t gpioint2[32];
|
2010-09-22 15:10:42 +02:00
|
|
|
|
|
|
|
|
2013-06-21 03:52:57 +02:00
|
|
|
void gpioint_init(void)
|
|
|
|
{
|
2010-09-22 15:10:42 +02:00
|
|
|
extern void GPIO_IRQHandler(void);
|
|
|
|
|
2013-06-21 03:52:57 +02:00
|
|
|
/* GPIO Init */
|
|
|
|
INTWAKE |= GPIO0WAKE | GPIO2WAKE; /* allow GPIO to wake up from power down */
|
|
|
|
install_irq(GPIO_INT, &GPIO_IRQHandler, IRQP_GPIO); /* install irq handler */
|
2010-09-22 15:10:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
bool
|
|
|
|
gpioint_set(int port, uint32_t bitmask, int flags, fp_irqcb callback)
|
|
|
|
{
|
2013-11-27 17:54:30 +01:00
|
|
|
struct irq_callback_t *cbdata;
|
2013-06-21 03:52:57 +02:00
|
|
|
unsigned long bit;
|
|
|
|
volatile unsigned long *en_f;
|
|
|
|
volatile unsigned long *en_r;
|
|
|
|
volatile unsigned long *en_clr;
|
|
|
|
|
|
|
|
/* lookup registers */
|
2014-04-10 22:28:35 +02:00
|
|
|
bit = bitarithm_msb(bitmask); /* get irq mapping table index */
|
2013-06-21 03:52:57 +02:00
|
|
|
|
|
|
|
switch(port) {
|
2013-11-27 17:54:30 +01:00
|
|
|
case 0: /* PORT0 */
|
2013-06-21 03:52:57 +02:00
|
|
|
cbdata = gpioint0;
|
|
|
|
en_f = &IO0_INT_EN_F;
|
|
|
|
en_r = &IO0_INT_EN_R;
|
|
|
|
en_clr = &IO0_INT_CLR;
|
|
|
|
break;
|
|
|
|
|
2013-11-27 17:54:30 +01:00
|
|
|
case 2: /* PORT2 */
|
2013-06-21 03:52:57 +02:00
|
|
|
cbdata = gpioint2;
|
|
|
|
en_f = &IO2_INT_EN_F;
|
|
|
|
en_r = &IO2_INT_EN_R;
|
|
|
|
en_clr = &IO2_INT_CLR;
|
|
|
|
break;
|
|
|
|
|
2013-11-27 17:54:30 +01:00
|
|
|
default: /* unsupported */
|
|
|
|
return false; /* fail */
|
2013-06-21 03:52:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* reconfigure irq */
|
|
|
|
unsigned long cpsr = disableIRQ();
|
2013-11-27 17:54:30 +01:00
|
|
|
*en_clr |= bitmask; /* clear interrupt */
|
2013-06-21 03:52:57 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if ((flags & GPIOINT_FALLING_EDGE) != 0) {
|
2013-11-27 17:54:30 +01:00
|
|
|
*en_f |= bitmask; /* enable falling edge */
|
2013-06-21 03:52:57 +02:00
|
|
|
}
|
|
|
|
else {
|
2013-11-27 17:54:30 +01:00
|
|
|
*en_f &= ~bitmask; /* disable falling edge */
|
2013-06-21 03:52:57 +02:00
|
|
|
}
|
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if ((flags & GPIOINT_RISING_EDGE) != 0) {
|
2013-11-27 17:54:30 +01:00
|
|
|
*en_r |= bitmask; /* enable rising edge */
|
2013-06-21 03:52:57 +02:00
|
|
|
}
|
|
|
|
else {
|
2013-11-27 17:54:30 +01:00
|
|
|
*en_r &= ~bitmask; /* disable rising edge */
|
2013-06-21 03:52:57 +02:00
|
|
|
}
|
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (((flags & (GPIOINT_FALLING_EDGE | GPIOINT_RISING_EDGE)) != 0)) {
|
2013-06-21 03:52:57 +02:00
|
|
|
cbdata[bit].callback = callback;
|
|
|
|
|
|
|
|
}
|
|
|
|
else {
|
2013-11-27 17:54:30 +01:00
|
|
|
cbdata[bit].callback = NULL; /* remove from interrupt mapping table */
|
2013-06-21 03:52:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
restoreIRQ(cpsr);
|
|
|
|
|
2013-11-27 17:54:30 +01:00
|
|
|
return true; /* success */
|
2010-09-22 15:10:42 +02:00
|
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
2013-06-21 03:52:57 +02:00
|
|
|
static void __attribute__((__no_instrument_function__)) test_irq(int port, unsigned long f_mask, unsigned long r_mask, struct irq_callback_t *pcb)
|
2010-09-22 15:10:42 +02:00
|
|
|
{
|
2013-11-21 14:18:54 +01:00
|
|
|
(void) port;
|
|
|
|
|
2013-06-21 03:52:57 +02:00
|
|
|
/* Test each bit of rising and falling masks, if set trigger interrupt
|
|
|
|
* on corresponding device */
|
|
|
|
do {
|
2013-06-24 22:37:35 +02:00
|
|
|
if ((pcb->callback != NULL)) {
|
|
|
|
if ((r_mask & 1) | (f_mask & 1)) {
|
2013-11-27 17:54:30 +01:00
|
|
|
pcb->callback(); /* pass to handler */
|
2013-06-21 03:52:57 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
f_mask >>= 1UL;
|
|
|
|
r_mask >>= 1UL;
|
|
|
|
pcb++;
|
|
|
|
}
|
2013-06-24 22:37:35 +02:00
|
|
|
while ((f_mask != 0) || (r_mask != 0));
|
2010-09-22 15:10:42 +02:00
|
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
void GPIO_IRQHandler(void) __attribute__((interrupt("IRQ")));
|
|
|
|
/**
|
2013-11-27 17:54:30 +01:00
|
|
|
* @brief GPIO Interrupt handler function
|
2010-09-22 15:10:42 +02:00
|
|
|
* @internal
|
|
|
|
*
|
|
|
|
* Invoked whenever an activated gpio interrupt is triggered by a rising
|
|
|
|
* or falling edge.
|
|
|
|
*/
|
2013-06-21 03:52:57 +02:00
|
|
|
void __attribute__((__no_instrument_function__)) GPIO_IRQHandler(void)
|
|
|
|
{
|
2013-11-27 17:54:30 +01:00
|
|
|
if (IO_INT_STAT & BIT0) { /* interrupt(s) on PORT0 pending */
|
|
|
|
unsigned long int_stat_f = IO0_INT_STAT_F; /* save content */
|
|
|
|
unsigned long int_stat_r = IO0_INT_STAT_R; /* save content */
|
2013-06-21 03:52:57 +02:00
|
|
|
|
2013-11-27 17:54:30 +01:00
|
|
|
IO0_INT_CLR = int_stat_f; /* clear flags of fallen pins */
|
|
|
|
IO0_INT_CLR = int_stat_r; /* clear flags of risen pins */
|
2010-09-22 15:10:42 +02:00
|
|
|
|
2013-06-21 03:52:57 +02:00
|
|
|
test_irq(0, int_stat_f, int_stat_r, gpioint0);
|
|
|
|
}
|
2010-09-22 15:10:42 +02:00
|
|
|
|
2013-11-27 17:54:30 +01:00
|
|
|
if (IO_INT_STAT & BIT2) { /* interrupt(s) on PORT2 pending */
|
|
|
|
unsigned long int_stat_f = IO2_INT_STAT_F; /* save content */
|
|
|
|
unsigned long int_stat_r = IO2_INT_STAT_R; /* save content */
|
2010-09-22 15:10:42 +02:00
|
|
|
|
2013-11-27 17:54:30 +01:00
|
|
|
IO2_INT_CLR = int_stat_f; /* clear flags of fallen pins */
|
|
|
|
IO2_INT_CLR = int_stat_r; /* clear flags of risen pins */
|
2010-09-22 15:10:42 +02:00
|
|
|
|
2013-06-21 03:52:57 +02:00
|
|
|
test_irq(2, int_stat_f, int_stat_r, gpioint2);
|
|
|
|
}
|
2010-09-22 15:10:42 +02:00
|
|
|
|
2013-11-27 17:54:30 +01:00
|
|
|
VICVectAddr = 0; /* Acknowledge Interrupt */
|
2010-09-22 15:10:42 +02:00
|
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/** @} */
|