1 /***************************************************************************//**
2 * @file
3 * @brief General Purpose IO (GPIO) driver API
4 *******************************************************************************
5 * # License
6 * <b>Copyright 2024 Silicon Laboratories Inc. www.silabs.com</b>
7 *******************************************************************************
8 *
9 * SPDX-License-Identifier: Zlib
10 *
11 * The licensor of this software is Silicon Laboratories Inc.
12 *
13 * This software is provided 'as-is', without any express or implied
14 * warranty. In no event will the authors be held liable for any damages
15 * arising from the use of this software.
16 *
17 * Permission is granted to anyone to use this software for any purpose,
18 * including commercial applications, and to alter it and redistribute it
19 * freely, subject to the following restrictions:
20 *
21 * 1. The origin of this software must not be misrepresented; you must not
22 * claim that you wrote the original software. If you use this software
23 * in a product, an acknowledgment in the product documentation would be
24 * appreciated but is not required.
25 * 2. Altered source versions must be plainly marked as such, and must not be
26 * misrepresented as being the original software.
27 * 3. This notice may not be removed or altered from any source distribution.
28 *
29 ******************************************************************************/
30
31 #include <stddef.h>
32 #include "sl_core.h"
33 #include "sl_common.h"
34 #include "sl_interrupt_manager.h"
35 #include "sl_clock_manager.h"
36 #include "sl_hal_gpio.h"
37 #include "sl_gpio.h"
38
39 /*******************************************************************************
40 ******************************* DEFINES ***********************************
41 ******************************************************************************/
42
43 /// Define for supporting gpiointerrupt porting
44 #define SL_GPIO_PORT_INTERRUPT (0xFF)
45
46 /// Pin direction validation.
47 #define SL_GPIO_DIRECTION_IS_VALID(direction) (direction <= SL_GPIO_PIN_DIRECTION_OUT)
48
49 /*******************************************************************************
50 ******************************* STRUCTS ***********************************
51 ******************************************************************************/
52
53 typedef struct {
54 // Pin interrupt number in range 0 to 15.
55 uint32_t int_no;
56 // Pointer to callback function.
57 void *callback;
58 // Pointer to callback context.
59 void *context;
60 } sl_gpio_callback_desc_t;
61
62 typedef struct {
63 // An array of user callbacks for external interrupts.
64 // We have external interrupts configured from 0 to 15 bits.
65 sl_gpio_callback_desc_t callback_ext[SL_HAL_GPIO_INTERRUPT_MAX];
66 // An array of user callbacks for EM4 interrupts.
67 // We have EM4 interrupts configured from 16 to 31 bits.
68 sl_gpio_callback_desc_t callback_em4[SL_HAL_GPIO_INTERRUPT_MAX];
69 } sl_gpio_callbacks_t;
70
71 /*******************************************************************************
72 ******************************** GLOBALS **********************************
73 ******************************************************************************/
74
75 // Variable to manage and organize the callback functions for External and EM4 interrupts.
76 static sl_gpio_callbacks_t gpio_interrupts = { 0 };
77
78 /*******************************************************************************
79 ****************************** LOCAL FUCTIONS *****************************
80 ******************************************************************************/
81 static void sl_gpio_dispatch_interrupt(uint32_t iflags);
82
83 /***************************************************************************//**
84 * Driver GPIO Initialization.
85 ******************************************************************************/
sl_gpio_init()86 sl_status_t sl_gpio_init()
87 {
88 sl_clock_manager_enable_bus_clock(SL_BUS_CLOCK_GPIO);
89
90 if (sl_interrupt_manager_is_irq_disabled(GPIO_ODD_IRQn)) {
91 sl_interrupt_manager_clear_irq_pending(GPIO_ODD_IRQn);
92 sl_interrupt_manager_enable_irq(GPIO_ODD_IRQn);
93 }
94 if (sl_interrupt_manager_is_irq_disabled(GPIO_EVEN_IRQn)) {
95 sl_interrupt_manager_clear_irq_pending(GPIO_EVEN_IRQn);
96 sl_interrupt_manager_enable_irq(GPIO_EVEN_IRQn);
97 }
98
99 return SL_STATUS_OK;
100 }
101
102 /***************************************************************************//**
103 * Sets the pin direction for GPIO pin.
104 ******************************************************************************/
sl_gpio_set_pin_direction(const sl_gpio_t * gpio,sl_gpio_pin_direction_t pin_direction)105 sl_status_t sl_gpio_set_pin_direction(const sl_gpio_t *gpio,
106 sl_gpio_pin_direction_t pin_direction)
107 {
108 CORE_DECLARE_IRQ_STATE;
109
110 if (gpio == NULL) {
111 EFM_ASSERT(false);
112 return SL_STATUS_NULL_POINTER;
113 }
114 if (!SL_HAL_GPIO_PORT_PIN_IS_VALID(gpio->port, gpio->pin) || !SL_GPIO_DIRECTION_IS_VALID(pin_direction)) {
115 EFM_ASSERT(false);
116 return SL_STATUS_INVALID_PARAMETER;
117 }
118 if (sl_hal_gpio_get_lock_status() != 0) {
119 EFM_ASSERT(false);
120 return SL_STATUS_INVALID_STATE;
121 }
122
123 CORE_ENTER_ATOMIC();
124
125 if (pin_direction == SL_GPIO_PIN_DIRECTION_OUT) {
126 sl_hal_gpio_set_pin_mode(gpio, SL_GPIO_MODE_PUSH_PULL, 1);
127 } else if (pin_direction == SL_GPIO_PIN_DIRECTION_IN) {
128 sl_hal_gpio_set_pin_mode(gpio, SL_GPIO_MODE_INPUT, 0);
129 }
130
131 CORE_EXIT_ATOMIC();
132 return SL_STATUS_OK;
133 }
134
135 /***************************************************************************//**
136 * Sets the mode for GPIO pin and pin direction.
137 ******************************************************************************/
sl_gpio_set_pin_mode(const sl_gpio_t * gpio,sl_gpio_mode_t mode,bool output_value)138 sl_status_t sl_gpio_set_pin_mode(const sl_gpio_t *gpio,
139 sl_gpio_mode_t mode,
140 bool output_value)
141 {
142 CORE_DECLARE_IRQ_STATE;
143
144 if (gpio == NULL) {
145 EFM_ASSERT(false);
146 return SL_STATUS_NULL_POINTER;
147 }
148 if (!SL_HAL_GPIO_MODE_IS_VALID(mode) || !SL_HAL_GPIO_PORT_PIN_IS_VALID(gpio->port, gpio->pin)) {
149 EFM_ASSERT(false);
150 return SL_STATUS_INVALID_PARAMETER;
151 }
152 if (sl_hal_gpio_get_lock_status() != 0) {
153 EFM_ASSERT(false);
154 return SL_STATUS_INVALID_STATE;
155 }
156
157 CORE_ENTER_ATOMIC();
158
159 sl_hal_gpio_set_pin_mode(gpio, mode, output_value);
160
161 CORE_EXIT_ATOMIC();
162 return SL_STATUS_OK;
163 }
164
165 /***************************************************************************//**
166 * Gets the current configuration selected pin on selected port.
167 ******************************************************************************/
sl_gpio_get_pin_config(const sl_gpio_t * gpio,sl_gpio_pin_config_t * pin_config)168 sl_status_t sl_gpio_get_pin_config(const sl_gpio_t *gpio,
169 sl_gpio_pin_config_t *pin_config)
170 {
171 CORE_DECLARE_IRQ_STATE;
172
173 if (gpio == NULL || pin_config == NULL) {
174 EFM_ASSERT(false);
175 return SL_STATUS_NULL_POINTER;
176 }
177 if (!SL_HAL_GPIO_PORT_PIN_IS_VALID(gpio->port, gpio->pin)) {
178 EFM_ASSERT(false);
179 return SL_STATUS_INVALID_PARAMETER;
180 }
181
182 CORE_ENTER_ATOMIC();
183
184 pin_config->mode = sl_hal_gpio_get_pin_mode(gpio);
185 switch (pin_config->mode) {
186 case SL_GPIO_MODE_INPUT:
187 case SL_GPIO_MODE_INPUT_PULL:
188 case SL_GPIO_MODE_INPUT_PULL_FILTER:
189 pin_config->direction = SL_GPIO_PIN_DIRECTION_IN;
190 break;
191
192 case SL_GPIO_MODE_DISABLED:
193 case SL_GPIO_MODE_PUSH_PULL:
194 case SL_GPIO_MODE_PUSH_PULL_ALTERNATE:
195 case SL_GPIO_MODE_WIRED_OR:
196 case SL_GPIO_MODE_WIRED_OR_PULL_DOWN:
197 case SL_GPIO_MODE_WIRED_AND:
198 case SL_GPIO_MODE_WIRED_AND_FILTER:
199 case SL_GPIO_MODE_WIRED_AND_PULLUP:
200 case SL_GPIO_MODE_WIRED_AND_PULLUP_FILTER:
201 case SL_GPIO_MODE_WIRED_AND_ALTERNATE:
202 case SL_GPIO_MODE_WIRED_AND_ALTERNATE_FILTER:
203 case SL_GPIO_MODE_WIRED_AND_ALTERNATE_PULLUP:
204 case SL_GPIO_MODE_WIRED_AND_ALTERNATE_PULLUP_FILTER:
205 pin_config->direction = SL_GPIO_PIN_DIRECTION_OUT;
206 break;
207
208 default:
209 CORE_EXIT_ATOMIC();
210 EFM_ASSERT(false);
211 return SL_STATUS_INVALID_MODE;
212 }
213
214 CORE_EXIT_ATOMIC();
215 return SL_STATUS_OK;
216 }
217
218 /***************************************************************************//**
219 * Sets the DOUT of selected pin on selected port.
220 ******************************************************************************/
sl_gpio_set_pin(const sl_gpio_t * gpio)221 sl_status_t sl_gpio_set_pin(const sl_gpio_t *gpio)
222 {
223 CORE_DECLARE_IRQ_STATE;
224
225 if (gpio == NULL) {
226 EFM_ASSERT(false);
227 return SL_STATUS_NULL_POINTER;
228 }
229 if (!SL_HAL_GPIO_PORT_PIN_IS_VALID(gpio->port, gpio->pin)) {
230 EFM_ASSERT(false);
231 return SL_STATUS_INVALID_PARAMETER;
232 }
233
234 CORE_ENTER_ATOMIC();
235
236 sl_hal_gpio_set_pin(gpio);
237
238 CORE_EXIT_ATOMIC();
239 return SL_STATUS_OK;
240 }
241
242 /***************************************************************************//**
243 * Clears the DOUT of selected pin on selected port.
244 ******************************************************************************/
sl_gpio_clear_pin(const sl_gpio_t * gpio)245 sl_status_t sl_gpio_clear_pin(const sl_gpio_t *gpio)
246 {
247 CORE_DECLARE_IRQ_STATE;
248
249 if (gpio == NULL) {
250 EFM_ASSERT(false);
251 return SL_STATUS_NULL_POINTER;
252 }
253 if (!SL_HAL_GPIO_PORT_PIN_IS_VALID(gpio->port, gpio->pin)) {
254 EFM_ASSERT(false);
255 return SL_STATUS_INVALID_PARAMETER;
256 }
257
258 CORE_ENTER_ATOMIC();
259
260 sl_hal_gpio_clear_pin(gpio);
261
262 CORE_EXIT_ATOMIC();
263 return SL_STATUS_OK;
264 }
265
266 /***************************************************************************//**
267 * Toggles the DOUT of selected pin on selected port.
268 ******************************************************************************/
sl_gpio_toggle_pin(const sl_gpio_t * gpio)269 sl_status_t sl_gpio_toggle_pin(const sl_gpio_t *gpio)
270 {
271 CORE_DECLARE_IRQ_STATE;
272
273 if (gpio == NULL) {
274 EFM_ASSERT(false);
275 return SL_STATUS_NULL_POINTER;
276 }
277 if (!SL_HAL_GPIO_PORT_PIN_IS_VALID(gpio->port, gpio->pin)) {
278 EFM_ASSERT(false);
279 return SL_STATUS_INVALID_PARAMETER;
280 }
281
282 CORE_ENTER_ATOMIC();
283
284 sl_hal_gpio_toggle_pin(gpio);
285
286 CORE_EXIT_ATOMIC();
287 return SL_STATUS_OK;
288 }
289
290 /***************************************************************************//**
291 * Gets the output state of selected pin on selected port.
292 ******************************************************************************/
sl_gpio_get_pin_output(const sl_gpio_t * gpio,bool * pin_value)293 sl_status_t sl_gpio_get_pin_output(const sl_gpio_t *gpio,
294 bool *pin_value)
295 {
296 CORE_DECLARE_IRQ_STATE;
297
298 if (gpio == NULL || pin_value == NULL) {
299 EFM_ASSERT(false);
300 return SL_STATUS_NULL_POINTER;
301 }
302 if (!SL_HAL_GPIO_PORT_PIN_IS_VALID(gpio->port, gpio->pin)) {
303 EFM_ASSERT(false);
304 return SL_STATUS_INVALID_PARAMETER;
305 }
306
307 CORE_ENTER_ATOMIC();
308
309 *pin_value = sl_hal_gpio_get_pin_output(gpio);
310
311 CORE_EXIT_ATOMIC();
312 return SL_STATUS_OK;
313 }
314
315 /***************************************************************************//**
316 * Gets the input state of selected pin on selected port.
317 ******************************************************************************/
sl_gpio_get_pin_input(const sl_gpio_t * gpio,bool * pin_value)318 sl_status_t sl_gpio_get_pin_input(const sl_gpio_t *gpio,
319 bool *pin_value)
320 {
321 CORE_DECLARE_IRQ_STATE;
322
323 if (gpio == NULL || pin_value == NULL) {
324 EFM_ASSERT(false);
325 return SL_STATUS_NULL_POINTER;
326 }
327 if (!SL_HAL_GPIO_PORT_PIN_IS_VALID(gpio->port, gpio->pin)) {
328 EFM_ASSERT(false);
329 return SL_STATUS_INVALID_PARAMETER;
330 }
331
332 CORE_ENTER_ATOMIC();
333
334 *pin_value = sl_hal_gpio_get_pin_input(gpio);
335
336 CORE_EXIT_ATOMIC();
337 return SL_STATUS_OK;
338 }
339
340 /***************************************************************************//**
341 * Sets the selected pin(s) on selected port.
342 ******************************************************************************/
sl_gpio_set_port(sl_gpio_port_t port,uint32_t pins)343 sl_status_t sl_gpio_set_port(sl_gpio_port_t port,
344 uint32_t pins)
345 {
346 CORE_DECLARE_IRQ_STATE;
347
348 if (!SL_HAL_GPIO_PORT_IS_VALID(port)) {
349 EFM_ASSERT(false);
350 return SL_STATUS_INVALID_PARAMETER;
351 }
352
353 CORE_ENTER_ATOMIC();
354
355 sl_hal_gpio_set_port(port, pins);
356
357 CORE_EXIT_ATOMIC();
358 return SL_STATUS_OK;
359 }
360
361 /***************************************************************************//**
362 * Clears the selected pin on selected port.
363 ******************************************************************************/
sl_gpio_clear_port(sl_gpio_port_t port,uint32_t pins)364 sl_status_t sl_gpio_clear_port(sl_gpio_port_t port,
365 uint32_t pins)
366 {
367 CORE_DECLARE_IRQ_STATE;
368
369 if (!SL_HAL_GPIO_PORT_IS_VALID(port)) {
370 EFM_ASSERT(false);
371 return SL_STATUS_INVALID_PARAMETER;
372 }
373
374 CORE_ENTER_ATOMIC();
375
376 sl_hal_gpio_clear_port(port, pins);
377
378 CORE_EXIT_ATOMIC();
379 return SL_STATUS_OK;
380 }
381
382 /***************************************************************************//**
383 * Gets the output state of pins of selected port.
384 ******************************************************************************/
sl_gpio_get_port_output(sl_gpio_port_t port,uint32_t * port_value)385 sl_status_t sl_gpio_get_port_output(sl_gpio_port_t port,
386 uint32_t *port_value)
387 {
388 CORE_DECLARE_IRQ_STATE;
389
390 if (!SL_HAL_GPIO_PORT_IS_VALID(port)) {
391 EFM_ASSERT(false);
392 return SL_STATUS_INVALID_PARAMETER;
393 }
394 if (port_value == NULL) {
395 EFM_ASSERT(false);
396 return SL_STATUS_NULL_POINTER;
397 }
398
399 CORE_ENTER_ATOMIC();
400
401 *port_value = sl_hal_gpio_get_port_output(port);
402
403 CORE_EXIT_ATOMIC();
404 return SL_STATUS_OK;
405 }
406
407 /***************************************************************************//**
408 * Gets the input state of pins of selected port.
409 ******************************************************************************/
sl_gpio_get_port_input(sl_gpio_port_t port,uint32_t * port_value)410 sl_status_t sl_gpio_get_port_input(sl_gpio_port_t port,
411 uint32_t *port_value)
412 {
413 CORE_DECLARE_IRQ_STATE;
414
415 if (!SL_HAL_GPIO_PORT_IS_VALID(port)) {
416 EFM_ASSERT(false);
417 return SL_STATUS_INVALID_PARAMETER;
418 }
419 if (port_value == NULL) {
420 EFM_ASSERT(false);
421 return SL_STATUS_NULL_POINTER;
422 }
423
424 CORE_ENTER_ATOMIC();
425
426 *port_value = sl_hal_gpio_get_port_input(port);
427
428 CORE_EXIT_ATOMIC();
429 return SL_STATUS_OK;
430 }
431
432 /***************************************************************************//**
433 * Configuring the GPIO external pin interrupt.
434 * This API can be used to configure interrupt and to register the callback.
435 ******************************************************************************/
sl_gpio_configure_external_interrupt(const sl_gpio_t * gpio,int32_t * int_no,sl_gpio_interrupt_flag_t flags,sl_gpio_irq_callback_t gpio_callback,void * context)436 sl_status_t sl_gpio_configure_external_interrupt(const sl_gpio_t *gpio,
437 int32_t *int_no,
438 sl_gpio_interrupt_flag_t flags,
439 sl_gpio_irq_callback_t gpio_callback,
440 void *context)
441 {
442 uint32_t enabled_interrupts;
443 CORE_DECLARE_IRQ_STATE;
444
445 if (gpio == NULL || int_no == NULL) {
446 EFM_ASSERT(false);
447 return SL_STATUS_NULL_POINTER;
448 }
449 if (!SL_HAL_GPIO_PORT_PIN_IS_VALID(gpio->port, gpio->pin) && (gpio->port != SL_GPIO_PORT_INTERRUPT)) {
450 EFM_ASSERT(false);
451 return SL_STATUS_INVALID_PARAMETER;
452 }
453 if (!SL_GPIO_FLAG_IS_VALID(flags)) {
454 EFM_ASSERT(false);
455 return SL_STATUS_INVALID_PARAMETER;
456 }
457
458 CORE_ENTER_ATOMIC();
459
460 if (gpio->port != SL_GPIO_PORT_INTERRUPT) {
461 *int_no = sl_hal_gpio_configure_external_interrupt(gpio, *int_no, flags);
462 }
463
464 if (*int_no == SL_GPIO_INTERRUPT_UNAVAILABLE && gpio->port == SL_GPIO_PORT_INTERRUPT) {
465 enabled_interrupts = sl_hal_gpio_get_enabled_interrupts();
466 *int_no = sl_hal_gpio_get_external_interrupt_number(gpio->pin, enabled_interrupts);
467 }
468
469 if (*int_no != SL_GPIO_INTERRUPT_UNAVAILABLE) {
470 // Callback registration.
471 gpio_interrupts.callback_ext[*int_no].callback = (void *)gpio_callback;
472 gpio_interrupts.callback_ext[*int_no].context = context;
473
474 if (gpio->port != SL_GPIO_PORT_INTERRUPT) {
475 sl_hal_gpio_enable_interrupts(1 << *int_no);
476 }
477 } else {
478 CORE_EXIT_ATOMIC();
479 return SL_STATUS_NOT_FOUND;
480 }
481
482 CORE_EXIT_ATOMIC();
483 return SL_STATUS_OK;
484 }
485
486 /***************************************************************************//**
487 * Deconfigures the GPIO external pin interrupt.
488 * This API can be used to deconfigure the interrupt and to unregister the callback.
489 ******************************************************************************/
sl_gpio_deconfigure_external_interrupt(int32_t int_no)490 sl_status_t sl_gpio_deconfigure_external_interrupt(int32_t int_no)
491 {
492 CORE_DECLARE_IRQ_STATE;
493
494 if (!((int_no != SL_GPIO_INTERRUPT_UNAVAILABLE) && (int_no <= SL_HAL_GPIO_INTERRUPT_MAX) && (int_no >= 0))) {
495 EFM_ASSERT(false);
496 return SL_STATUS_INVALID_PARAMETER;
497 }
498
499 CORE_ENTER_ATOMIC();
500
501 // Clear pending interrupt.
502 sl_hal_gpio_clear_interrupts(1 << int_no);
503 sl_hal_gpio_disable_interrupts(1 << int_no);
504
505 // Callback deregistration.
506 gpio_interrupts.callback_ext[int_no].callback = NULL;
507 gpio_interrupts.callback_ext[int_no].context = NULL;
508
509 CORE_EXIT_ATOMIC();
510 return SL_STATUS_OK;
511 }
512
513 /***************************************************************************//**
514 * Enables one or more GPIO interrupts.
515 ******************************************************************************/
sl_gpio_enable_interrupts(uint32_t flags)516 sl_status_t sl_gpio_enable_interrupts(uint32_t flags)
517 {
518 CORE_DECLARE_IRQ_STATE;
519 CORE_ENTER_ATOMIC();
520
521 sl_hal_gpio_enable_interrupts(flags);
522
523 CORE_EXIT_ATOMIC();
524 return SL_STATUS_OK;
525 }
526
527 /***************************************************************************//**
528 * Disables one or more GPIO interrupts.
529 ******************************************************************************/
sl_gpio_disable_interrupts(uint32_t flags)530 sl_status_t sl_gpio_disable_interrupts(uint32_t flags)
531 {
532 CORE_DECLARE_IRQ_STATE;
533 CORE_ENTER_ATOMIC();
534
535 sl_hal_gpio_disable_interrupts(flags);
536
537 CORE_EXIT_ATOMIC();
538 return SL_STATUS_OK;
539 }
540
541 /***************************************************************************//**
542 * Configures the EM4WU pin as external level interrupts for waking up from EM mode.
543 * Registering/unregistering the callbacks and Configuring the EM4 interrupts to enable/disable
544 ******************************************************************************/
sl_gpio_configure_wakeup_em4_interrupt(const sl_gpio_t * gpio,int32_t * em4_int_no,bool polarity,sl_gpio_irq_callback_t gpio_callback,void * context)545 sl_status_t sl_gpio_configure_wakeup_em4_interrupt(const sl_gpio_t *gpio,
546 int32_t *em4_int_no,
547 bool polarity,
548 sl_gpio_irq_callback_t gpio_callback,
549 void *context)
550 {
551 CORE_DECLARE_IRQ_STATE;
552
553 if (gpio == NULL || em4_int_no == NULL) {
554 EFM_ASSERT(false);
555 return SL_STATUS_NULL_POINTER;
556 }
557
558 if (!SL_HAL_GPIO_PORT_PIN_IS_VALID(gpio->port, gpio->pin) && (gpio->port != SL_GPIO_PORT_INTERRUPT)) {
559 EFM_ASSERT(false);
560 return SL_STATUS_INVALID_PARAMETER;
561 }
562
563 CORE_ENTER_ATOMIC();
564
565 if (gpio->port != SL_GPIO_PORT_INTERRUPT) {
566 *em4_int_no = sl_hal_gpio_configure_wakeup_em4_external_interrupt(gpio, *em4_int_no, polarity);
567 }
568
569 if (*em4_int_no != SL_GPIO_INTERRUPT_UNAVAILABLE) {
570 // Callback registration.
571 gpio_interrupts.callback_em4[*em4_int_no].callback = (void *)gpio_callback;
572 gpio_interrupts.callback_em4[*em4_int_no].context = context;
573
574 if (gpio->port != SL_GPIO_PORT_INTERRUPT) {
575 sl_hal_gpio_enable_interrupts(1 << (*em4_int_no + SL_HAL_GPIO_EM4WUEN_SHIFT));
576 }
577 } else {
578 CORE_EXIT_ATOMIC();
579 return SL_STATUS_NOT_FOUND;
580 }
581
582 CORE_EXIT_ATOMIC();
583 return SL_STATUS_OK;
584 }
585
586 /***************************************************************************//**
587 * Deconfigures the EM4 GPIO pin interrupt.
588 * Unregisters a callback, disable/clear interrupt and clear em4 wakeup source
589 ******************************************************************************/
sl_gpio_deconfigure_wakeup_em4_interrupt(int32_t em4_int_no)590 sl_status_t sl_gpio_deconfigure_wakeup_em4_interrupt(int32_t em4_int_no)
591 {
592 CORE_DECLARE_IRQ_STATE;
593
594 if (!((em4_int_no != SL_GPIO_INTERRUPT_UNAVAILABLE) && (em4_int_no <= SL_HAL_GPIO_INTERRUPT_MAX) && (em4_int_no >= 0))) {
595 EFM_ASSERT(false);
596 return SL_STATUS_INVALID_PARAMETER;
597 }
598
599 CORE_ENTER_ATOMIC();
600
601 // Clear any pending interrupt.
602 sl_hal_gpio_clear_interrupts(1 << (em4_int_no + SL_HAL_GPIO_EM4WUEN_SHIFT));
603 sl_hal_gpio_disable_pin_em4_wakeup(1 << (em4_int_no + SL_HAL_GPIO_EM4WUEN_SHIFT));
604 sl_hal_gpio_disable_interrupts(1 << (em4_int_no + SL_HAL_GPIO_EM4WUEN_SHIFT));
605
606 /* Callback deregistration */
607 gpio_interrupts.callback_em4[em4_int_no].callback = NULL;
608 gpio_interrupts.callback_em4[em4_int_no].context = NULL;
609
610 CORE_EXIT_ATOMIC();
611 return SL_STATUS_OK;
612 }
613
614 /***************************************************************************//**
615 * Sets GPIO EM4 Wake up interrupt to Enable and EM4 Wake up interrupt polarity
616 ******************************************************************************/
sl_gpio_enable_pin_em4_wakeup(uint32_t em4_int_mask,uint32_t em4_polarity_mask)617 sl_status_t sl_gpio_enable_pin_em4_wakeup(uint32_t em4_int_mask,
618 uint32_t em4_polarity_mask)
619 {
620 uint32_t int_mask = 0;
621 uint32_t polarity_mask = 0;
622
623 CORE_DECLARE_IRQ_STATE;
624 CORE_ENTER_ATOMIC();
625
626 // Enable EM4WU function and set polarity.
627 int_mask |= (em4_int_mask << _GPIO_EM4WUEN_EM4WUEN_SHIFT);
628 polarity_mask |= (em4_polarity_mask << _GPIO_EM4WUEN_EM4WUEN_SHIFT);
629 sl_hal_gpio_enable_pin_em4_wakeup(int_mask, polarity_mask);
630
631 CORE_EXIT_ATOMIC();
632 return SL_STATUS_OK;
633 }
634
635 /***************************************************************************//**
636 * Clears GPIO EM4 Wake up enable
637 ******************************************************************************/
sl_gpio_disable_pin_em4_wakeup(uint32_t em4_int_mask)638 sl_status_t sl_gpio_disable_pin_em4_wakeup(uint32_t em4_int_mask)
639 {
640 uint32_t int_mask = 0;
641
642 CORE_DECLARE_IRQ_STATE;
643 CORE_ENTER_ATOMIC();
644
645 // Disable EM4WU function.
646 int_mask |= (em4_int_mask << _GPIO_EM4WUEN_EM4WUEN_SHIFT);
647 sl_hal_gpio_disable_pin_em4_wakeup(int_mask);
648
649 CORE_EXIT_ATOMIC();
650 return SL_STATUS_OK;
651 }
652
653 /***************************************************************************//**
654 * Enable GPIO pin retention of output enable, output value, pull direction, pull enable in EM4
655 ******************************************************************************/
sl_gpio_set_pin_em4_retention(bool enable)656 sl_status_t sl_gpio_set_pin_em4_retention(bool enable)
657 {
658 CORE_DECLARE_IRQ_STATE;
659 CORE_ENTER_ATOMIC();
660
661 sl_hal_gpio_set_pin_em4_retention(enable);
662
663 CORE_EXIT_ATOMIC();
664 return SL_STATUS_OK;
665 }
666
667 /***************************************************************************//**
668 * Sets slewrate for selected port.
669 ******************************************************************************/
sl_gpio_set_slew_rate(sl_gpio_port_t port,uint8_t slewrate)670 sl_status_t sl_gpio_set_slew_rate(sl_gpio_port_t port,
671 uint8_t slewrate)
672 {
673 CORE_DECLARE_IRQ_STATE;
674
675 if (!SL_HAL_GPIO_PORT_IS_VALID(port)) {
676 EFM_ASSERT(false);
677 return SL_STATUS_INVALID_PARAMETER;
678 }
679
680 CORE_ENTER_ATOMIC();
681
682 sl_hal_gpio_set_slew_rate(port, slewrate);
683
684 CORE_EXIT_ATOMIC();
685 return SL_STATUS_OK;
686 }
687
688 /***************************************************************************//**
689 * Gets slewrate for selected port.
690 ******************************************************************************/
sl_gpio_get_slew_rate(sl_gpio_port_t port,uint8_t * slewrate)691 sl_status_t sl_gpio_get_slew_rate(sl_gpio_port_t port,
692 uint8_t *slewrate)
693 {
694 CORE_DECLARE_IRQ_STATE;
695
696 if (!SL_HAL_GPIO_PORT_IS_VALID(port)) {
697 EFM_ASSERT(false);
698 return SL_STATUS_INVALID_PARAMETER;
699 }
700 if (slewrate == NULL) {
701 EFM_ASSERT(false);
702 return SL_STATUS_NULL_POINTER;
703 }
704
705 CORE_ENTER_ATOMIC();
706
707 *slewrate = sl_hal_gpio_get_slew_rate(port);
708
709 CORE_EXIT_ATOMIC();
710 return SL_STATUS_OK;
711 }
712
713 /***************************************************************************//**
714 * Locks the GPIO Configuration
715 ******************************************************************************/
sl_gpio_lock(void)716 sl_status_t sl_gpio_lock(void)
717 {
718 sl_hal_gpio_lock();
719 return SL_STATUS_OK;
720 }
721
722 /***************************************************************************//**
723 * Unlocks the GPIO Configuration
724 ******************************************************************************/
sl_gpio_unlock(void)725 sl_status_t sl_gpio_unlock(void)
726 {
727 sl_hal_gpio_unlock();
728 return SL_STATUS_OK;
729 }
730
731 /***************************************************************************//**
732 * Gets the GPIO State
733 ******************************************************************************/
sl_gpio_is_locked(bool * state)734 sl_status_t sl_gpio_is_locked(bool *state)
735 {
736 uint32_t status;
737 CORE_DECLARE_IRQ_STATE;
738
739 if (state == NULL) {
740 EFM_ASSERT(false);
741 return SL_STATUS_NULL_POINTER;
742 }
743
744 CORE_ENTER_ATOMIC();
745
746 status = sl_hal_gpio_get_lock_status();
747 if (status) {
748 // true - GPIO configuration registers are locked.
749 *state = true;
750 } else {
751 // false - GPIO configuration registers are unlocked.
752 *state = false;
753 }
754
755 CORE_EXIT_ATOMIC();
756 return SL_STATUS_OK;
757 }
758
759 /***************************************************************************//**
760 * Function calls users callback for registered pin interrupts.
761 *
762 * @details This function is called when GPIO interrupts are handled by the IRQHandlers.
763 * Function gets even or odd interrupt flags and calls user callback
764 * registered for that pin. Function iterates on flags starting from MSB.
765 *
766 * @param iflags Interrupt flags which shall be handled by the dispatcher.
767 ******************************************************************************/
sl_gpio_dispatch_interrupt(uint32_t iflags)768 static void sl_gpio_dispatch_interrupt(uint32_t iflags)
769 {
770 uint32_t irq_idx;
771 sl_gpio_callback_desc_t *callback;
772 sl_gpio_irq_callback_t func;
773
774 // Check for flags set in IF register.
775 while (iflags != 0) {
776 irq_idx = SL_CTZ(iflags);
777 iflags &= ~(1UL << irq_idx);
778
779 if (irq_idx <= SL_HAL_GPIO_INTERRUPT_MAX) {
780 callback = &gpio_interrupts.callback_ext[irq_idx];
781 } else {
782 callback = &gpio_interrupts.callback_em4[irq_idx - SL_HAL_GPIO_EM4WUEN_SHIFT];
783 irq_idx = irq_idx - SL_HAL_GPIO_EM4WUEN_SHIFT;
784 }
785 // Call user callback.
786 if (callback->callback) {
787 func = (sl_gpio_irq_callback_t)(callback->callback);
788 func((uint8_t)irq_idx, callback->context);
789 }
790 }
791 }
792
793 /***************************************************************************//**
794 * GPIO EVEN interrupt handler. Interrupt handler clears all IF even flags and
795 * call the dispatcher passing the flags which triggered the interrupt.
796 ******************************************************************************/
GPIO_EVEN_IRQHandler(void)797 void GPIO_EVEN_IRQHandler(void)
798 {
799 uint32_t even_flags;
800
801 // Gets all enabled and pending even interrupts.
802 even_flags = sl_hal_gpio_get_enabled_pending_interrupts() & SL_HAL_GPIO_INT_IF_EVEN_MASK;
803 // Clears only even interrupts.
804 sl_hal_gpio_clear_interrupts(even_flags);
805
806 sl_gpio_dispatch_interrupt(even_flags);
807 }
808
809 /***************************************************************************//**
810 * @brief
811 * GPIO ODD interrupt handler. Interrupt handler clears all IF odd flags and
812 * call the dispatcher passing the flags which triggered the interrupt.
813 ******************************************************************************/
GPIO_ODD_IRQHandler(void)814 void GPIO_ODD_IRQHandler(void)
815 {
816 uint32_t odd_flags;
817
818 // Gets all enabled and pending odd interrupts.
819 odd_flags = sl_hal_gpio_get_enabled_pending_interrupts() & SL_HAL_GPIO_INT_IF_ODD_MASK;
820 // Clears only odd interrupts.
821 sl_hal_gpio_clear_interrupts(odd_flags);
822
823 sl_gpio_dispatch_interrupt(odd_flags);
824 }
825