xref: /nrf52832-nimble/drivers/drv_gpio.c (revision 167494296f0543431a51b6b1b83e957045294e05)
1 /*
2  * SPDX-License-Identifier: Apache-2.0
3  *
4  * Date           Author       Notes
5  * 2018-03-13     ZeroFree     first implementation
6  */
7 
8 #include <rtthread.h>
9 #include <rtdevice.h>
10 #include <rthw.h>
11 
12 #include "drv_gpio.h"
13 #include "nrf.h"
14 
15 #define MCU_GPIO_USE_PORT_EVENT 1
16 
17 #define NRF_GPIO_INDEX(pin) (pin)
18 #define NRF_GPIO_PORT(pin)  (NRF_P0)
19 #define NRF_GPIO_MASK(pin)  (1 << NRF_GPIO_INDEX(pin))
20 #define NRF_GPIOTE_PIN_MASK GPIOTE_CONFIG_PSEL_Msk
21 
22 /* GPIO interrupts */
23 #define NRF_GPIO_MAX_IRQ    8
24 
25 #if MCU_GPIO_USE_PORT_EVENT
26 #define NRF_GPIO_SENSE_TRIG_NONE    0x00 /* just 0 */
27 #define NRF_GPIO_SENSE_TRIG_BOTH    0x01 /* something else than both below */
28 #define NRF_GPIO_SENSE_TRIG_HIGH    0x02 /* GPIO_PIN_CNF_SENSE_High */
29 #define NRF_GPIO_SENSE_TRIG_LOW     0x03 /* GPIO_PIN_CNF_SENSE_Low */
30 #endif
31 
32 /* Storage for GPIO callbacks */
33 struct nrf_gpio_irq
34 {
35     void (*func)(void *args);
36     void              *args;
37 #if MCU_GPIO_USE_PORT_EVENT
38     rt_int16_t        pin;
39     uint8_t           sense_trig;
40 #endif
41 };
42 
43 static struct nrf_gpio_irq nrf_gpio_irqs[NRF_GPIO_MAX_IRQ];
44 
nrf_pin_mode(struct rt_device * device,rt_base_t pin,rt_base_t mode)45 static void nrf_pin_mode(struct rt_device *device, rt_base_t pin, rt_base_t mode)
46 {
47     uint32_t conf;
48     NRF_GPIO_Type *port;
49     uint8_t dir = 0;
50     int index = NRF_GPIO_INDEX(pin);
51 
52     switch (mode)
53     {
54     case PIN_MODE_OUTPUT:
55         conf = GPIO_PIN_CNF_DIR_Output |
56                (GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos);
57         dir = 1;
58         break;
59     case PIN_MODE_INPUT:
60         conf = 0;
61         break;
62     case PIN_MODE_INPUT_PULLUP:
63         conf = GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos;
64         break;
65     case PIN_MODE_INPUT_PULLDOWN:
66         conf = GPIO_PIN_CNF_PULL_Pulldown << GPIO_PIN_CNF_PULL_Pos;
67         break;
68     default:
69         conf = 0;
70         break;
71     }
72 
73     port = NRF_GPIO_PORT(pin);
74     port->PIN_CNF[index] = conf;
75 
76     if (dir == 1)
77     {
78         /* output */
79         port->DIRSET = NRF_GPIO_MASK(pin);
80         port->OUTCLR = NRF_GPIO_MASK(pin);
81     }
82     else
83     {
84         /* input */
85         port->DIRCLR = NRF_GPIO_MASK(pin);
86     }
87 }
88 
nrf_pin_write(struct rt_device * device,rt_base_t pin,rt_base_t value)89 static void nrf_pin_write(struct rt_device *device, rt_base_t pin, rt_base_t value)
90 {
91     NRF_GPIO_Type *port;
92 
93     port = NRF_GPIO_PORT(pin);
94     if (value)
95     {
96         port->OUTSET = NRF_GPIO_MASK(pin);
97     }
98     else
99     {
100         port->OUTCLR = NRF_GPIO_MASK(pin);
101     }
102 }
103 
nrf_pin_read(struct rt_device * device,rt_base_t pin)104 static int nrf_pin_read(struct rt_device *device, rt_base_t pin)
105 {
106     NRF_GPIO_Type *port;
107     port = NRF_GPIO_PORT(pin);
108 
109     return (port->DIR & NRF_GPIO_MASK(pin)) ?
110            (port->OUT >> NRF_GPIO_INDEX(pin)) & 1UL :
111            (port->IN >> NRF_GPIO_INDEX(pin)) & 1UL;
112 }
113 
114 /*
115  * GPIO irq handler
116  *
117  * Handles the gpio interrupt attached to a gpio pin.
118  *
119  * @param index
120  */
nrf_gpio_irq_handler(void)121 static void nrf_gpio_irq_handler(void)
122 {
123 #if MCU_GPIO_USE_PORT_EVENT
124     NRF_GPIO_Type *gpio_port;
125     int pin_index;
126     int pin_state;
127     uint8_t sense_trig;
128     uint32_t gpio_state;
129 #endif
130     int i;
131 
132     rt_interrupt_enter();
133 
134 #if MCU_GPIO_USE_PORT_EVENT
135     NRF_GPIOTE->EVENTS_PORT = 0;
136     gpio_state = NRF_P0->IN;
137 
138     for (i = 0; i < NRF_GPIO_MAX_IRQ; i++)
139     {
140         if ((!nrf_gpio_irqs[i].func) ||
141                 (nrf_gpio_irqs[i].sense_trig == NRF_GPIO_SENSE_TRIG_NONE))
142         {
143             continue;
144         }
145 
146         gpio_port = NRF_GPIO_PORT(nrf_gpio_irqs[i].pin);
147         pin_index = NRF_GPIO_INDEX(nrf_gpio_irqs[i].pin);
148 
149         /* Store current SENSE setting */
150         sense_trig = (gpio_port->PIN_CNF[pin_index] & GPIO_PIN_CNF_SENSE_Msk) >> GPIO_PIN_CNF_SENSE_Pos;
151 
152         if (!sense_trig)
153         {
154             continue;
155         }
156 
157         /*
158          * SENSE values are 0x02 for high and 0x03 for low, so bit #0 is the
159          * opposite of state which triggers interrupt (thus its value should be
160          * different than pin state).
161          */
162         pin_state = (gpio_state >> nrf_gpio_irqs[i].pin) & 0x01;
163         if (pin_state == (sense_trig & 0x01))
164         {
165             continue;
166         }
167 
168         /*
169          * Toggle sense to clear interrupt or allow detection of opposite edge
170          * when trigger on both edges is requested.
171          */
172         gpio_port->PIN_CNF[pin_index] &= ~GPIO_PIN_CNF_SENSE_Msk;
173         if (sense_trig == NRF_GPIO_SENSE_TRIG_HIGH)
174         {
175             gpio_port->PIN_CNF[pin_index] |= GPIO_PIN_CNF_SENSE_Low << GPIO_PIN_CNF_SENSE_Pos;
176         }
177         else
178         {
179             gpio_port->PIN_CNF[pin_index] |= GPIO_PIN_CNF_SENSE_High << GPIO_PIN_CNF_SENSE_Pos;
180         }
181 
182         /*
183          * Call handler in case SENSE configuration matches requested one or
184          * trigger on both edges is requested.
185          */
186         if ((nrf_gpio_irqs[i].sense_trig == NRF_GPIO_SENSE_TRIG_BOTH) ||
187                 (nrf_gpio_irqs[i].sense_trig == sense_trig))
188         {
189             nrf_gpio_irqs[i].func(nrf_gpio_irqs[i].args);
190         }
191     }
192 #else
193     for (i = 0; i < NRF_GPIO_MAX_IRQ; i++)
194     {
195         if (NRF_GPIOTE->EVENTS_IN[i] && (NRF_GPIOTE->INTENSET & (1 << i)))
196         {
197             NRF_GPIOTE->EVENTS_IN[i] = 0;
198             if (nrf_gpio_irqs[i].func)
199             {
200                 nrf_gpio_irqs[i].func(nrf_gpio_irqs[i].args);
201             }
202         }
203     }
204 #endif
205 
206     rt_interrupt_leave();
207 }
208 
GPIOTE_IRQHandler(void)209 void GPIOTE_IRQHandler(void)
210 {
211     nrf_gpio_irq_handler();
212 }
213 
nrf_gpio_irq_setup(void)214 static void nrf_gpio_irq_setup(void)
215 {
216     static uint8_t irq_setup = 0;
217 
218     if (!irq_setup)
219     {
220         NVIC_EnableIRQ(GPIOTE_IRQn);
221         irq_setup = 1;
222 
223 #if MCU_GPIO_USE_PORT_EVENT
224         NRF_GPIOTE->INTENCLR = GPIOTE_INTENCLR_PORT_Msk;
225         NRF_GPIOTE->EVENTS_PORT = 0;
226 #endif
227     }
228 }
229 
230 /*
231  * Find out whether we have an GPIOTE pin event to use.
232  */
hal_gpio_find_empty_slot(void)233 static int hal_gpio_find_empty_slot(void)
234 {
235     int i;
236 
237     for (i = 0; i < NRF_GPIO_MAX_IRQ; i++)
238     {
239         if (nrf_gpio_irqs[i].func == NULL)
240         {
241             return i;
242         }
243     }
244     return -1;
245 }
246 
247 /*
248  * Find the GPIOTE event which handles this pin.
249  */
nrf_gpio_find_pin(int pin)250 static int nrf_gpio_find_pin(int pin)
251 {
252     int i;
253 
254 #if MCU_GPIO_USE_PORT_EVENT
255     for (i = 0; i < NRF_GPIO_MAX_IRQ; i++)
256     {
257         if (nrf_gpio_irqs[i].func && nrf_gpio_irqs[i].pin == pin)
258         {
259             return i;
260         }
261     }
262 #else
263     pin = pin << GPIOTE_CONFIG_PSEL_Pos;
264 
265     for (i = 0; i < NRF_GPIO_MAX_IRQ; i++)
266     {
267         if (nrf_gpio_irqs[i].func &&
268                 (NRF_GPIOTE->CONFIG[i] & NRF_GPIOTE_PIN_MASK) == pin)
269         {
270             return i;
271         }
272     }
273 #endif
274 
275     return -1;
276 }
277 
nrf_pin_attach_irq(struct rt_device * device,rt_int32_t pin,rt_uint32_t mode,void (* hdr)(void * args),void * args)278 static rt_err_t nrf_pin_attach_irq(struct rt_device *device, rt_int32_t pin,
279                                    rt_uint32_t mode, void (*hdr)(void *args), void *args)
280 {
281     uint32_t conf;
282     int i;
283 
284     nrf_gpio_irq_setup();
285     i = hal_gpio_find_empty_slot();
286     if (i < 0)
287     {
288         return -RT_EFULL;
289     }
290 
291 #if MCU_GPIO_USE_PORT_EVENT
292     (void)conf;
293     nrf_gpio_irqs[i].pin = pin;
294 
295     switch (mode)
296     {
297     case PIN_IRQ_MODE_RISING:
298         nrf_gpio_irqs[i].sense_trig = NRF_GPIO_SENSE_TRIG_HIGH;
299         break;
300     case PIN_IRQ_MODE_FALLING:
301         nrf_gpio_irqs[i].sense_trig = NRF_GPIO_SENSE_TRIG_LOW;
302         break;
303     case PIN_IRQ_MODE_RISING_FALLING:
304         nrf_gpio_irqs[i].sense_trig = NRF_GPIO_SENSE_TRIG_BOTH;
305         break;
306     default:
307         nrf_gpio_irqs[i].sense_trig = NRF_GPIO_SENSE_TRIG_NONE;
308         return -1;
309     }
310 #else
311     switch (mode)
312     {
313     case PIN_IRQ_MODE_RISING:
314         conf = GPIOTE_CONFIG_POLARITY_LoToHi << GPIOTE_CONFIG_POLARITY_Pos;
315         break;
316     case PIN_IRQ_MODE_FALLING:
317         conf = GPIOTE_CONFIG_POLARITY_HiToLo << GPIOTE_CONFIG_POLARITY_Pos;
318         break;
319     case PIN_IRQ_MODE_RISING_FALLING:
320         conf = GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos;
321         break;
322     default:
323         return -RT_ERROR;
324     }
325 
326     conf |= pin << GPIOTE_CONFIG_PSEL_Pos;
327     conf |= GPIOTE_CONFIG_MODE_Event << GPIOTE_CONFIG_MODE_Pos;
328     NRF_GPIOTE->CONFIG[i] = conf;
329 #endif
330 
331     nrf_gpio_irqs[i].func = hdr;
332     nrf_gpio_irqs[i].args = args;
333 
334     return RT_EOK;
335 }
336 
nrf_pin_detach_irq(struct rt_device * device,rt_int32_t pin)337 static rt_err_t nrf_pin_detach_irq(struct rt_device *device, rt_int32_t pin)
338 {
339     rt_err_t ret = RT_EOK;
340 
341     int i;
342 
343     i = nrf_gpio_find_pin(pin);
344     if (i < 0)
345     {
346         return -RT_ERROR;
347     }
348     /* disable pin irq */
349     rt_pin_irq_enable(pin, 0);
350 
351 #if MCU_GPIO_USE_PORT_EVENT
352     nrf_gpio_irqs[i].sense_trig = NRF_GPIO_SENSE_TRIG_NONE;
353 #else
354     NRF_GPIOTE->CONFIG[i] = 0;
355     NRF_GPIOTE->EVENTS_IN[i] = 0;
356 #endif
357 
358     nrf_gpio_irqs[i].args = NULL;
359     nrf_gpio_irqs[i].func = NULL;
360 
361     return ret;
362 }
363 
nrf_pin_irq_enable(struct rt_device * device,rt_base_t pin,rt_uint32_t enabled)364 static rt_err_t nrf_pin_irq_enable(struct rt_device *device, rt_base_t pin, rt_uint32_t enabled)
365 {
366 #if MCU_GPIO_USE_PORT_EVENT
367     NRF_GPIO_Type *nrf_gpio;
368     int pin_index, sense_enabled = 0;
369 #endif
370     int i;
371 
372     i = nrf_gpio_find_pin(pin);
373     if (i < 0)
374     {
375         return -RT_ERROR;
376     }
377 
378 #if MCU_GPIO_USE_PORT_EVENT
379     nrf_gpio = NRF_GPIO_PORT(pin);
380     pin_index = NRF_GPIO_INDEX(pin);
381     nrf_gpio->PIN_CNF[pin_index] &= ~GPIO_PIN_CNF_SENSE_Msk;
382 
383     if (enabled)
384     {
385         /*
386          * Always set initial SENSE to opposite of current pin state to avoid
387          * triggering immediately
388          */
389         if (nrf_gpio->IN & (1 << pin_index))
390         {
391             nrf_gpio->PIN_CNF[pin_index] |= GPIO_PIN_CNF_SENSE_Low << GPIO_PIN_CNF_SENSE_Pos;
392         }
393         else
394         {
395             nrf_gpio->PIN_CNF[pin_index] |= GPIO_PIN_CNF_SENSE_High << GPIO_PIN_CNF_SENSE_Pos;
396         }
397 
398         NRF_GPIOTE->INTENSET = GPIOTE_INTENSET_PORT_Msk;
399     }
400     else
401     {
402         for (i = 0; i < NRF_GPIO_MAX_IRQ; i++)
403         {
404             if (nrf_gpio_irqs[i].sense_trig != NRF_GPIO_SENSE_TRIG_NONE)
405             {
406                 sense_enabled = 1;
407                 break;
408             }
409         }
410         if (!sense_enabled)
411         {
412             NRF_GPIOTE->INTENCLR = GPIOTE_INTENCLR_PORT_Msk;
413         }
414     }
415 #else
416     if (enabled)
417     {
418         NRF_GPIOTE->EVENTS_IN[i] = 0;
419         NRF_GPIOTE->INTENSET = 1 << i;
420     }
421     else
422     {
423         NRF_GPIOTE->INTENCLR = 1 << i;
424     }
425 
426 #endif
427 
428     return RT_EOK;
429 }
430 
431 const static struct rt_pin_ops nrf_pin_ops =
432 {
433     nrf_pin_mode,
434     nrf_pin_write,
435     nrf_pin_read,
436 
437     nrf_pin_attach_irq,
438     nrf_pin_detach_irq,
439     nrf_pin_irq_enable
440 };
441 
rt_hw_pin_init(void)442 int rt_hw_pin_init(void)
443 {
444     rt_err_t ret = RT_EOK;
445 
446     ret = rt_device_pin_register("pin", &nrf_pin_ops, RT_NULL);
447 
448     return ret;
449 }
450 
451 INIT_BOARD_EXPORT(rt_hw_pin_init);
452