1 /***************************************************************************//**
2  * @file
3  * @brief Keyscan (KEYSCAN) peripheral 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 #ifndef SL_HAL_KEYSCAN_H
32 #define SL_HAL_KEYSCAN_H
33 
34 #include "em_device.h"
35 
36 #if defined(KEYSCAN_COUNT) && (KEYSCAN_COUNT > 0)
37 
38 #ifdef __cplusplus
39 extern "C" {
40 #endif
41 
42 #include <stdbool.h>
43 #include "sl_hal_keyscan_compat.h"
44 #include "sl_enum.h"
45 
46 /***************************************************************************//**
47  * @addtogroup keyscan
48  * @{
49  ******************************************************************************/
50 
51 /*******************************************************************************
52  *********************************   ENUM   ************************************
53  ******************************************************************************/
54 
55 /// KEYSCAN configuration delay values
SL_ENUM(sl_hal_keyscan_delay_t)56 SL_ENUM(sl_hal_keyscan_delay_t) {
57   SL_HAL_KEYSCAN_DELAY_2MS = 0, ///< 2 ms delay.
58   SL_HAL_KEYSCAN_DELAY_4MS,   ///< 4 ms delay.
59   SL_HAL_KEYSCAN_DELAY_6MS,   ///< 6 ms delay.
60   SL_HAL_KEYSCAN_DELAY_8MS,   ///< 8 ms delay.
61   SL_HAL_KEYSCAN_DELAY_10MS,  ///< 10 ms delay.
62   SL_HAL_KEYSCAN_DELAY_12MS,  ///< 12 ms delay.
63   SL_HAL_KEYSCAN_DELAY_14MS,  ///< 14 ms delay.
64   SL_HAL_KEYSCAN_DELAY_16MS,  ///< 16 ms delay.
65   SL_HAL_KEYSCAN_DELAY_18MS,  ///< 18 ms delay.
66   SL_HAL_KEYSCAN_DELAY_20MS,  ///< 20 ms delay.
67   SL_HAL_KEYSCAN_DELAY_22MS,  ///< 22 ms delay.
68   SL_HAL_KEYSCAN_DELAY_24MS,  ///< 24 ms delay.
69   SL_HAL_KEYSCAN_DELAY_26MS,  ///< 26 ms delay.
70   SL_HAL_KEYSCAN_DELAY_28MS,  ///< 28 ms delay.
71   SL_HAL_KEYSCAN_DELAY_30MS,  ///< 30 ms delay.
72   SL_HAL_KEYSCAN_DELAY_32MS   ///< 32 ms delay.
73 };
74 
75 /*******************************************************************************
76  *******************************   STRUCTS   ***********************************
77  ******************************************************************************/
78 
79 /// KEYSCAN configuration structure.
80 typedef struct {
81   uint32_t            clock_divider;       ///< Clock divider value.
82   uint8_t             column_number;       ///< Number of columns to set for keyscan (maximum 8).
83   uint8_t             row_number;          ///< Number of rows  to set for keyscan (maximum 6).
84   sl_hal_keyscan_delay_t  scan_delay;      ///< Scan delay.
85   sl_hal_keyscan_delay_t  debounce_delay;  ///< Debounce delay.
86   sl_hal_keyscan_delay_t  stable_delay;    ///< Stable delay.
87   bool                single_press_enable; ///< Enable Single Press feature.
88   bool                auto_start_enable;   ///< Enable auto-start feature.
89 } sl_hal_keyscan_config_t;
90 
91 /// Suggested default values for KEYSCAN configuration structure.
92 #define KEYSCAN_CONFIG_DEFAULT                                           \
93   {                                                                      \
94     0x1387F,                  /* Clock divider default value = 79999. */ \
95     3u,                       /* 3 columns by default. */                \
96     6u,                       /* 6 rows by default. */                   \
97     SL_HAL_KEYSCAN_DELAY_2MS, /* value 0 = 2ms Scan Delay*/              \
98     SL_HAL_KEYSCAN_DELAY_2MS, /* value 0 = 2ms Debounce Delay */         \
99     SL_HAL_KEYSCAN_DELAY_2MS, /* value 0 = 2ms Row Stable Delay */       \
100     false,                    /* Multi-press by default.*/               \
101     false,                    /* No auto-start by default. */            \
102   }
103 
104 /*******************************************************************************
105  *****************************   PROTOTYPES   **********************************
106  ******************************************************************************/
107 
108 /***************************************************************************//**
109  * Initializes KEYSCAN module.
110  *
111  * @param[in] p_config  A pointer to the KEYSCAN initialization structure
112  *                      variable.
113  ******************************************************************************/
114 void sl_hal_keyscan_init(const sl_hal_keyscan_config_t *p_config);
115 
116 /***************************************************************************//**
117  * Enables KEYSCAN module.
118  ******************************************************************************/
119 void sl_hal_keyscan_enable(void);
120 
121 /***************************************************************************//**
122  * Disables KEYSCAN module.
123  *
124  * @note The disabling of the module could take some time. This function will
125  *       not wait for the disabling to finish before returning. Use the function
126  *       sl_hal_keyscan_wait_ready to wait for the module to be fully disable.
127  ******************************************************************************/
128 void sl_hal_keyscan_disable(void);
129 
130 /***************************************************************************//**
131  * Waits for the KEYSCAN to complete reseting or disabling procedure.
132  ******************************************************************************/
sl_hal_keyscan_wait_ready(void)133 __STATIC_INLINE void sl_hal_keyscan_wait_ready(void)
134 {
135   while ((KEYSCAN->SWRST & _KEYSCAN_SWRST_RESETTING_MASK) || (KEYSCAN->EN & _KEYSCAN_EN_DISABLING_MASK) || (KEYSCAN->STATUS & _KEYSCAN_STATUS_SYNCBUSY_MASK)) {
136     // Wait for resetting, for disabling or for all synchronizations to finish
137   }
138 }
139 
140 /***************************************************************************//**
141  * Waits for the KEYSCAN to complete all synchronization of register changes
142  * and commands.
143  ******************************************************************************/
sl_hal_keyscan_wait_sync(void)144 __STATIC_INLINE void sl_hal_keyscan_wait_sync(void)
145 {
146   while ((KEYSCAN->EN != 0U) && (KEYSCAN->STATUS & KEYSCAN_STATUS_SYNCBUSY)) {
147     // Wait for all synchronizations to finish
148   }
149 }
150 
151 /***************************************************************************//**
152  * Starts KEYSCAN scan.
153  *
154  * @note This function will send a start command to the KEYSCAN peripheral.
155  *       The sl_hal_keyscan_wait_sync function can be used to wait for the start
156  *       command to be executed.
157  *
158  * @note This function requires the KEYSCAN to be enabled.
159  ******************************************************************************/
sl_hal_keyscan_start_scan(void)160 __STATIC_INLINE void sl_hal_keyscan_start_scan(void)
161 {
162   sl_hal_keyscan_wait_sync();
163   KEYSCAN->CMD = KEYSCAN_CMD_KEYSCANSTART;
164   sl_hal_keyscan_wait_ready();
165 }
166 
167 /***************************************************************************//**
168  * Stops the KEYSCAN scan.
169  *
170  * @note This function will send a stop command to the KEYSCAN peripheral.
171  *       The sl_hal_keyscan_wait_sync function can be used to wait for the stop
172  *       command to be executed.
173  *
174  * @note This function requires the KEYSCAN to be enabled.
175  ******************************************************************************/
sl_hal_keyscan_stop_scan(void)176 __STATIC_INLINE void sl_hal_keyscan_stop_scan(void)
177 {
178   sl_hal_keyscan_wait_sync();
179   KEYSCAN->CMD = KEYSCAN_CMD_KEYSCANSTOP;
180   sl_hal_keyscan_wait_ready();
181 }
182 
183 /***************************************************************************//**
184  * Restores KEYSCAN to its reset state.
185  *
186  * @note The resetting of the module could take some time. This function will
187  *       not wait for the resetting to finish before returning. Use the function
188  *       sl_hal_keyscan_wait_ready to wait for the module to be fully reset.
189  ******************************************************************************/
190 void sl_hal_keyscan_reset(void);
191 
192 /***************************************************************************//**
193  * Gets KEYSCAN STATUS register value.
194  *
195  * @return  Current STATUS register value.
196  ******************************************************************************/
sl_hal_keyscan_get_status(void)197 __STATIC_INLINE uint32_t sl_hal_keyscan_get_status(void)
198 {
199   return KEYSCAN->STATUS;
200 }
201 
202 /***************************************************************************//**
203  * Enables one or more KEYSCAN interrupts.
204  *
205  * @note  Depending on the use, a pending interrupt may already be set prior to
206  *        enabling the interrupt. To ignore a pending interrupt, consider using
207  *        sl_hal_keyscan_clear_interrupts prior to enabling the interrupt.
208  *
209  * @param[in] flags   KEYSCAN interrupt sources to enable.
210  *                    Use a set of interrupt flags OR-ed together to set
211  *                    multiple interrupt sources.
212  ******************************************************************************/
sl_hal_keyscan_enable_interrupts(uint32_t flags)213 __STATIC_INLINE void sl_hal_keyscan_enable_interrupts(uint32_t flags)
214 {
215   KEYSCAN->IEN_SET = flags;
216 }
217 
218 /***************************************************************************//**
219  * Disables one or more KEYSCAN interrupts.
220  *
221  * @param[in] flags   KEYSCAN interrupt sources to disable.
222  *                    Use a set of interrupt flags OR-ed together to disable
223  *                    multiple interrupt sources.
224  ******************************************************************************/
sl_hal_keyscan_disable_interrupts(uint32_t flags)225 __STATIC_INLINE void sl_hal_keyscan_disable_interrupts(uint32_t flags)
226 {
227   KEYSCAN->IEN_CLR = flags;
228 }
229 
230 /***************************************************************************//**
231  * Clears one or more pending KEYSCAN interrupts.
232  *
233  * @param[in] flags   KEYSCAN interrupt sources to clear.
234  *                    Use a set of interrupt flags OR-ed together to clear
235  *                    multiple interrupt sources.
236  ******************************************************************************/
sl_hal_keyscan_clear_interrupts(uint32_t flags)237 __STATIC_INLINE void sl_hal_keyscan_clear_interrupts(uint32_t flags)
238 {
239   KEYSCAN->IF_CLR = flags;
240 }
241 
242 /***************************************************************************//**
243  * Gets pending KEYSCAN interrupt flags.
244  *
245  * @note  Event bits are not cleared by using this function.
246  *
247  * @return  Pending KEYSCAN interrupt sources.
248  *          Returns a set of interrupt flags OR-ed together for multiple
249  *          interrupt sources.
250  ******************************************************************************/
sl_hal_keyscan_get_interrupts(void)251 __STATIC_INLINE uint32_t sl_hal_keyscan_get_interrupts(void)
252 {
253   return KEYSCAN->IF;
254 }
255 
256 /***************************************************************************//**
257  * Gets enabled and pending KEYSCAN interrupt flags.
258  * Useful for handling more interrupt sources in the same interrupt handler.
259  *
260  * @note  Interrupt flags are not cleared by using this function.
261  *
262  * @return  Pending and enabled KEYSCAN interrupt sources.
263  *          The return value is the bitwise AND of
264  *          - the enabled interrupt sources in KEYSCAN_IEN and
265  *          - the pending interrupt flags KEYSCAN_IF.
266  ******************************************************************************/
sl_hal_keyscan_get_enabled_interrupts(void)267 __STATIC_INLINE uint32_t sl_hal_keyscan_get_enabled_interrupts(void)
268 {
269   return KEYSCAN->IF & KEYSCAN->IEN;
270 }
271 
272 /***************************************************************************//**
273  * Sets one or more pending KEYSCAN interrupts from Software.
274  *
275  * @param[in] flags   KEYSCAN interrupt sources to set to pending.
276  *                    Use a set of interrupt flags OR-ed together to set
277  *                    multiple interrupt sources.
278  ******************************************************************************/
sl_hal_keyscan_set_interrupts(uint32_t flags)279 __STATIC_INLINE void sl_hal_keyscan_set_interrupts(uint32_t flags)
280 {
281   KEYSCAN->IF_SET = flags;
282 }
283 
284 /** @} (end addtogroup keyscan) */
285 
286 #ifdef __cplusplus
287 }
288 #endif
289 
290 #endif /* defined(KEYSCAN_COUNT) && (KEYSCAN_COUNT > 0) */
291 #endif /* SL_HAL_KEYSCAN_H */
292