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