1 /***************************************************************************//**
2  * @file
3  * @brief Backup Real Time Counter (BURTC) 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 EM_BURTC_H
32 #define EM_BURTC_H
33 
34 #include "em_device.h"
35 #if defined(BURTC_PRESENT)
36 
37 #include <stdbool.h>
38 #include "em_assert.h"
39 #include "em_bus.h"
40 
41 #ifdef __cplusplus
42 extern "C" {
43 #endif
44 
45 /***************************************************************************//**
46  * @addtogroup burtc
47  * @{
48  ******************************************************************************/
49 
50 /*******************************************************************************
51  *******************************   DEFINES   ***********************************
52  ******************************************************************************/
53 
54 /** BURTC clock divisors. These values are valid for the BURTC prescaler. */
55 #define burtcClkDiv_1      1     /**< Divide clock by 1. */
56 #define burtcClkDiv_2      2     /**< Divide clock by 2. */
57 #define burtcClkDiv_4      4     /**< Divide clock by 4. */
58 #define burtcClkDiv_8      8     /**< Divide clock by 8. */
59 #define burtcClkDiv_16     16    /**< Divide clock by 16. */
60 #define burtcClkDiv_32     32    /**< Divide clock by 32. */
61 #define burtcClkDiv_64     64    /**< Divide clock by 64. */
62 #define burtcClkDiv_128    128   /**< Divide clock by 128. */
63 
64 /*******************************************************************************
65  ********************************   ENUMS   ************************************
66  ******************************************************************************/
67 
68 #if defined(_SILICON_LABS_32B_SERIES_0)
69 /** BURTC clock selection. */
70 typedef enum {
71   /** Ultra low frequency (1 kHz) clock. */
72   burtcClkSelULFRCO = BURTC_CTRL_CLKSEL_ULFRCO,
73   /** Low frequency RC oscillator. */
74   burtcClkSelLFRCO  = BURTC_CTRL_CLKSEL_LFRCO,
75   /** Low frequency crystal osciallator. */
76   burtcClkSelLFXO   = BURTC_CTRL_CLKSEL_LFXO
77 } BURTC_ClkSel_TypeDef;
78 
79 /** BURTC mode of operation. */
80 typedef enum {
81   /** Disable BURTC */
82   burtcModeDisable = BURTC_CTRL_MODE_DISABLE,
83   /** Enable and start BURTC counter in EM0 to EM2. */
84   burtcModeEM2     = BURTC_CTRL_MODE_EM2EN,
85   /** Enable and start BURTC counter in EM0 to EM3. */
86   burtcModeEM3     = BURTC_CTRL_MODE_EM3EN,
87   /** Enable and start BURTC counter in EM0 to EM4. */
88   burtcModeEM4     = BURTC_CTRL_MODE_EM4EN,
89 } BURTC_Mode_TypeDef;
90 
91 /** BURTC low power mode. */
92 typedef enum {
93   /** Low Power Mode is disabled. */
94   burtcLPDisable = BURTC_LPMODE_LPMODE_DISABLE,
95   /** Low Power Mode is always enabled. */
96   burtcLPEnable  = BURTC_LPMODE_LPMODE_ENABLE,
97   /** Low Power Mode when system enters backup mode. */
98   burtcLPBU      = BURTC_LPMODE_LPMODE_BUEN
99 } BURTC_LP_TypeDef;
100 #endif
101 
102 /*******************************************************************************
103  *******************************   STRUCTS   ***********************************
104  ******************************************************************************/
105 
106 #if defined(_SILICON_LABS_32B_SERIES_0)
107 /** BURTC initialization structure for Series 0 devices. */
108 typedef struct {
109   bool                 enable;       /**< Enable BURTC after initialization (starts counter). */
110 
111   BURTC_Mode_TypeDef   mode;         /**< Configure energy mode operation. */
112   bool                 debugRun;     /**< If true, counter will keep running under debug halt. */
113   BURTC_ClkSel_TypeDef clkSel;       /**< Select clock source. */
114   uint32_t             clkDiv;       /**< Clock divider; for ULFRCO 1Khz or 2kHz operation. */
115 
116   uint32_t             lowPowerComp; /**< Number of least significantt clock bits to ignore in low power mode. */
117   bool                 timeStamp;    /**< Enable time stamp on entering backup power domain. */
118 
119   bool                 compare0Top;  /**< Set if Compare Value 0 is also top value (counter restart). */
120 
121   BURTC_LP_TypeDef     lowPowerMode; /**< Low power operation mode, requires LFXO or LFRCO. */
122 } BURTC_Init_TypeDef;
123 
124 /** Default configuration for BURTC initialization structure. */
125 #define BURTC_INIT_DEFAULT \
126   {                        \
127     true,                  \
128     burtcModeEM2,          \
129     false,                 \
130     burtcClkSelULFRCO,     \
131     burtcClkDiv_1,         \
132     0,                     \
133     true,                  \
134     false,                 \
135     burtcLPDisable,        \
136   }
137 
138 #elif defined(_SILICON_LABS_32B_SERIES_2)
139 /** BURTC initialization structure for Series 2 devices. */
140 typedef struct {
141   bool                 start;        /**< Start BURTC after initialization */
142   bool                 debugRun;     /**< If true, counter will keep running under debug halt */
143   uint32_t             clkDiv;       /**< Clock divider. Supported range is 1-32768 */
144   bool                 compare0Top;  /**< Set if Compare Value 0 is also top value (counter restart) */
145   bool                 em4comp;      /**< Enable EM4 wakeup on compare match. */
146   bool                 em4overflow;  /**< Enable EM4 wakeup on counter overflow. */
147 } BURTC_Init_TypeDef;
148 
149 /** Default configuration for BURTC init structure */
150 #define BURTC_INIT_DEFAULT \
151   {                        \
152     true,                  \
153     false,                 \
154     1,                     \
155     0,                     \
156     false,                 \
157     false,                 \
158   }
159 #endif
160 
161 /*******************************************************************************
162  *****************************   PROTOTYPES   **********************************
163  ******************************************************************************/
164 
165 /***************************************************************************//**
166  * @brief
167  *   Clear one or more pending BURTC interrupts.
168  *
169  * @param[in] flags
170  *   BURTC interrupt sources to clear. Use a set of interrupt flags OR-ed
171  *   together to clear multiple interrupt sources for the BURTC module
172  *   (BURTC_IFS_nnn).
173  ******************************************************************************/
BURTC_IntClear(uint32_t flags)174 __STATIC_INLINE void BURTC_IntClear(uint32_t flags)
175 {
176 #if defined(BURTC_HAS_SET_CLEAR)
177   BURTC->IF_CLR = flags;
178 #else
179   BURTC->IFC = flags;
180 #endif
181 }
182 
183 /***************************************************************************//**
184  * @brief
185  *   Disable one or more BURTC interrupts.
186  *
187  * @param[in] flags
188  *   BURTC interrupt sources to disable. Use a set of interrupt flags OR-ed
189  *   together to disable multiple interrupt sources for the BURTC module
190  *   (BURTC_IFS_nnn).
191  ******************************************************************************/
BURTC_IntDisable(uint32_t flags)192 __STATIC_INLINE void BURTC_IntDisable(uint32_t flags)
193 {
194 #if defined(BURTC_HAS_SET_CLEAR)
195   BURTC->IEN_CLR = flags;
196 #else
197   BURTC->IEN &= ~(flags);
198 #endif
199 }
200 
201 /***************************************************************************//**
202  * @brief
203  *   Enable one or more BURTC interrupts.
204  *
205  * @note
206  *   Depending on use, a pending interrupt may already be set prior to
207  *   enabling the interrupt. Consider using BURTC_IntClear() prior to enabling
208  *   if a pending interrupt should be ignored.
209  *
210  * @param[in] flags
211  *   BURTC interrupt sources to enable. Use a set of interrupt flags OR-ed
212  *   together to set multiple interrupt sources for the BURTC module
213  *   (BURTC_IFS_nnn).
214  ******************************************************************************/
BURTC_IntEnable(uint32_t flags)215 __STATIC_INLINE void BURTC_IntEnable(uint32_t flags)
216 {
217 #if defined(BURTC_HAS_SET_CLEAR)
218   BURTC->IEN_SET = flags;
219 #else
220   BURTC->IEN |= flags;
221 #endif
222 }
223 
224 /***************************************************************************//**
225  * @brief
226  *   Get pending BURTC interrupt flags.
227  *
228  * @note
229  *   This function does not clear the event bits.
230  *
231  * @return
232  *   Pending BURTC interrupt sources. Returns a set of interrupt flags OR-ed
233  *   together for multiple interrupt sources in the BURTC module (BURTC_IFS_nnn).
234  ******************************************************************************/
BURTC_IntGet(void)235 __STATIC_INLINE uint32_t BURTC_IntGet(void)
236 {
237   return BURTC->IF;
238 }
239 
240 /***************************************************************************//**
241  * @brief
242  *   Get enabled and pending BURTC interrupt flags.
243  *
244  * @note
245  *   The event bits are not cleared by the use of this function.
246  *
247  * @return
248  *   Pending BURTC interrupt sources that is also enabled. Returns a set of
249  *   interrupt flags OR-ed together for multiple interrupt sources in the
250  *   BURTC module (BURTC_IFS_nnn).
251  ******************************************************************************/
BURTC_IntGetEnabled(void)252 __STATIC_INLINE uint32_t BURTC_IntGetEnabled(void)
253 {
254   uint32_t tmp;
255 
256   /* Get enabled interrupts */
257   tmp = BURTC->IEN;
258 
259   /* Return set interrupts */
260   return BURTC->IF & tmp;
261 }
262 
263 /***************************************************************************//**
264  * @brief
265  *   Set one or more pending BURTC interrupts from SW.
266  *
267  * @param[in] flags
268  *   BURTC interrupt sources to set to pending. Use a set of interrupt flags
269  *   OR-ed together to set multiple interrupt sources for the BURTC module
270  *   (BURTC_IFS_nnn).
271  ******************************************************************************/
BURTC_IntSet(uint32_t flags)272 __STATIC_INLINE void BURTC_IntSet(uint32_t flags)
273 {
274 #if defined(BURTC_HAS_SET_CLEAR)
275   BURTC->IF_SET = flags;
276 #else
277   BURTC->IFS = flags;
278 #endif
279 }
280 
281 /***************************************************************************//**
282  * @brief
283  *   Status of BURTC RAM, timestamp and LP Mode
284  *
285  * @return A mask logially OR-ed status bits
286  ******************************************************************************/
BURTC_Status(void)287 __STATIC_INLINE uint32_t BURTC_Status(void)
288 {
289   return BURTC->STATUS;
290 }
291 
292 #if defined(BURTC_CMD_CLRSTATUS)
293 /***************************************************************************//**
294  * @brief
295  *   Clear and reset BURTC status register
296  ******************************************************************************/
BURTC_StatusClear(void)297 __STATIC_INLINE void BURTC_StatusClear(void)
298 {
299   BURTC->CMD = BURTC_CMD_CLRSTATUS;
300 }
301 #endif
302 
303 /***************************************************************************//**
304  * @brief
305  *   Wait for the BURTC to complete all synchronization of register changes
306  *   and commands.
307  ******************************************************************************/
BURTC_SyncWait(void)308 __STATIC_INLINE void BURTC_SyncWait(void)
309 {
310 #if defined(_SILICON_LABS_32B_SERIES_2)
311   while ((BURTC->EN != 0U) && (BURTC->SYNCBUSY != 0U)) {
312     /* Wait for previous synchronization to finish */
313   }
314 #else
315   while (BURTC->SYNCBUSY != 0U) {
316     /* Wait for previous synchronization to finish */
317   }
318 #endif
319 }
320 
321 #if defined(_SILICON_LABS_32B_SERIES_2)
322 /***************************************************************************//**
323  * @brief
324  *   Start BURTC counter.
325  *
326  *   This function will send a start command to the BURTC peripheral. The BURTC
327  *   peripheral will use some LF clock ticks before the command is executed.
328  *   The @ref BURTC_SyncWait() function can be used to wait for the start command
329  *   to be executed.
330  *
331  * @note
332  *   This function requires the BURTC to be enabled.
333  ******************************************************************************/
BURTC_Start(void)334 __STATIC_INLINE void BURTC_Start(void)
335 {
336   BURTC_SyncWait();
337   BURTC->CMD = BURTC_CMD_START;
338 }
339 
340 /***************************************************************************//**
341  * @brief
342  *   Stop the BURTC counter.
343  *
344  *   This function will send a stop command to the BURTC peripheral. The BURTC
345  *   peripheral will use some LF clock ticks before the command is executed.
346  *   The @ref BURTC_SyncWait() function can be used to wait for the stop command
347  *   to be executed.
348  *
349  * @note
350  *   This function requires the BURTC to be enabled.
351  ******************************************************************************/
BURTC_Stop(void)352 __STATIC_INLINE void BURTC_Stop(void)
353 {
354   BURTC_SyncWait();
355   BURTC->CMD = BURTC_CMD_STOP;
356 }
357 #endif
358 
359 /***************************************************************************//**
360  * @brief Get BURTC counter
361  *
362  * @return
363  *   BURTC counter value
364  ******************************************************************************/
BURTC_CounterGet(void)365 __STATIC_INLINE uint32_t BURTC_CounterGet(void)
366 {
367   return BURTC->CNT;
368 }
369 
370 #if defined(_SILICON_LABS_32B_SERIES_0)
371 /***************************************************************************//**
372  * @brief Get BURTC timestamp for entering BU
373  *
374  * @return
375  *   BURTC Time Stamp value
376  ******************************************************************************/
BURTC_TimestampGet(void)377 __STATIC_INLINE uint32_t BURTC_TimestampGet(void)
378 {
379   return BURTC->TIMESTAMP;
380 }
381 
382 /***************************************************************************//**
383  * @brief Freeze register updates until enabled
384  * @param[in] enable If true, registers are not updated until enabled again.
385  ******************************************************************************/
BURTC_FreezeEnable(bool enable)386 __STATIC_INLINE void BURTC_FreezeEnable(bool enable)
387 {
388   BUS_RegBitWrite(&BURTC->FREEZE, _BURTC_FREEZE_REGFREEZE_SHIFT, enable);
389 }
390 
391 /***************************************************************************//**
392  * @brief Shut down power to rentention register bank.
393  * @param[in] enable
394  *     If true, shuts off power to retention registers.
395  * @note
396  *    When power rentention is disabled, it cannot be enabled again (until
397  *    reset).
398  ******************************************************************************/
BURTC_Powerdown(bool enable)399 __STATIC_INLINE void BURTC_Powerdown(bool enable)
400 {
401   BUS_RegBitWrite(&BURTC->POWERDOWN, _BURTC_POWERDOWN_RAM_SHIFT, enable);
402 }
403 
404 /***************************************************************************//**
405  * @brief
406  *   Set a value in one of the retention registers
407  *
408  * @param[in] num
409  *   Register to set
410  * @param[in] data
411  *   Value to put into register
412  ******************************************************************************/
BURTC_RetRegSet(uint32_t num,uint32_t data)413 __STATIC_INLINE void BURTC_RetRegSet(uint32_t num, uint32_t data)
414 {
415   EFM_ASSERT(num <= 127);
416 
417   BURTC->RET[num].REG = data;
418 }
419 
420 /***************************************************************************//**
421  * @brief
422  *   Read a value from one of the retention registers
423  *
424  * @param[in] num
425  *   Retention Register to read
426  *
427  * @return
428  *   Value of the retention register
429  ******************************************************************************/
BURTC_RetRegGet(uint32_t num)430 __STATIC_INLINE uint32_t BURTC_RetRegGet(uint32_t num)
431 {
432   EFM_ASSERT(num <= 127);
433 
434   return BURTC->RET[num].REG;
435 }
436 #endif
437 
438 /***************************************************************************//**
439  * @brief
440  *   Lock BURTC registers, will protect from writing new config settings
441  ******************************************************************************/
BURTC_Lock(void)442 __STATIC_INLINE void BURTC_Lock(void)
443 {
444   BURTC->LOCK = 0x0;
445 }
446 
447 /***************************************************************************//**
448  * @brief
449  *   Unlock BURTC registers, enable write access to change configuration
450  ******************************************************************************/
BURTC_Unlock(void)451 __STATIC_INLINE void BURTC_Unlock(void)
452 {
453   BURTC->LOCK = BURTC_LOCK_LOCKKEY_UNLOCK;
454 }
455 
456 void BURTC_Reset(void);
457 void BURTC_Init(const BURTC_Init_TypeDef *burtcInit);
458 void BURTC_Enable(bool enable);
459 void BURTC_CounterReset(void);
460 void BURTC_CompareSet(unsigned int comp, uint32_t value);
461 uint32_t BURTC_CompareGet(unsigned int comp);
462 #if defined(_BURTC_CTRL_MASK)
463 uint32_t BURTC_ClockFreqGet(void);
464 #endif
465 
466 /** @} (end addtogroup burtc) */
467 
468 #ifdef __cplusplus
469 }
470 #endif
471 
472 #endif /* BURTC_PRESENT */
473 #endif /* EM_BURTC_H */
474