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