Remove the PIO config from the clkout_on() function.
[dtplug] / 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 /***************************************************************************** */
25 /* Driver for GPIO configuration and access (including GPIO interrupts) on the LPC176x.
26  * Refer to LPC176x documentation (UM10360.pdf) for more information.
27  */
30 #include <stdint.h>
31 #include "core/lpc_regs_17xx.h"
32 #include "core/lpc_core_cm3.h"
33 #include "core/system.h"
34 #include "core/pio.h"
35 #include "drivers/gpio.h"
39 /***************************************************************************** */
40 /*   GPIO setup   */
42 /* IMPORTANT NOTICE : 
43  *    GPIO Power is on after reset and should be left ON as it also powers the
44  *      PIO configuration block.
45  *    Turn it off manually using subsystem_power() if you have configured all
46  *      your PIO functions and do not use GPIO.
47  */
50 /* GPIO Configuration
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_port_control* gpio_port = &(LPC_GPIO_PORTS->p[gpio->port]);
58         /* Configure as GPIO */
59         config_pio(gpio, mode);
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 }
73 /***************************************************************************** */
74 /* GPIO Interrupts Callbacks */
75 static void (*gpio_callbacks_port0[PORT0_MAX_PIN_NUM + 1]) (uint32_t);
76 static void (*gpio_callbacks_port2[PORT2_MAX_PIN_NUM + 1]) (uint32_t);
78 int set_gpio_callback(void (*callback) (uint32_t), const struct pio* gpio, uint8_t sense)
79 {
80         struct lpc_gpio_port_control* gpio_port = &(LPC_GPIO_PORTS->p[gpio->port]);
81         struct lpc_gpio_interrupts* gpio_int = LPC_GPIO_INTERRUPTS;
82         struct lpc_gpio_port_int* gpio_port_int = NULL;
83         uint32_t irq = EINT3_IRQ;
85         /* Register the callback */
86         /* FIXME : we should check that there were none registered for the selected pin */
87         switch (gpio->port) {
88                 case 0:
89                         if (gpio->pin > PORT0_MAX_PIN_NUM)
90                                 return -EINVAL;
91                         gpio_callbacks_port0[gpio->pin] = callback;
92                         gpio_port_int = &(gpio_int->port0);
93                         break;
94                 case 2:
95                         if (gpio->pin > PORT2_MAX_PIN_NUM)
96                                 return -EINVAL;
97                         gpio_callbacks_port2[gpio->pin] = callback;
98                         gpio_port_int = &(gpio_int->port2);
99                         break;
100                 default:
101                         return -EINVAL;
102         }
104         /* Configure the pin as interrupt source */
105         gpio_port->data_dir &= ~(1 << gpio->pin); /* Input */
106         config_pio(gpio, 0);
107         switch (sense) {
108                 case EDGES_BOTH:
109                         gpio_port_int->rising_enable |= (1 << gpio->pin);
110                         gpio_port_int->falling_enable |= (1 << gpio->pin);
111                         break;
112                 case EDGE_RISING:
113                         gpio_port_int->rising_enable |= (1 << gpio->pin);
114                         gpio_port_int->falling_enable &= ~(1 << gpio->pin);
115                         break;
116                 case EDGE_FALLING:
117                         gpio_port_int->rising_enable &= ~(1 << gpio->pin);
118                         gpio_port_int->falling_enable |= (1 << gpio->pin);
119                         break;
120                 default: /* Not handled, do not activate the interrupt */
121                         return -EINVAL;
122         }
123         NVIC_EnableIRQ(irq);
124         return 0;
126 void remove_gpio_callback(const struct pio* gpio)
128         struct lpc_gpio_interrupts* gpio_int = LPC_GPIO_INTERRUPTS;
129         struct lpc_gpio_port_int* gpio_port_int = NULL;
131         /* Remove the handler */
132         switch (gpio->port) {
133                 case 0:
134                         if (gpio->pin > PORT0_MAX_PIN_NUM)
135                                 return;
136                         gpio_callbacks_port0[gpio->pin] = NULL;
137                         gpio_port_int = &(gpio_int->port0);
138                         break;
139                 case 2:
140                         if (gpio->pin > PORT2_MAX_PIN_NUM)
141                                 return;
142                         gpio_callbacks_port2[gpio->pin] = NULL;
143                         gpio_port_int = &(gpio_int->port2);
144                         break;
145                 default:
146                         return;
147         }
148         /* And disable the interrupt */
149         gpio_port_int->rising_enable &= ~(1 << gpio->pin);
150         gpio_port_int->falling_enable &= ~(1 << gpio->pin);
154 /* Interrupt Handlers */
155 /* Those handlers are far from the most effective if used without concertation
156  * with the people doing the electronic design.
157  * Use them if you place the signals generating interrupts on low numbered pins
158  */
159 void PIO_Handler(struct lpc_gpio_port_int* port_int, void (**callbacks) (uint32_t))
161         uint32_t status = (port_int->rising_status | port_int->falling_status);
162         uint32_t rising = port_int->rising_status;
163         uint32_t i = 0;
165         port_int->clear = status;
166         /* Call interrupt handlers */
167         while (status) {
168                 if (status & 1) {
169                         /* Is there an handler for this one ? */
170                         if (callbacks[i] != NULL) {
171                                 callbacks[i](rising & (1 << i)); /* Tell whether it was a rising edge interrupt or not */
172                         }
173                 }
174                 status >>= 1;
175                 i++;
176         }
179 void EINT3_Handler(void)
181         struct lpc_gpio_interrupts* gpio_int = LPC_GPIO_INTERRUPTS;
182         if (gpio_int->overall_int_status & LPC_GPIO_INT_PORT0_PENDING) {
183                 PIO_Handler(&(gpio_int->port0), gpio_callbacks_port0);
184         }
185         if (gpio_int->overall_int_status & LPC_GPIO_INT_PORT2_PENDING) {
186                 PIO_Handler(&(gpio_int->port2), gpio_callbacks_port2);
187         }