1 /***************************************************************************//**
2  * @file
3  * @brief General Purpose IO (GPIO) peripheral API
4  *******************************************************************************
5  * # License
6  * <b>Copyright 2018 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 #ifndef SL_HAL_GPIO_H
32 #define SL_HAL_GPIO_H
33 
34 #include "em_device.h"
35 
36 #if defined(GPIO_PRESENT)
37 
38 #ifdef __cplusplus
39 extern "C" {
40 #endif
41 
42 #include <stdbool.h>
43 #include <stddef.h>
44 #include "sl_assert.h"
45 #include "sl_device_gpio.h"
46 #include "sl_code_classification.h"
47 
48 /* *INDENT-OFF* */
49 // *****************************************************************************
50 /// @addtogroup gpio GPIO - General Purpose Input Output
51 /// @brief General Purpose Input Output peripheral
52 ///
53 /// @li @ref gpio_intro
54 ///
55 ///@n @section gpio_intro Introduction
56 ///  This module contains functions to control the GPIO peripheral of Silicon Labs 32-bit MCUs and SoCs.
57 ///  The GPIO peripheral is used for interrupt configuration, pin configuration and direct pin manipulation
58 ///  as well as routing for peripheral pin connections.
59 ///
60 /// @{
61 // *****************************************************************************
62 /* *INDENT-ON* */
63 
64 /*******************************************************************************
65  ********************************   DEFINES   **********************************
66  ******************************************************************************/
67 
68 /// Define for port specific pin mask
69 #if defined(GPIO_PA_MASK)
70 #define SL_HAL_GPIO_PORT_A_PIN_MASK (GPIO_PA_MASK)
71 #else
72 #define SL_HAL_GPIO_PORT_A_PIN_MASK 0
73 #endif
74 #if defined(GPIO_PB_MASK)
75 #define SL_HAL_GPIO_PORT_B_PIN_MASK (GPIO_PB_MASK)
76 #else
77 #define SL_HAL_GPIO_PORT_B_PIN_MASK 0
78 #endif
79 #if defined(GPIO_PC_MASK)
80 #define SL_HAL_GPIO_PORT_C_PIN_MASK (GPIO_PC_MASK)
81 #else
82 #define SL_HAL_GPIO_PORT_C_PIN_MASK 0
83 #endif
84 #if defined(GPIO_PD_MASK)
85 #define SL_HAL_GPIO_PORT_D_PIN_MASK (GPIO_PD_MASK)
86 #else
87 #define SL_HAL_GPIO_PORT_D_PIN_MASK 0
88 #endif
89 #if defined(GPIO_PE_MASK)
90 #define SL_HAL_GPIO_PORT_E_PIN_MASK (GPIO_PE_MASK)
91 #else
92 #define SL_HAL_GPIO_PORT_E_PIN_MASK 0
93 #endif
94 #if defined(GPIO_PF_MASK)
95 #define SL_HAL_GPIO_PORT_F_PIN_MASK (GPIO_PF_MASK)
96 #else
97 #define SL_HAL_GPIO_PORT_F_PIN_MASK 0
98 #endif
99 #if defined(GPIO_PG_MASK)
100 #define SL_HAL_GPIO_PORT_G_PIN_MASK (GPIO_PG_MASK)
101 #else
102 #define SL_HAL_GPIO_PORT_G_PIN_MASK 0
103 #endif
104 #if defined(GPIO_PH_MASK)
105 #define SL_HAL_GPIO_PORT_H_PIN_MASK (GPIO_PH_MASK)
106 #else
107 #define SL_HAL_GPIO_PORT_H_PIN_MASK 0
108 #endif
109 #if defined(GPIO_PI_MASK)
110 #define SL_HAL_GPIO_PORT_I_PIN_MASK (GPIO_PI_MASK)
111 #else
112 #define SL_HAL_GPIO_PORT_I_PIN_MASK 0
113 #endif
114 #if defined(GPIO_PJ_MASK)
115 #define SL_HAL_GPIO_PORT_J_PIN_MASK (GPIO_PJ_MASK)
116 #else
117 #define SL_HAL_GPIO_PORT_J_PIN_MASK 0
118 #endif
119 #if defined(GPIO_PK_MASK)
120 #define SL_HAL_GPIO_PORT_K_PIN_MASK (GPIO_PK_MASK)
121 #else
122 #define SL_HAL_GPIO_PORT_K_PIN_MASK 0
123 #endif
124 
125 /// Define for port specific pin count
126 #if defined(GPIO_PA_COUNT)
127 #define SL_HAL_GPIO_PORT_A_PIN_COUNT (GPIO_PA_COUNT)
128 #else
129 #define SL_HAL_GPIO_PORT_A_PIN_COUNT 0
130 #endif
131 #if defined(GPIO_PB_COUNT)
132 #define SL_HAL_GPIO_PORT_B_PIN_COUNT (GPIO_PB_COUNT)
133 #else
134 #define SL_HAL_GPIO_PORT_B_PIN_COUNT 0
135 #endif
136 #if defined(GPIO_PC_COUNT)
137 #define SL_HAL_GPIO_PORT_C_PIN_COUNT (GPIO_PC_COUNT)
138 #else
139 #define SL_HAL_GPIO_PORT_C_PIN_COUNT 0
140 #endif
141 #if defined(GPIO_PD_COUNT)
142 #define SL_HAL_GPIO_PORT_D_PIN_COUNT (GPIO_PD_COUNT)
143 #else
144 #define SL_HAL_GPIO_PORT_D_PIN_COUNT 0
145 #endif
146 #if defined(GPIO_PE_COUNT)
147 #define SL_HAL_GPIO_PORT_E_PIN_COUNT (GPIO_PE_COUNT)
148 #else
149 #define SL_HAL_GPIO_PORT_E_PIN_COUNT 0
150 #endif
151 #if defined(GPIO_PF_COUNT)
152 #define SL_HAL_GPIO_PORT_F_PIN_COUNT (GPIO_PF_COUNT)
153 #else
154 #define SL_HAL_GPIO_PORT_F_PIN_COUNT 0
155 #endif
156 #if defined(GPIO_PG_COUNT)
157 #define SL_HAL_GPIO_PORT_G_PIN_COUNT (GPIO_PG_COUNT)
158 #else
159 #define SL_HAL_GPIO_PORT_G_PIN_COUNT 0
160 #endif
161 #if defined(GPIO_PH_COUNT)
162 #define SL_HAL_GPIO_PORT_H_PIN_COUNT (GPIO_PH_COUNT)
163 #else
164 #define SL_HAL_GPIO_PORT_H_PIN_COUNT 0
165 #endif
166 #if defined(GPIO_PI_COUNT)
167 #define SL_HAL_GPIO_PORT_I_PIN_COUNT (GPIO_PI_COUNT)
168 #else
169 #define SL_HAL_GPIO_PORT_I_PIN_COUNT 0
170 #endif
171 #if defined(GPIO_PJ_COUNT)
172 #define SL_HAL_GPIO_PORT_J_PIN_COUNT (GPIO_PJ_COUNT)
173 #else
174 #define SL_HAL_GPIO_PORT_J_PIN_COUNT 0
175 #endif
176 #if defined(GPIO_PK_COUNT)
177 #define SL_HAL_GPIO_PORT_K_PIN_COUNT (GPIO_PK_COUNT)
178 #else
179 #define SL_HAL_GPIO_PORT_K_PIN_COUNT 0
180 #endif
181 
182 /// @cond DO_NOT_INCLUDE_WITH_DOXYGEN
183 
184 /// Highest GPIO port number.
185 
186 #if (SL_HAL_GPIO_PORT_K_PIN_COUNT > 0)
187 #define SL_HAL_GPIO_PORT_MAX  10
188 #elif (SL_HAL_GPIO_PORT_J_PIN_COUNT > 0)
189 #define SL_HAL_GPIO_PORT_MAX  9
190 #elif (SL_HAL_GPIO_PORT_I_PIN_COUNT > 0)
191 #define SL_HAL_GPIO_PORT_MAX  8
192 #elif (SL_HAL_GPIO_PORT_H_PIN_COUNT > 0)
193 #define SL_HAL_GPIO_PORT_MAX  7
194 #elif (SL_HAL_GPIO_PORT_G_PIN_COUNT > 0)
195 #define SL_HAL_GPIO_PORT_MAX  6
196 #elif (SL_HAL_GPIO_PORT_F_PIN_COUNT > 0)
197 #define SL_HAL_GPIO_PORT_MAX  5
198 #elif (SL_HAL_GPIO_PORT_E_PIN_COUNT > 0)
199 #define SL_HAL_GPIO_PORT_MAX  4
200 #elif (SL_HAL_GPIO_PORT_D_PIN_COUNT > 0)
201 #define SL_HAL_GPIO_PORT_MAX  3
202 #elif (SL_HAL_GPIO_PORT_C_PIN_COUNT > 0)
203 #define SL_HAL_GPIO_PORT_MAX  2
204 #elif (SL_HAL_GPIO_PORT_B_PIN_COUNT > 0)
205 #define SL_HAL_GPIO_PORT_MAX  1
206 #elif (SL_HAL_GPIO_PORT_A_PIN_COUNT > 0)
207 #define SL_HAL_GPIO_PORT_MAX  0
208 #else
209 #error "Max GPIO port number is undefined for this part."
210 #endif
211 
212 /// Highest GPIO pin number.
213 #define SL_HAL_GPIO_PIN_MAX 15
214 
215 /// @endcond
216 
217 #define SL_HAL_GPIO_PORT_SIZE(port) (             \
218     (port) == 0  ? SL_HAL_GPIO_PORT_A_PIN_COUNT   \
219     : (port) == 1  ? SL_HAL_GPIO_PORT_B_PIN_COUNT \
220     : (port) == 2  ? SL_HAL_GPIO_PORT_C_PIN_COUNT \
221     : (port) == 3  ? SL_HAL_GPIO_PORT_D_PIN_COUNT \
222     : (port) == 4  ? SL_HAL_GPIO_PORT_E_PIN_COUNT \
223     : (port) == 5  ? SL_HAL_GPIO_PORT_F_PIN_COUNT \
224     : (port) == 6  ? SL_HAL_GPIO_PORT_G_PIN_COUNT \
225     : (port) == 7  ? SL_HAL_GPIO_PORT_H_PIN_COUNT \
226     : (port) == 8  ? SL_HAL_GPIO_PORT_I_PIN_COUNT \
227     : (port) == 9  ? SL_HAL_GPIO_PORT_J_PIN_COUNT \
228     : (port) == 10 ? SL_HAL_GPIO_PORT_K_PIN_COUNT \
229     : 0)
230 
231 #define SL_HAL_GPIO_PORT_MASK(port) (                 \
232     ((int)port) == 0  ? SL_HAL_GPIO_PORT_A_PIN_MASK   \
233     : ((int)port) == 1  ? SL_HAL_GPIO_PORT_B_PIN_MASK \
234     : ((int)port) == 2  ? SL_HAL_GPIO_PORT_C_PIN_MASK \
235     : ((int)port) == 3  ? SL_HAL_GPIO_PORT_D_PIN_MASK \
236     : ((int)port) == 4  ? SL_HAL_GPIO_PORT_E_PIN_MASK \
237     : ((int)port) == 5  ? SL_HAL_GPIO_PORT_F_PIN_MASK \
238     : ((int)port) == 6  ? SL_HAL_GPIO_PORT_G_PIN_MASK \
239     : ((int)port) == 7  ? SL_HAL_GPIO_PORT_H_PIN_MASK \
240     : ((int)port) == 8  ? SL_HAL_GPIO_PORT_I_PIN_MASK \
241     : ((int)port) == 9  ? SL_HAL_GPIO_PORT_J_PIN_MASK \
242     : ((int)port) == 10 ? SL_HAL_GPIO_PORT_K_PIN_MASK \
243     : 0UL)
244 
245 /// Validation of port.
246 #define SL_HAL_GPIO_PORT_IS_VALID(port)          (SL_HAL_GPIO_PORT_MASK(port) != 0x0UL)
247 
248 /// Validation of port and pin.
249 #define SL_HAL_GPIO_PORT_PIN_IS_VALID(port, pin) ((((SL_HAL_GPIO_PORT_MASK(port)) >> (pin)) & 0x1UL) == 0x1UL)
250 
251 /// Max interrupt lines for external and EM4 interrupts.
252 #define SL_HAL_GPIO_INTERRUPT_MAX 15
253 
254 /// Shift value for EM4WUEN
255 #define SL_HAL_GPIO_EM4WUEN_SHIFT _GPIO_EM4WUEN_EM4WUEN_SHIFT
256 
257 /// Masks for even and odd interrupt bits.
258 #define SL_HAL_GPIO_INT_IF_EVEN_MASK ((_GPIO_IF_MASK) & 0x55555555UL)
259 #define SL_HAL_GPIO_INT_IF_ODD_MASK  ((_GPIO_IF_MASK) & 0xAAAAAAAAUL)
260 
261 /// Validation of mode.
262 #define SL_HAL_GPIO_MODE_IS_VALID(mode)  ((mode & _GPIO_P_MODEL_MODE0_MASK) == mode)
263 
264 /// Validation of interrupt number and pin.
265 #define SL_HAL_GPIO_INTNO_PIN_VALID(int_no, pin)    (((int_no) & ~_GPIO_EXTIPINSELL_EXTIPINSEL0_MASK) == ((pin) & ~_GPIO_EXTIPINSELL_EXTIPINSEL0_MASK))
266 
267 /*******************************************************************************
268  ********************************   ENUMS   ************************************
269  ******************************************************************************/
270 
271 /*******************************************************************************
272  *****************************   PROTOTYPES   **********************************
273  ******************************************************************************/
274 
275 /***************************************************************************//**
276  * Set the mode for a GPIO pin.
277  *
278  * @param[in] gpio Pointer to GPIO structure with port and pin
279  * @param[in] mode The desired pin mode.
280  * @param[in] output_value A value to set for the pin in the DOUT register. The DOUT setting is important for
281  *                         some input mode configurations to determine the pull-up/down direction.
282  ******************************************************************************/
283 void sl_hal_gpio_set_pin_mode(const sl_gpio_t *gpio,
284                               sl_gpio_mode_t mode,
285                               bool output_value);
286 
287 /***************************************************************************//**
288  * Get the mode for a GPIO pin.
289  *
290  * @param[in] gpio Pointer to GPIO structure with port and pin
291  *
292  * @return Return the pin mode.
293  ******************************************************************************/
294 sl_gpio_mode_t sl_hal_gpio_get_pin_mode(const sl_gpio_t *gpio);
295 
296 /***************************************************************************//**
297  * Configure the GPIO external pin interrupt by connecting external interrupt id with gpio pin.
298  *
299  * @note This function configure the pin interrupt with pin ,port and external interrupt id as input.
300  *       If external interrupt id is provided as input it will be considered as the input or else
301  *       available interrupt number will be generated by looping through the interrupt group and will be used.
302  *       User can provide SL_HAL_GPIO_INTERRUPT_UNAVAILABLE if user don't want to provide interrupt id.
303  * @note the pin number can be selected freely within a group.
304  *       Interrupt numbers are divided into 4 groups (int_no / 4) and valid pin
305  *       number within the interrupt groups are:
306  *       0: pins 0-3   (interrupt number 0-3)
307  *       1: pins 4-7   (interrupt number 4-7)
308  *       2: pins 8-11  (interrupt number 8-11)
309  *       3: pins 12-15 (interrupt number 12-15)
310  * @note It is recommended to disable interrupts before configuring the GPIO pin interrupt.
311  *       See @ref sl_hal_gpio_disable_interrupts() for more information.
312  *       The GPIO interrupt handler must be in place before enabling the interrupt.
313  *       Notice that any pending interrupt for the selected interrupt is cleared by this function.
314  *       Notice that only interrupt will be configured by this function. It is not enabled.
315  *       It is recommended to enable interrupts after configuring the GPIO pin interrupt if needed.
316  *       See @ref sl_hal_gpio_enable_interrupts() for more information.
317  *
318  * @param[in] gpio Pointer to GPIO structure with port and pin
319  * @param[in] int_no The interrupt number to trigger.
320  * @param[in] flags Interrupt configuration flags. @ref sl_hal_gpio_interrupt_flag_t for more information.
321  *
322  * @return Return the available interrupt number
323  ******************************************************************************/
324 int32_t sl_hal_gpio_configure_external_interrupt(const sl_gpio_t *gpio,
325                                                  int32_t int_no,
326                                                  sl_gpio_interrupt_flag_t flags);
327 
328 /**************************************************************************//**
329  * Enable GPIO pin wake-up from EM4. When the function exits,
330  * EM4 mode can be safely entered.
331  *
332  * @note It is assumed that the GPIO pin modes are set correctly.
333  *       Valid modes are SL_GPIO_MODE_INPUT and SL_GPIO_MODE_INPUT_PULL.
334  *
335  * @param[in] pinmask A bitmask containing the bitwise logic OR of which GPIO pin(s) to enable.
336  * @param[in] polaritymask A bitmask containing the bitwise logic OR of GPIO pin(s) wake-up polarity.
337  *****************************************************************************/
338 void sl_hal_gpio_enable_pin_em4_wakeup(uint32_t pinmask,
339                                        uint32_t polaritymask);
340 
341 /***************************************************************************//**
342  * Configure EM4WU pins as external level-sensitive interrupts.
343  *
344  * @note It is recommended to disable interrupts before configuring the GPIO pin interrupt.
345  *       See @ref sl_hal_gpio_disable_interrupts() for more information.
346  *       The provided port, pin and int_no inputs should be valid EM4 related parameters
347  *       because there are dedicated port, pin and EM4 Wakeup interrupt combination for
348  *       configuring the port, pin for EM4 functionality.
349  *       User can provide SL_HAL_GPIO_INTERRUPT_UNAVAILABLE if user don't want to provide interrupt id.
350  *       The GPIO interrupt handler must be in place before enabling the interrupt.
351  *       Notice that any pending interrupt for the selected interrupt is cleared by this function.
352  *       Notice that any only EM4WU interrupt is configured by this function. It is not enabled.
353  *       It is recommended to enable interrupts after configuring the GPIO pin interrupt if needed.
354  *       See @ref sl_hal_gpio_enable_interrupts() for more information.
355  *
356  * @param[in] gpio Pointer to GPIO structure with port and pin
357  * @param[in] int_no The EM4WU interrupt number to trigger.
358  * @param[in] polarity true = Active high level-sensitive interrupt.
359  *                     false = Active low level-sensitive interrupt.
360  *
361  * @return Return the available EM4WU interrupt number
362  ******************************************************************************/
363 int32_t sl_hal_gpio_configure_wakeup_em4_external_interrupt(const sl_gpio_t *gpio,
364                                                             int32_t int_no,
365                                                             bool polarity);
366 
367 /***************************************************************************//**
368  * Lock the GPIO configuration.
369  *
370  * @note Configuration lock affects the GPIO_Px_MODEL, GPIO_Px_MODEH, GPIO_Px_CTRL,
371  *       GPIO_Px_PINLOCKN, GPIO_EXTIPSELL, GPIO_EXTIPSELH, GPIO_EXTIPINSELL,
372  *       GPIO_EXTIPINSELH, GPIO_INSENSE, GPIO_ROUTE, GPIO_ROUTEPEN, and
373  *       GPIO_ROUTELOC0 registers when they are present on a specific device.
374  * @note Unwanted or accidental changes to GPIO configuration can be avoided by
375  *       using the configuration lock register. Any value other than 0xA534 written to
376  *       GPIO_LOCK enables the configuration lock. Pins are unlocked by a reset or
377  *       by writing 0xA534 to the GPIO_LOCK register.
378  ******************************************************************************/
sl_hal_gpio_lock(void)379 __INLINE void sl_hal_gpio_lock(void)
380 {
381   GPIO->LOCK = ~GPIO_LOCK_LOCKKEY_UNLOCK;
382 }
383 
384 /***************************************************************************//**
385  * Unlock the GPIO configuration.
386  *
387  * @note Configuration lock affects the GPIO_Px_MODEL, GPIO_Px_MODEH, GPIO_Px_CTRL,
388  *       GPIO_Px_PINLOCKN, GPIO_EXTIPSELL, GPIO_EXTIPSELH, GPIO_EXTIPINSELL,
389  *       GPIO_EXTIPINSELH, GPIO_INSENSE, GPIO_ROUTE, GPIO_ROUTEPEN, and
390  *       GPIO_ROUTELOC0 registers when they are present on a specific device.
391  * @note Unwanted or accidental changes to GPIO configuration can be avoided by
392  *       using the configuration lock register. Any value other than 0xA534 written to
393  *       GPIO_LOCK enables the configuration lock. Pins are unlocked by a reset or
394  *       by writing 0xA534 to the GPIO_LOCK register.
395  ******************************************************************************/
sl_hal_gpio_unlock(void)396 __INLINE void sl_hal_gpio_unlock(void)
397 {
398   GPIO->LOCK = GPIO_LOCK_LOCKKEY_UNLOCK;
399 }
400 
401 /***************************************************************************//**
402  * Gets the GPIO configuration state.
403  *
404  * @return Return the GPIO lock state.
405  ******************************************************************************/
sl_hal_gpio_get_lock_status(void)406 __INLINE uint32_t sl_hal_gpio_get_lock_status(void)
407 {
408   return GPIO->GPIOLOCKSTATUS;
409 }
410 
411 /***************************************************************************//**
412  * Set a single pin in GPIO data out register to 1.
413  *
414  * @param[in] gpio Pointer to GPIO structure with port and pin
415  ******************************************************************************/
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_HAL_GPIO,SL_CODE_CLASS_TIME_CRITICAL)416 SL_CODE_CLASSIFY(SL_CODE_COMPONENT_HAL_GPIO, SL_CODE_CLASS_TIME_CRITICAL)
417 __INLINE void sl_hal_gpio_set_pin(const sl_gpio_t *gpio)
418 {
419   EFM_ASSERT(gpio != NULL);
420   EFM_ASSERT(SL_HAL_GPIO_PORT_PIN_IS_VALID(gpio->port, gpio->pin));
421 
422   GPIO->P_SET[gpio->port].DOUT = 1UL << gpio->pin;
423 }
424 
425 /***************************************************************************//**
426  * Set bits GPIO data out register to 1.
427  *
428  * @param[in] port The GPIO port to access.
429  * @param[in] pins Bit mask for bits to set to 1 in DOUT register.
430  ******************************************************************************/
sl_hal_gpio_set_port(sl_gpio_port_t port,uint32_t pins)431 __INLINE void sl_hal_gpio_set_port(sl_gpio_port_t port,
432                                    uint32_t pins)
433 {
434   EFM_ASSERT(SL_HAL_GPIO_PORT_IS_VALID(port));
435   GPIO->P_SET[port].DOUT = pins;
436 }
437 
438 /***************************************************************************//**
439  * Set GPIO port data out register.
440  *
441  * @param[in] port The GPIO port to access.
442  * @param[in] val Value to write to port data out register.
443  * @param[in] mask Mask indicating which bits to modify.
444  ******************************************************************************/
sl_hal_gpio_set_port_value(sl_gpio_port_t port,uint32_t val,uint32_t mask)445 __INLINE void sl_hal_gpio_set_port_value(sl_gpio_port_t port,
446                                          uint32_t val,
447                                          uint32_t mask)
448 {
449   EFM_ASSERT(SL_HAL_GPIO_PORT_IS_VALID(port));
450   GPIO->P[port].DOUT = (GPIO->P[port].DOUT & ~mask) | (val & mask);
451 }
452 
453 /***************************************************************************//**
454  * Set slewrate for pins on a GPIO port which are configured into normal modes.
455  *
456  * @param[in] port The GPIO port to configure.
457  * @param[in] slewrate The slewrate to configure for pins on this GPIO port.
458  ******************************************************************************/
sl_hal_gpio_set_slew_rate(sl_gpio_port_t port,uint8_t slewrate)459 __INLINE void sl_hal_gpio_set_slew_rate(sl_gpio_port_t port,
460                                         uint8_t slewrate)
461 {
462   EFM_ASSERT(SL_HAL_GPIO_PORT_IS_VALID(port));
463   EFM_ASSERT(slewrate <= (_GPIO_P_CTRL_SLEWRATE_MASK
464                           >> _GPIO_P_CTRL_SLEWRATE_SHIFT));
465 
466   GPIO->P[port].CTRL = (GPIO->P[port].CTRL
467                         & ~_GPIO_P_CTRL_SLEWRATE_MASK)
468                        | (slewrate << _GPIO_P_CTRL_SLEWRATE_SHIFT);
469 }
470 
471 /***************************************************************************//**
472  * Set slewrate for pins on a GPIO port which are configured into alternate modes.
473  *
474  * @param[in] port The GPIO port to configure.
475  * @param[in] slewrate_alt The slewrate to configure for pins using alternate modes on this GPIO port.
476  ******************************************************************************/
sl_hal_gpio_set_slew_rate_alternate(sl_gpio_port_t port,uint8_t slewrate_alt)477 __INLINE void sl_hal_gpio_set_slew_rate_alternate(sl_gpio_port_t port,
478                                                   uint8_t slewrate_alt)
479 {
480   EFM_ASSERT(SL_HAL_GPIO_PORT_IS_VALID(port));
481   EFM_ASSERT(slewrate_alt <= (_GPIO_P_CTRL_SLEWRATEALT_MASK
482                               >> _GPIO_P_CTRL_SLEWRATEALT_SHIFT));
483 
484   GPIO->P[port].CTRL = (GPIO->P[port].CTRL
485                         & ~_GPIO_P_CTRL_SLEWRATEALT_MASK)
486                        | (slewrate_alt << _GPIO_P_CTRL_SLEWRATEALT_SHIFT);
487 }
488 
489 /***************************************************************************//**
490  * Get slewrate for pins on a GPIO port.
491  *
492  * @param[in] port The GPIO port to access to get slew rate.
493  *
494  * @return Return the slewrate setting for the selected GPIO port.
495  ******************************************************************************/
sl_hal_gpio_get_slew_rate(sl_gpio_port_t port)496 __INLINE uint8_t sl_hal_gpio_get_slew_rate(sl_gpio_port_t port)
497 {
498   EFM_ASSERT(SL_HAL_GPIO_PORT_IS_VALID(port));
499 
500   return (GPIO->P[port].CTRL & _GPIO_P_CTRL_SLEWRATE_MASK) >> _GPIO_P_CTRL_SLEWRATE_SHIFT;
501 }
502 
503 /***************************************************************************//**
504  * Get slewrate for pins on a GPIO port which are configured into alternate modes.
505  *
506  * @param[in] port The GPIO port to access to get slew rate.
507  *
508  * @return Return the alternate slewrate setting for selected GPIO port.
509  ******************************************************************************/
sl_hal_gpio_get_slew_rate_alternate(sl_gpio_port_t port)510 __INLINE uint8_t sl_hal_gpio_get_slew_rate_alternate(sl_gpio_port_t port)
511 {
512   EFM_ASSERT(SL_HAL_GPIO_PORT_IS_VALID(port));
513 
514   return (GPIO->P[port].CTRL & _GPIO_P_CTRL_SLEWRATEALT_MASK) >> _GPIO_P_CTRL_SLEWRATEALT_SHIFT;
515 }
516 
517 /***************************************************************************//**
518  * Set a single pin in GPIO data out port register to 0.
519  *
520  * @param[in] gpio Pointer to GPIO structure with port and pin
521  ******************************************************************************/
sl_hal_gpio_clear_pin(const sl_gpio_t * gpio)522 __INLINE void sl_hal_gpio_clear_pin(const sl_gpio_t *gpio)
523 {
524   EFM_ASSERT(gpio != NULL);
525   EFM_ASSERT(SL_HAL_GPIO_PORT_PIN_IS_VALID(gpio->port, gpio->pin));
526 
527   GPIO->P_CLR[gpio->port].DOUT = 1UL << gpio->pin;
528 }
529 
530 /***************************************************************************//**
531  * Set bits in DOUT register for a port to 0.
532  *
533  * @param[in] port The GPIO port to access.
534  * @param[in] pins Bit mask for bits to clear in DOUT register.
535  ******************************************************************************/
sl_hal_gpio_clear_port(sl_gpio_port_t port,uint32_t pins)536 __INLINE void sl_hal_gpio_clear_port(sl_gpio_port_t port,
537                                      uint32_t pins)
538 {
539   EFM_ASSERT(SL_HAL_GPIO_PORT_IS_VALID(port));
540 
541   GPIO->P_CLR[port].DOUT = pins;
542 }
543 
544 /***************************************************************************//**
545  * Read the pad value for a single pin in a GPIO port.
546  *
547  * @param[in] gpio Pointer to GPIO structure with port and pin.
548  *
549  * @return The pin value, 0 or 1.
550  ******************************************************************************/
sl_hal_gpio_get_pin_input(const sl_gpio_t * gpio)551 __INLINE bool sl_hal_gpio_get_pin_input(const sl_gpio_t *gpio)
552 {
553   EFM_ASSERT(gpio != NULL);
554   EFM_ASSERT(SL_HAL_GPIO_PORT_PIN_IS_VALID(gpio->port, gpio->pin));
555 
556   bool pin_input = ((GPIO->P[gpio->port].DIN) >> gpio->pin) & 1UL;
557 
558   return pin_input;
559 }
560 
561 /***************************************************************************//**
562  * Get current setting for a pin in a GPIO port data out register.
563  *
564  * @param[in] gpio Pointer to GPIO structure with port and pin.
565  *
566  * @return The DOUT setting for the requested pin, 0 or 1.
567  ******************************************************************************/
sl_hal_gpio_get_pin_output(const sl_gpio_t * gpio)568 __INLINE bool sl_hal_gpio_get_pin_output(const sl_gpio_t *gpio)
569 {
570   EFM_ASSERT(gpio != NULL);
571   EFM_ASSERT(SL_HAL_GPIO_PORT_PIN_IS_VALID(gpio->port, gpio->pin));
572 
573   bool pin_output = ((GPIO->P[gpio->port].DOUT) >> gpio->pin) & 1UL;
574 
575   return pin_output;
576 }
577 
578 /***************************************************************************//**
579  * Read the pad values for GPIO port.
580  *
581  * @param[in] port The GPIO port to access.
582  *
583  * @return The pad values for the GPIO port.
584  ******************************************************************************/
sl_hal_gpio_get_port_input(sl_gpio_port_t port)585 __INLINE uint32_t sl_hal_gpio_get_port_input(sl_gpio_port_t port)
586 {
587   EFM_ASSERT(SL_HAL_GPIO_PORT_IS_VALID(port));
588 
589   return GPIO->P[port].DIN;
590 }
591 
592 /***************************************************************************//**
593  * Get current setting for a GPIO port data out register.
594  *
595  * @param[in] port The GPIO port to access.
596  *
597  * @return The data out setting for the requested port.
598  ******************************************************************************/
sl_hal_gpio_get_port_output(sl_gpio_port_t port)599 __INLINE uint32_t sl_hal_gpio_get_port_output(sl_gpio_port_t port)
600 {
601   EFM_ASSERT(SL_HAL_GPIO_PORT_IS_VALID(port));
602 
603   return GPIO->P[port].DOUT;
604 }
605 
606 /***************************************************************************//**
607  * Toggle a single pin in GPIO port data out register.
608  *
609  * @param[in] gpio Pointer to GPIO structure with port and pin.
610  ******************************************************************************/
sl_hal_gpio_toggle_pin(const sl_gpio_t * gpio)611 __INLINE void sl_hal_gpio_toggle_pin(const sl_gpio_t *gpio)
612 {
613   EFM_ASSERT(gpio != NULL);
614   EFM_ASSERT(SL_HAL_GPIO_PORT_PIN_IS_VALID(gpio->port, gpio->pin));
615 
616   GPIO->P_TGL[gpio->port].DOUT = 1UL << gpio->pin;
617 }
618 
619 /***************************************************************************//**
620  * Toggle pins in GPIO port data out register.
621  *
622  * @param[in] port The GPIO port to access.
623  * @param[in] pins Bit mask with pins to toggle.
624  ******************************************************************************/
sl_hal_gpio_toggle_port(sl_gpio_port_t port,uint32_t pins)625 __INLINE void sl_hal_gpio_toggle_port(sl_gpio_port_t port,
626                                       uint32_t pins)
627 {
628   EFM_ASSERT(SL_HAL_GPIO_PORT_IS_VALID(port));
629 
630   GPIO->P_TGL[port].DOUT = pins;
631 }
632 
633 /***************************************************************************//**
634  * Enable one or more GPIO interrupts.
635  *
636  * @param[in] flags GPIO interrupt sources to enable.
637  ******************************************************************************/
sl_hal_gpio_enable_interrupts(uint32_t flags)638 __INLINE void sl_hal_gpio_enable_interrupts(uint32_t flags)
639 {
640   GPIO->IEN_SET = flags;
641 }
642 
643 /***************************************************************************//**
644  * Disable one or more GPIO interrupts.
645  *
646  * @param[in] flags GPIO interrupt sources to disable.
647  ******************************************************************************/
sl_hal_gpio_disable_interrupts(uint32_t flags)648 __INLINE void sl_hal_gpio_disable_interrupts(uint32_t flags)
649 {
650   GPIO->IEN_CLR = flags;
651 }
652 
653 /***************************************************************************//**
654  * Clear one or more pending GPIO interrupts.
655  *
656  * @param[in] flags Bitwise logic OR of GPIO interrupt sources to clear.
657  ******************************************************************************/
sl_hal_gpio_clear_interrupts(uint32_t flags)658 __INLINE void sl_hal_gpio_clear_interrupts(uint32_t flags)
659 {
660   GPIO->IF_CLR = flags;
661 }
662 
663 /**************************************************************************//**
664  * Set one or more pending GPIO interrupts from SW.
665  *
666  * @param[in] flags GPIO interrupt sources to set to pending.
667  *****************************************************************************/
sl_hal_gpio_set_interrupts(uint32_t flags)668 __INLINE void sl_hal_gpio_set_interrupts(uint32_t flags)
669 {
670   GPIO->IF_SET = flags;
671 }
672 
673 /***************************************************************************//**
674  * Get pending GPIO interrupts.
675  *
676  * @return GPIO interrupt sources pending.
677  ******************************************************************************/
sl_hal_gpio_get_pending_interrupts(void)678 __INLINE uint32_t sl_hal_gpio_get_pending_interrupts(void)
679 {
680   return GPIO->IF;
681 }
682 
683 /***************************************************************************//**
684  * Get enabled GPIO interrupts.
685  *
686  * @return Enabled GPIO interrupt sources.
687  ******************************************************************************/
sl_hal_gpio_get_enabled_interrupts(void)688 __INLINE uint32_t sl_hal_gpio_get_enabled_interrupts(void)
689 {
690   return GPIO->IEN;
691 }
692 
693 /***************************************************************************//**
694  * Get enabled and pending GPIO interrupt flags.
695  *
696  * @return Enabled and pending interrupt sources.
697  *
698  * @note Useful for handling more interrupt sources in the same interrupt handler.
699  ******************************************************************************/
sl_hal_gpio_get_enabled_pending_interrupts(void)700 __INLINE uint32_t sl_hal_gpio_get_enabled_pending_interrupts(void)
701 {
702   uint32_t tmp;
703 
704   tmp = GPIO->IEN;
705 
706   return GPIO->IF & tmp;
707 }
708 
709 /***************************************************************************//**
710  * The available external interrupt number getter.
711  *
712  * @param[in] pin  The GPIO pin to access.
713  * @param[in] enabled_interrupts_mask Contains enabled GPIO interrupts mask.
714  *
715  * @return  The available interrupt number based on interrupt and pin grouping.
716  ******************************************************************************/
sl_hal_gpio_get_external_interrupt_number(uint8_t pin,uint32_t enabled_interrupts_mask)717 __INLINE int32_t sl_hal_gpio_get_external_interrupt_number(uint8_t pin,
718                                                            uint32_t enabled_interrupts_mask)
719 {
720   uint32_t interrupt_to_check;
721   uint32_t int_group_start = (pin & 0xFFC);
722   int32_t int_no = -1;
723   // loop through the interrupt group, starting
724   // from the pin number, and take
725   // the first available.
726   for (uint8_t i = 0; i < 4; i++) {
727     interrupt_to_check = int_group_start + ((pin + i) & 0x3);     // modulo 4
728     if (((enabled_interrupts_mask >> interrupt_to_check) & 0x1) == 0) {
729       int_no = interrupt_to_check;
730       break;
731     }
732   }
733   return int_no;
734 }
735 
736 /***************************************************************************//**
737  * The available em4 wakeup interrupt number getter.
738  *
739  * @param[in] gpio Pointer to GPIO structure with port and pin.
740  *
741  * @return The available em4 wakeup interrupt number based on associated port and pin.
742  ******************************************************************************/
sl_hal_gpio_get_em4_interrupt_number(const sl_gpio_t * gpio)743 __INLINE int32_t sl_hal_gpio_get_em4_interrupt_number(const sl_gpio_t *gpio)
744 {
745   EFM_ASSERT(gpio != NULL);
746   int32_t em4_int_no;
747 
748   if (false) {
749     // Check all the EM4WU Pins and check if given port, pin matches any of them.
750     #if defined(GPIO_EM4WU0_PORT)
751   } else if (GPIO_EM4WU0_PORT == gpio->port && GPIO_EM4WU0_PIN == gpio->pin) {
752     em4_int_no = 0;
753     #endif
754     #if defined(GPIO_EM4WU1_PORT)
755   } else if (GPIO_EM4WU1_PORT == gpio->port && GPIO_EM4WU1_PIN == gpio->pin) {
756     em4_int_no = 1;
757     #endif
758     #if defined(GPIO_EM4WU3_PORT)
759   } else if (GPIO_EM4WU3_PORT == gpio->port && GPIO_EM4WU3_PIN == gpio->pin) {
760     em4_int_no = 3;
761     #endif
762     #if defined(GPIO_EM4WU4_PORT)
763   } else if (GPIO_EM4WU4_PORT == gpio->port && GPIO_EM4WU4_PIN == gpio->pin) {
764     em4_int_no = 4;
765     #endif
766     #if defined(GPIO_EM4WU6_PORT)
767   } else if (GPIO_EM4WU6_PORT == gpio->port && GPIO_EM4WU6_PIN == gpio->pin) {
768     em4_int_no = 6;
769     #endif
770     #if defined(GPIO_EM4WU7_PORT)
771   } else if (GPIO_EM4WU7_PORT == gpio->port && GPIO_EM4WU7_PIN == gpio->pin) {
772     em4_int_no = 7;
773     #endif
774     #if defined(GPIO_EM4WU8_PORT)
775   } else if (GPIO_EM4WU8_PORT == gpio->port && GPIO_EM4WU8_PIN == gpio->pin) {
776     em4_int_no = 8;
777     #endif
778     #if defined(GPIO_EM4WU9_PORT)
779   } else if (GPIO_EM4WU9_PORT == gpio->port && GPIO_EM4WU9_PIN == gpio->pin) {
780     em4_int_no = 9;
781     #endif
782     #if defined(GPIO_EM4WU10_PORT)
783   } else if (GPIO_EM4WU10_PORT == gpio->port && GPIO_EM4WU10_PIN == gpio->pin) {
784     em4_int_no = 10;
785     #endif
786   } else {
787     em4_int_no = -1;
788   }
789 
790   return em4_int_no;
791 }
792 
793 /*************************************************************************//**
794 * Disable GPIO pin wake-up from EM4.
795 *
796 * @param[in] pinmask Bit mask containing the bitwise logic OR of which GPIO pin(s) to disable.
797 *****************************************************************************/
sl_hal_gpio_disable_pin_em4_wakeup(uint32_t pinmask)798 __INLINE void sl_hal_gpio_disable_pin_em4_wakeup(uint32_t pinmask)
799 {
800   EFM_ASSERT((pinmask & ~_GPIO_EM4WUEN_MASK) == 0UL);
801 
802   GPIO->EM4WUEN &= ~pinmask;
803 }
804 
805 /**************************************************************************//**
806  * Enable GPIO pin retention of output enable, output value, pull enable, and
807  * pull direction in EM4.
808  *
809  * @note The behavior of this function depends on the configured GPIO retention mode.
810  *       If the GPIO retention mode is configured to be "SWUNLATCH" then this
811  *       function will not change anything. If the retention mode is anything else
812  *       then this function will set the GPIO retention mode to "EM4EXIT" when the
813  *       enable argument is true, and "Disabled" when false.
814  *
815  * @param[in] enable true - enable EM4 pin retention.
816  *                   false - disable EM4 pin retention.
817  *****************************************************************************/
sl_hal_gpio_set_pin_em4_retention(bool enable)818 __INLINE void sl_hal_gpio_set_pin_em4_retention(bool enable)
819 {
820   // Leave configuration alone when software unlatch is used.
821   uint32_t mode = EMU->EM4CTRL & _EMU_EM4CTRL_EM4IORETMODE_MASK;
822 
823   if (mode == EMU_EM4CTRL_EM4IORETMODE_SWUNLATCH) {
824     return;
825   }
826 
827   if (enable) {
828     EMU->EM4CTRL = (EMU->EM4CTRL & ~_EMU_EM4CTRL_EM4IORETMODE_MASK)
829                    | EMU_EM4CTRL_EM4IORETMODE_EM4EXIT;
830   } else {
831     EMU->EM4CTRL = (EMU->EM4CTRL & ~_EMU_EM4CTRL_EM4IORETMODE_MASK)
832                    | EMU_EM4CTRL_EM4IORETMODE_DISABLE;
833   }
834 }
835 
836 /**************************************************************************//**
837  * Check which GPIO pin(s) that caused a wake-up from EM4.
838  *
839  * @return Bit mask containing the bitwise logic OR of which GPIO pin(s) caused the wake-up.
840  *****************************************************************************/
sl_hal_gpio_get_pin_em4_wakeup_cause(void)841 __INLINE uint32_t sl_hal_gpio_get_pin_em4_wakeup_cause(void)
842 {
843   return GPIO->IF & _GPIO_EM4WUEN_EM4WUEN_MASK;
844 }
845 
846 /***************************************************************************//**
847  * Enable/Disable serial wire output pin.
848  *
849  * @note Enabling this pin is not sufficient to fully enable serial wire output,
850  *       which is also dependent on issues outside the GPIO module.
851  * @note If debug port is locked, SWO pin is not disabled automatically. To avoid
852  *       information leakage through SWO, disable SWO pin after locking debug port.
853  *
854  * @param[in] enable false - disable serial wire viewer pin (default after reset).
855  *                   true - enable serial wire viewer pin.
856  ******************************************************************************/
sl_hal_gpio_enable_debug_swo(bool enable)857 __INLINE void sl_hal_gpio_enable_debug_swo(bool enable)
858 {
859   uint32_t bit = enable ? 0x1UL : 0x0UL;
860 
861   if (bit != 0U) {
862     GPIO->TRACEROUTEPEN_SET = 1UL << _GPIO_TRACEROUTEPEN_SWVPEN_SHIFT;
863   } else {
864     GPIO->TRACEROUTEPEN_CLR = 1UL << _GPIO_TRACEROUTEPEN_SWVPEN_SHIFT;
865   }
866 }
867 
868 /***************************************************************************//**
869  * Enable/disable serial wire clock pin.
870  *
871  * @note Disabling SWDClk will disable the debug interface, which may result in
872  *       a lockout if done early in startup (before debugger is able to halt core).
873  *
874  * @param[in] enable false - disable serial wire clock.
875  *                   true - enable serial wire clock (default after reset).
876  ******************************************************************************/
sl_hal_gpio_enable_debug_swd_clk(bool enable)877 __INLINE void sl_hal_gpio_enable_debug_swd_clk(bool enable)
878 {
879   uint32_t bit = enable ? 0x1UL : 0x0UL;
880 
881   if (bit != 0U) {
882     GPIO->DBGROUTEPEN_SET = 1UL << _GPIO_DBGROUTEPEN_SWCLKTCKPEN_SHIFT;
883   } else {
884     GPIO->DBGROUTEPEN_CLR = 1UL << _GPIO_DBGROUTEPEN_SWCLKTCKPEN_SHIFT;
885   }
886 }
887 
888 /***************************************************************************//**
889  * Enable/disable serial wire data I/O pin.
890  *
891  * @note Disabling SWDClk will disable the debug interface, which may result in
892  *       a lockout if done early in startup (before debugger is able to halt core).
893  *
894  * @param[in] enable false - disable serial wire data pin.
895  *                   true - enable serial wire data pin (default after reset).
896  ******************************************************************************/
sl_hal_gpio_enable_debug_swd_io(bool enable)897 __INLINE void sl_hal_gpio_enable_debug_swd_io(bool enable)
898 {
899   uint32_t bit = enable ? 0x1UL : 0x0UL;
900 
901   if (bit != 0U) {
902     GPIO->DBGROUTEPEN_SET = 1UL << _GPIO_DBGROUTEPEN_SWDIOTMSPEN_SHIFT;
903   } else {
904     GPIO->DBGROUTEPEN_CLR = 1UL << _GPIO_DBGROUTEPEN_SWDIOTMSPEN_SHIFT;
905   }
906 }
907 
908 /** @} (end addtogroup gpio) */
909 
910 #ifdef __cplusplus
911 }
912 #endif
913 
914 #endif /* GPIO_PRESENT */
915 #endif /* SL_HAL_GPIO_H */
916