Initial commit, code based on LPC1224 support and LPC812-MAX CMSIS-DAP interface...
[lpc11u3x] / drivers / gpio.c
1 /****************************************************************************
2  *  drivers/gpio.c
3  *
4  * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
5  *
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.
10  *
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.
15  *
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/>.
18  *
19  *************************************************************************** */
21 /***************************************************************************** */
22 /*                GPIOs and GPIO Interrupts                                    */
23 /***************************************************************************** */
27 #include <stdint.h>
28 #include "core/lpc_regs_11u3x.h"
29 #include "core/lpc_core_cm0.h"
30 #include "core/system.h"
31 #include "core/pio.h"
32 #include "drivers/gpio.h"
36 /***************************************************************************** */
37 /*   GPIO setup   */
39 void gpio_on(void)
40 {
41         /* Provide power to GPIO control blocks */
42         subsystem_power(LPC_SYS_ABH_CLK_CTRL_GPIO, 1);
43 }
44 void gpio_off(void)
45 {
46         /* Remove power from GPIO control blocks */
47         subsystem_power(LPC_SYS_ABH_CLK_CTRL_GPIO, 0);
48 }
50 /*
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.
53  */
54 void config_gpio(const struct pio* gpio, uint32_t mode, uint8_t dir, uint8_t ini_val)
55 {
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);
63         } else {
64                 gpio_port->data_dir |= (1 << gpio->pin);
65                 if (ini_val == 0) {
66                         gpio_port->clear = (1 << gpio->pin);
67                 } else {
68                         gpio_port->set = (1 << gpio->pin);
69                 }
70         }
71 }
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)
84 {
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;
90         /* Sanity checks */
91         if (irq >= NB_PIN_INTERRUPTS) {
92                 return -EINVAL;
93         }
94         switch (gpio->port) {
95                 case 0:
96                         if (gpio->pin >= PORT0_NB_PINS)
97                                 return -EINVAL;
98                         gpio_port = LPC_GPIO_0;
99                         break;
100                 case 1:
101                         if (gpio->pin >= PORT1_NB_PINS)
102                                 return -EINVAL;
103                         gpio_port = LPC_GPIO_1;
104                         break;
105                 default:
106                         return -EINVAL;
107         }
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 */
123         switch (sense) {
124                 case EDGES_BOTH:
125                         edge_conf->mode &= ~(0x01 << irq);
126                         edge_conf->rising_enable_set = (0x01 << irq);
127                         edge_conf->falling_enable_set = (0x01 << irq);
128                         break;
129                 case EDGE_RISING:
130                         edge_conf->mode &= ~(0x01 << irq);
131                         edge_conf->rising_enable_set = (0x01 << irq);
132                         edge_conf->falling_enable_clear = (0x01 << irq);
133                         break;
134                 case EDGE_FALLING:
135                         edge_conf->mode &= ~(0x01 << irq);
136                         edge_conf->falling_enable_set = (0x01 << irq);
137                         edge_conf->rising_enable_clear = (0x01 << irq);
138                         break;
139                 case LEVEL_LOW:
140                         level_conf->mode |= (0x01 << irq);
141                         level_conf->enable_set = (0x01 << irq);
142                         level_conf->set_active_low = (0x01 << irq);
143                         break;
144                 case LEVEL_HIGH:
145                         level_conf->mode |= (0x01 << irq);
146                         level_conf->enable_set = (0x01 << irq);
147                         level_conf->set_active_high = (0x01 << irq);
148                         break;
149                 default: /* Not handled, do not activate the interrupt */
150                         return -EINVAL;
151         }
153         /* Connect the port/pin to the interrupt */
154         sys_ctrl->gpio_int_sel[irq] = ((gpio->pin & 0x1F) | (gpio->port << 5));
156         NVIC_EnableIRQ(irq);
157         return 0;
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) \
173         { \
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)); \
178                 } \
179         }
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)