]> git.donarmstrong.com Git - qmk_firmware.git/blob - tool/mbed/mbed-sdk/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC11XX_11CXX/gpio_irq_api.c
Squashed 'tmk_core/' changes from 7967731..b9e0ea0
[qmk_firmware.git] / tool / mbed / mbed-sdk / libraries / mbed / targets / hal / TARGET_NXP / TARGET_LPC11XX_11CXX / gpio_irq_api.c
1 /* mbed Microcontroller Library
2  * Copyright (c) 2006-2013 ARM Limited
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include <stddef.h>
17 #include "cmsis.h"
18 #include "gpio_irq_api.h"
19 #include "mbed_error.h"
20 #include "gpio_api.h"
21
22 // The chip is capable of 42 GPIO interrupts.
23 // PIO0_0..PIO0_11, PIO1_0..PIO1_11, PIO2_0..PIO2_11, PIO3_0..PIO3_5
24 #define CHANNEL_NUM 42
25
26 static uint32_t channel_ids[CHANNEL_NUM] = {0};
27 static gpio_irq_handler irq_handler;
28
29 static inline int numofbits(uint32_t bits)
30 {
31     // Count number of bits
32     bits = (bits & 0x55555555) + (bits >> 1 & 0x55555555);
33     bits = (bits & 0x33333333) + (bits >> 2 & 0x33333333);
34     bits = (bits & 0x0f0f0f0f) + (bits >> 4 & 0x0f0f0f0f);
35     bits = (bits & 0x00ff00ff) + (bits >> 8 & 0x00ff00ff);
36     return (bits & 0x0000ffff) + (bits >>16 & 0x0000ffff);
37 }
38
39 static inline void handle_interrupt_in(uint32_t port) {
40     // Find out whether the interrupt has been triggered by a high or low value...
41     // As the LPC1114 doesn't have a specific register for this, we'll just have to read
42     // the level of the pin as if it were just a normal input...
43     
44     uint32_t channel;
45     
46     // Get the number of the pin being used and the port typedef
47     LPC_GPIO_TypeDef *port_reg = ((LPC_GPIO_TypeDef *) (LPC_GPIO0_BASE + (port * 0x10000)));
48     
49     // Get index of function table from Mask Interrupt Status register
50     channel = numofbits(port_reg->MIS - 1) + (port * 12);
51     
52     if (port_reg->MIS & port_reg->IBE) {
53         // both edge, read the level of pin
54         if ((port_reg->DATA & port_reg->MIS) != 0)
55             irq_handler(channel_ids[channel], IRQ_RISE);
56         else
57             irq_handler(channel_ids[channel], IRQ_FALL);
58     }
59     else if (port_reg->MIS & port_reg->IEV) {
60         irq_handler(channel_ids[channel], IRQ_RISE);
61     }
62     else {
63         irq_handler(channel_ids[channel], IRQ_FALL);
64     }
65
66     // Clear the interrupt...
67     port_reg->IC = port_reg->MIS;
68 }
69
70 void gpio_irq0(void) {handle_interrupt_in(0);}
71 void gpio_irq1(void) {handle_interrupt_in(1);}
72 void gpio_irq2(void) {handle_interrupt_in(2);}
73 void gpio_irq3(void) {handle_interrupt_in(3);}
74
75 int gpio_irq_init(gpio_irq_t *obj, PinName pin, gpio_irq_handler handler, uint32_t id) {
76     int channel;
77     uint32_t port_num;
78     
79     if (pin == NC) return -1;
80     
81     // Firstly, we'll put some data in *obj so we can keep track of stuff.
82     obj->pin = pin;
83     
84     // Set the handler to be the pointer at the top...
85     irq_handler = handler;
86     
87     // Which port are we using?
88     port_num = ((pin & 0xF000) >> PORT_SHIFT);
89     
90     switch (port_num) {
91         case 0:
92             NVIC_SetVector(EINT0_IRQn, (uint32_t)gpio_irq0);
93             NVIC_EnableIRQ(EINT0_IRQn);
94             break;
95         case 1:
96             NVIC_SetVector(EINT1_IRQn, (uint32_t)gpio_irq1);
97             NVIC_EnableIRQ(EINT1_IRQn);
98             break;
99         case 2:
100             NVIC_SetVector(EINT2_IRQn, (uint32_t)gpio_irq2);
101             NVIC_EnableIRQ(EINT2_IRQn);
102             break;
103         case 3:
104             NVIC_SetVector(EINT3_IRQn, (uint32_t)gpio_irq3);
105             NVIC_EnableIRQ(EINT3_IRQn);
106             break;
107         default:
108             return -1;
109     }
110     
111     // Generate index of function pointer table
112     // PIO0_0 - PIO0_11 :  0..11
113     // PIO1_0 - PIO1_11 : 12..23
114     // PIO2_0 - PIO2_11 : 24..35
115     // PIO3_0 - PIO3_5  : 36..41
116     channel = (port_num * 12) + ((pin & 0x0F00) >> PIN_SHIFT);
117     
118     channel_ids[channel] = id;
119     obj->ch = channel;
120     
121     return 0;
122 }
123
124 void gpio_irq_free(gpio_irq_t *obj) {
125     channel_ids[obj->ch] = 0;
126 }
127
128 void gpio_irq_set(gpio_irq_t *obj, gpio_irq_event event, uint32_t enable) {
129     // Firstly, check if there is an existing event stored...
130
131     LPC_GPIO_TypeDef *port_reg = ((LPC_GPIO_TypeDef *) (LPC_GPIO0_BASE + (((obj->pin & 0xF000) >> PORT_SHIFT) * 0x10000)));
132
133     // Need to get the pin number of the pin, not the value of the enum
134     uint32_t pin_num = (1 << ((obj->pin & 0x0f00) >> PIN_SHIFT));
135    
136     // Clear
137     port_reg->IC |= pin_num;
138     
139     // Make it edge sensitive.
140     port_reg->IS &= ~pin_num;
141
142     if ( (port_reg->IE & pin_num) != 0) {
143     // We have an event.
144     // Enable both edge interrupts.
145
146         if (enable) {
147             port_reg->IBE |= pin_num;
148             port_reg->IE  |= pin_num;
149         }
150         else {
151             // These all need to be opposite, to reenable the other one.
152             port_reg->IBE &= ~pin_num;
153
154             if (event == IRQ_RISE)
155                 port_reg->IEV &= ~pin_num;
156             else 
157                 port_reg->IEV |=  pin_num;
158
159             port_reg->IE |= pin_num;
160         }
161     }
162     else {
163         // One edge
164         port_reg->IBE &= ~pin_num;
165         // Rising/falling?
166         if (event == IRQ_RISE)
167             port_reg->IEV |=  pin_num;
168         else
169             port_reg->IEV &= ~pin_num;
170
171         if (enable) {
172             port_reg->IE |= pin_num;
173         }
174     }
175
176 }
177
178 void gpio_irq_enable(gpio_irq_t *obj) {
179     uint32_t port_num = ((obj->pin & 0xF000) >> PORT_SHIFT);
180     switch (port_num) {
181         case 0:
182             NVIC_EnableIRQ(EINT0_IRQn);
183             break;
184         case 1:
185             NVIC_EnableIRQ(EINT1_IRQn);
186             break;
187         case 2:
188             NVIC_EnableIRQ(EINT2_IRQn);
189             break;
190         case 3:
191             NVIC_EnableIRQ(EINT3_IRQn);
192             break;
193         default:
194             break;
195     }
196 }
197
198 void gpio_irq_disable(gpio_irq_t *obj) {
199     uint32_t port_num = ((obj->pin & 0xF000) >> PORT_SHIFT);
200     switch (port_num) {
201         case 0:
202             NVIC_DisableIRQ(EINT0_IRQn);
203             break;
204         case 1:
205             NVIC_DisableIRQ(EINT1_IRQn);
206             break;
207         case 2:
208             NVIC_DisableIRQ(EINT2_IRQn);
209             break;
210         case 3:
211             NVIC_DisableIRQ(EINT3_IRQn);
212             break;
213         default:
214             break;
215     }
216 }