1 /****************************************************************************
4 * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *************************************************************************** */
21 /***************************************************************************** */
22 /* GPIOs and GPIO Interrupts */
23 /***************************************************************************** */
28 #include "core/lpc_regs_11u3x.h"
29 #include "core/lpc_core_cm0.h"
30 #include "core/system.h"
32 #include "drivers/gpio.h"
36 /***************************************************************************** */
41 /* Provide power to GPIO control blocks */
42 subsystem_power(LPC_SYS_ABH_CLK_CTRL_GPIO, 1);
46 /* Remove power from GPIO control blocks */
47 subsystem_power(LPC_SYS_ABH_CLK_CTRL_GPIO, 0);
51 * This function calls the config_pio() function for the gpio with the given
52 * mode, configures the direction of the pin and sets the initial state.
54 void config_gpio(const struct pio* gpio, uint32_t mode, uint8_t dir, uint8_t ini_val)
56 struct lpc_gpio* gpio_port = LPC_GPIO_REGS(gpio->port);
58 /* Configure as GPIO */
59 config_pio(gpio, mode | LPC_IO_DIGITAL);
61 if (dir == GPIO_DIR_IN) {
62 gpio_port->data_dir &= ~(1 << gpio->pin);
64 gpio_port->data_dir |= (1 << gpio->pin);
66 gpio_port->clear = (1 << gpio->pin);
68 gpio_port->set = (1 << gpio->pin);
75 /***************************************************************************** */
76 /* GPIO Interrupts setup */
79 #define NB_PIN_INTERRUPTS 8
80 static void (*gpio_calbacks[NB_PIN_INTERRUPTS]) (uint32_t);
83 int set_gpio_callback(void (*callback) (uint32_t), uint8_t irq, const struct pio* gpio, uint8_t sense)
85 struct lpc_gpio* gpio_port = NULL;
86 struct lpc_sys_control* sys_ctrl = LPC_SYS_CONTROL;
87 struct lpc_gpio_pin_edge_interrupt* edge_conf = LPC_GPIO_INT_EDGE;
88 struct lpc_gpio_pin_level_interrupt* level_conf = LPC_GPIO_INT_LEVEL;
91 if (irq >= NB_PIN_INTERRUPTS) {
96 if (gpio->pin >= PORT0_NB_PINS)
98 gpio_port = LPC_GPIO_0;
101 if (gpio->pin >= PORT1_NB_PINS)
103 gpio_port = LPC_GPIO_1;
109 /* Configure the pin as interrupt source */
110 config_pio(gpio, LPC_IO_DIGITAL);
111 gpio_port->data_dir &= ~(1 << gpio->pin); /* Input */
113 /* Register the callback */
114 /* FIXME : we should check that there were none registered for the selected pin */
115 gpio_calbacks[irq] = callback;
117 /* Power the Pin interrupt block */
118 subsystem_power(LPC_SYS_ABH_CLK_CTRL_PINT, 1);
119 subsystem_power(LPC_SYS_ABH_CLK_CTRL_P0INT, 1);
120 subsystem_power(LPC_SYS_ABH_CLK_CTRL_P1INT, 1);
122 /* And setup the interrupt */
125 edge_conf->mode &= ~(0x01 << irq);
126 edge_conf->rising_enable_set = (0x01 << irq);
127 edge_conf->falling_enable_set = (0x01 << irq);
130 edge_conf->mode &= ~(0x01 << irq);
131 edge_conf->rising_enable_set = (0x01 << irq);
132 edge_conf->falling_enable_clear = (0x01 << irq);
135 edge_conf->mode &= ~(0x01 << irq);
136 edge_conf->falling_enable_set = (0x01 << irq);
137 edge_conf->rising_enable_clear = (0x01 << irq);
140 level_conf->mode |= (0x01 << irq);
141 level_conf->enable_set = (0x01 << irq);
142 level_conf->set_active_low = (0x01 << irq);
145 level_conf->mode |= (0x01 << irq);
146 level_conf->enable_set = (0x01 << irq);
147 level_conf->set_active_high = (0x01 << irq);
149 default: /* Not handled, do not activate the interrupt */
153 /* Connect the port/pin to the interrupt */
154 sys_ctrl->gpio_int_sel[irq] = ((gpio->pin & 0x1F) | (gpio->port << 5));
159 void remove_gpio_callback(uint8_t irq)
161 /* Remove the handler */
162 gpio_calbacks[irq] = NULL;
163 /* And disable the interrupt */
164 NVIC_DisableIRQ(irq);
168 /* Interrupt Handlers */
169 /* Using LPC_GPIO_INT_EDGE is OK for both types of interupts */
170 /* Note : For level interrupts, we toggle the active level, which may no be what's th euser wants ... */
171 #define DECLARE_PIO_INT_HANDLER(x) \
172 void Pin_Int ## x ## _Handler(void) \
174 struct lpc_gpio_pin_edge_interrupt* regs = LPC_GPIO_INT_EDGE; \
175 regs->status = (0x01 << (x)); \
176 if (gpio_calbacks[(x)] != NULL) { \
177 gpio_calbacks[(x)]((x)); \
180 DECLARE_PIO_INT_HANDLER(0);
181 DECLARE_PIO_INT_HANDLER(1);
182 DECLARE_PIO_INT_HANDLER(2);
183 DECLARE_PIO_INT_HANDLER(3);
184 DECLARE_PIO_INT_HANDLER(4);
185 DECLARE_PIO_INT_HANDLER(5);
186 DECLARE_PIO_INT_HANDLER(6);
187 DECLARE_PIO_INT_HANDLER(7);
189 void PIO_GRP_0_Handler(void)
192 void PIO_GRP_1_Handler(void)