From 80119920218c06dbaa3da922e438f1e438c2ab48 Mon Sep 17 00:00:00 2001
From: Matthew Else <matthewelse1997@gmail.com>
Date: Tue, 23 Jul 2013 14:19:33 +0100
Subject: [PATCH] Fully implemented gpio_irq_set

---
 .../TARGET_NXP/TARGET_LPC11XX/gpio_irq_api.c  | 122 ++++++++++--------
 .../hal/TARGET_NXP/TARGET_LPC11XX/objects.h   |   2 +
 2 files changed, 69 insertions(+), 55 deletions(-)

diff --git a/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC11XX/gpio_irq_api.c b/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC11XX/gpio_irq_api.c
index 9782f78793..509606dd0e 100644
--- a/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC11XX/gpio_irq_api.c
+++ b/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC11XX/gpio_irq_api.c
@@ -23,34 +23,16 @@
 
 static uint32_t channel_ids[CHANNEL_NUM] = {0};
 static gpio_irq_handler irq_handler;
-static int gpioIrqInitialised = 0;
+static uint32_t channel = 0;
 
 #warning (matthewelse) This code isn't working yet, so don't rely on it, or try to use it.
 
 static inline void handle_interrupt_in(uint32_t channel) {
 
 #error (matthewelse) There's no way this code will work now...
-    
     uint32_t ch_bit = (1 << channel);
-
-    LPC_GPIO_TypeDef *port_reg = ((LPC_GPIO_TypeDef *) LPC_GPIO0_BASE + (channel * 0x10000));
-
-    // Return immediately if:
-    //   * The interrupt was already served
-    //   * There is no user handler
-    //   * It is a level interrupt, not an edge interrupt
-    if ( ((&port_reg->IST & ch_bit) == 0) ||
-         (channel_ids[channel] == 0     ) ||
-         (&port_reg->ISEL & ch_bit      ) ) return;
-
-    if ((&port_reg->IENR & ch_bit) && (&port_reg->RISE & ch_bit)) {
-        irq_handler(channel_ids[channel], IRQ_RISE);
-        &port_reg->RISE = ch_bit;
-    }
-    if ((&port_reg->IENF & ch_bit) && (&port_reg->FALL & ch_bit)) {
-        irq_handler(channel_ids[channel], IRQ_FALL);
-    }
-    &port_reg->IST = ch_bit;
+    LPC_GPIO_TypeDef *port_reg = ((LPC_GPIO_TypeDef *) (LPC_GPIO0_BASE + (channel * 0x10000)));
+    
 }
 
 void gpio_irq0(void) {handle_interrupt_in(0);}
@@ -60,63 +42,93 @@ void gpio_irq3(void) {handle_interrupt_in(3);}
 
 int gpio_irq_init(gpio_irq_t *obj, PinName pin, gpio_irq_handler handler, uint32_t id) {
     if (pin == NC) return -1;
-    if (gpioInitialised) return;
     
+    channel_ids[channel] = id;
     irq_handler = handler;
 
-    /* Enable AHB clock to the GPIO domain. */
-    LPC_SYSCON->SYSAHBCLKCTRL |= SCB_SYSAHBCLKCTRL_GPIO;
+    //obj->pin = pin;
+    obj->ch = channel;
     
     NVIC_EnableIRQ(EINT0_IRQn);
     NVIC_EnableIRQ(EINT1_IRQn);
     NVIC_EnableIRQ(EINT2_IRQn);
     NVIC_EnableIRQ(EINT3_IRQn);
     
-    gpioInitialised = 1;
+    channel++;
     return 0;
 }
 
 void gpio_irq_free(gpio_irq_t *obj) {
     channel_ids[obj->ch] = 0;
-    LPC_SYSCON->STARTERP0 &= ~(1 << obj->ch);
 }
 
 // This is basically complete, but non-functional as it needs to do something with obj at some point.
 void gpio_irq_set(gpio_irq_t *obj, gpio_irq_event event, uint32_t enable) {
-    if (!gpioIqrInitialised) gpio_irq_init();
+    // TODO: Debug this to find out what data is put in the obj object at runtime...
 
-#warning (matthewelse) TODO: undefined port and value. Also need to do something with the *obj...
-    int port = 0;
-    int pin = 0;
+    LPC_GPIO_TypeDef *gpioReg;
 
-    LPC_GPIO_TypeDef *gpioRegisters;
-
-    switch (port) {
-        case 0:
-            gpioRegisters = LPC_GPIO0;
+    // Firstly, clear the interrupts for this pin.
+    // Then, let the registers know whether we're looking for edge detection...
+    // And enable the interrupt
+    // And set it to only respond to interrupts on one edge.
+    switch (obj->port) {
+        case LPC_GPIO0_BASE:
+            // Clear
+            LPC_GPIO0->IC |= 1 << obj->pin;
+            
+            // Edge
+            LPC_GPIO0->IS &= ~(1 << obj->pin);
+            
+            // Enable
+            if (enable) LPC_GPIO0->IE |= 1 << obj->pin;
+            else LPC_GPIO0->IE &= ~(1 << obj->pin);
+            
+            // One edge
+            LPC_GPIO0->IBE &= ~(1 << obj->pin);
+            
+            // Rising/falling?
+            if (event == IRQ_RISE) LPC_GPIO0->IEV |= 1 << obj->pin;
+            else LPC_GPIO0->IEV &= ~(1 << obj->pin);
             break;
-        case 1:
-            gpioRegisters = LPC_GPIO1;
-            break;
-        case 2:
-            gpioRegisters = LPC_GPIO2;
-            break;
-        case 3:
-            gpioRegisters = LPC_GPIO3;
-            break;
-    }
+        case LPC_GPIO1_BASE:
+            LPC_GPIO1->IC |= 1 << obj->pin;
 
-    gpioRegisters->IBE  0; // Assume that we only want to interrupt on high or low edges, not both.
-    gpioRegisters->IS &= ~(1 << pin);
+            LPC_GPIO1->IS &= ~(1 << obj->pin);
 
-    if (enable) {
-        gpioRegisters->IE |= (1<<pin);
-    }
+            if (enable) LPC_GPIO1->IE |= 1 << obj->pin;
+            else LPC_GPIO1->IE &= ~(1 << obj->pin);
 
-    if (event == IRP_RISE) {
-        gpioRegisters->IEV |= 1 << pin;
-    }
-    else {
-        gpioRegisters->IEV &= ~(1 << pin);
+            LPC_GPIO1->IBE &= ~(1 << obj->pin);
+
+            if (event == IRQ_RISE) LPC_GPIO0->IEV |= 1 << obj->pin;
+            else LPC_GPIO0->IEV &= ~(1 << obj->pin);
+            break;
+        case LPC_GPIO2_BASE:
+            LPC_GPIO2->IC |= 1 << obj->pin;
+
+            LPC_GPIO2->IS &= ~(1 << obj->pin);
+
+            if (enable) LPC_GPIO2->IE |= 1 << obj->pin;
+            else LPC_GPIO2->IE &= ~(1 << obj->pin);
+
+            LPC_GPIO2->IBE &= ~(1 << obj->pin);
+
+            if (event == IRQ_RISE) LPC_GPIO0->IEV |= 1 << obj->pin;
+            else LPC_GPIO0->IEV &= ~(1 << obj->pin);
+            break;
+        case LPC_GPIO3_BASE:
+            LPC_GPIO3->IC |= 1 << obj->pin;
+
+            LPC_GPIO3->IC &= ~(1 << obj->pin);
+
+            if (enable) LPC_GPIO3->IE |= 1 << obj->pin;
+            else LPC_GPIO3->IE &= ~(1 << obj->pin);
+
+            LPC_GPIO3->IBE &= ~(1 << obj->pin);
+
+            if (event == IRQ_RISE) LPC_GPIO0->IEV |= 1 << obj->pin;
+            else LPC_GPIO0->IEV &= ~(1 << obj->pin);
+            break;
     }
 }
diff --git a/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC11XX/objects.h b/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC11XX/objects.h
index 0718498e8d..9ca1df1f3e 100644
--- a/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC11XX/objects.h
+++ b/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC11XX/objects.h
@@ -27,6 +27,8 @@ extern "C" {
 
 struct gpio_irq_s {
     uint32_t ch;
+    uint32_t port;
+    uint32_t pin;
 };
 
 struct port_s {