1 /*
2 * Copyright (c) 2020 - 2024 Renesas Electronics Corporation and/or its affiliates
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6 
7 /***********************************************************************************************************************
8  * Includes
9  **********************************************************************************************************************/
10 
11 #include "bsp_api.h"
12 #include "r_lpm.h"
13 
14 /***********************************************************************************************************************
15  * Macro definitions
16  **********************************************************************************************************************/
17 
18 #define LPM_LPSCR_SYSTEM_ACTIVE                  (0x0U)
19 #define LPM_LPSCR_SOFTWARE_STANDBY_MODE          (0x4U)
20 #define LPM_LPSCR_DEEP_SOFTWARE_STANDBY_MODE1    (0x8U)
21 #define LPM_LPSCR_DEEP_SOFTWARE_STANDBY_MODE2    (0x9U)
22 #define LPM_LPSCR_DEEP_SOFTWARE_STANDBY_MODE3    (0xAU)
23 
24 /* Clock control register addresses */
25 #define LPM_CLOCK_HOCOCR                         (&R_SYSTEM->HOCOCR)
26 #define LPM_CLOCK_MOCOCR                         (&R_SYSTEM->MOCOCR)
27 #define LPM_CLOCK_LOCOCR                         (&R_SYSTEM->LOCOCR)
28 #define LPM_CLOCK_MOSCCR                         (&R_SYSTEM->MOSCCR)
29 #define LPM_CLOCK_SOSCCR                         (&R_SYSTEM->SOSCCR)
30 #define LPM_CLOCK_PLLCR                          (&R_SYSTEM->PLLCR)
31 #define LPM_CLOCK_PLL2CR                         (&R_SYSTEM->PLL2CR)
32 #define LPM_CLOCK_HOCO                           0 // The high speed on chip oscillator.
33 #define LPM_CLOCK_MOCO                           1 // The middle speed on chip oscillator.
34 #define LPM_CLOCK_LOCO                           2 // The low speed on chip oscillator.
35 #define LPM_CLOCK_MAIN_OSC                       3 // The main oscillator.
36 #define LPM_CLOCK_SUBCLOCK                       4 // The subclock oscillator.
37 #define LPM_CLOCK_PLL                            5 // The PLL oscillator.
38 #define LPM_CLOCK_PLL2                           6 // The PLL2 oscillator.
39 
40 /* From user's manual and discussions with hardware group,
41  * using the maximum is safe for all MCUs, will be updated and restored in LPM when entering
42  * low power mode on RA6 MCUs (lowPowerModeEnter())
43  */
44 
45 #define LPM_SW_STANDBY_STCONR                    (0x0U)
46 #define LPM_SW_STANDBY_WAKE_STCONR               (0x3U)
47 
48 #define LPM_SNZREQCR1_OFFSET                     (32ULL)
49 #define LPM_WUPEN1_OFFSET                        (32ULL)
50 #define LPM_SBYEDCR1_OFFSET                      (32ULL)
51 
52 #define LPM_OPEN                                 (0x524c504d)
53 
54 /***********************************************************************************************************************
55  * Typedef definitions
56  **********************************************************************************************************************/
57 
58 /***********************************************************************************************************************
59  * Private global variables
60  **********************************************************************************************************************/
61 
62 #ifdef R_SYSTEM_SNZCR_SNZE_Msk
63 
64 /* This array stores the address of the register containing the stop bit for each clock. All of these registers are
65  * 8-bit registers and only bit 0 is valid.  All other bits are read as 0 and should be written to 0.  Bit 0 of each
66  * of these registers indicates that the corresponding clock is stopped when set, or that the corresponding clock
67  * is operating when cleared. */
68 static uint8_t volatile * const gp_lpm_clock_stp_registers[] =
69 {
70     [LPM_CLOCK_HOCO]     = LPM_CLOCK_HOCOCR,
71     [LPM_CLOCK_MOCO]     = LPM_CLOCK_MOCOCR,
72     [LPM_CLOCK_LOCO]     = LPM_CLOCK_LOCOCR,
73     [LPM_CLOCK_MAIN_OSC] = LPM_CLOCK_MOSCCR,
74     [LPM_CLOCK_SUBCLOCK] = LPM_CLOCK_SOSCCR,
75  #if BSP_FEATURE_CGC_HAS_PLL
76     [LPM_CLOCK_PLL] = LPM_CLOCK_PLLCR,
77  #endif
78  #if BSP_FEATURE_CGC_HAS_PLL2
79     [LPM_CLOCK_PLL2] = LPM_CLOCK_PLL2CR,
80  #endif
81 };
82 #endif
83 
84 /***********************************************************************************************************************
85  * Global Variables
86  **********************************************************************************************************************/
87 const lpm_api_t g_lpm_on_lpm =
88 {
89     .open                = R_LPM_Open,
90     .close               = R_LPM_Close,
91     .lowPowerReconfigure = R_LPM_LowPowerReconfigure,
92     .lowPowerModeEnter   = R_LPM_LowPowerModeEnter,
93     .ioKeepClear         = R_LPM_IoKeepClear,
94 };
95 
96 /***********************************************************************************************************************
97  * Functions
98  **********************************************************************************************************************/
99 
100 /***********************************************************************************************************************
101  * Private Functions
102  **********************************************************************************************************************/
103 static fsp_err_t r_lpm_configure(lpm_cfg_t const * const p_cfg);
104 static fsp_err_t r_lpm_low_power_enter(lpm_instance_ctrl_t * const p_instance_ctrl);
105 
106 #ifdef R_SYSTEM_SNZCR_SNZE_Msk
107 static fsp_err_t r_lpm_check_clocks(uint32_t clock_source);
108 
109 #endif
110 static void r_lpm_wait_for_operating_mode_flags(void);
111 
112 #if BSP_FEATURE_LPM_HAS_LPSCR
113 static uint8_t r_lpm_lpscr_calculate(lpm_cfg_t const * p_cfg);
114 
115 #endif
116 #if LPM_CFG_PARAM_CHECKING_ENABLE
117 static fsp_err_t r_lpm_mcu_specific_low_power_check(lpm_cfg_t const * const p_cfg);
118 
119 #endif
120 
121 /*******************************************************************************************************************//**
122  * @addtogroup LPM
123  * @{
124  **********************************************************************************************************************/
125 
126 /*******************************************************************************************************************//**
127  * Perform any necessary initialization
128  *
129  * @retval     FSP_SUCCESS                   LPM instance opened
130  * @retval     FSP_ERR_ASSERTION             Null Pointer
131  * @retval     FSP_ERR_ALREADY_OPEN          LPM instance is already open
132  * @retval     FSP_ERR_UNSUPPORTED           This MCU does not support Deep Software Standby
133  * @retval     FSP_ERR_INVALID_ARGUMENT      One of the following:
134  *                                           - Invalid snooze entry source
135  *                                           - Invalid snooze end sources
136  * @retval     FSP_ERR_INVALID_MODE          One of the following:
137  *                                           - Invalid low power mode
138  *                                           - Invalid DTC option for snooze mode
139  *                                           - Invalid deep standby end sources
140  *                                           - Invalid deep standby end sources edges
141  *                                           - Invalid power supply option for deep standby
142  *                                           - Invalid IO port option for deep standby
143  *                                           - Invalid output port state setting for standby or deep standby
144  *                                           - Invalid sources for wake from standby mode
145  *                                           - Invalid power supply option for standby
146  *                                           - Invalid IO port option for standby
147  *                                           - Invalid standby end sources
148  *                                           - Invalid standby end sources edges
149  **********************************************************************************************************************/
R_LPM_Open(lpm_ctrl_t * const p_api_ctrl,lpm_cfg_t const * const p_cfg)150 fsp_err_t R_LPM_Open (lpm_ctrl_t * const p_api_ctrl, lpm_cfg_t const * const p_cfg)
151 {
152     lpm_instance_ctrl_t * p_ctrl = (lpm_instance_ctrl_t *) p_api_ctrl;
153 #if LPM_CFG_PARAM_CHECKING_ENABLE
154     FSP_ASSERT(NULL != p_api_ctrl);
155     FSP_ERROR_RETURN(LPM_OPEN != p_ctrl->lpm_open, FSP_ERR_ALREADY_OPEN);
156 #endif
157 
158     /* Save the configuration  */
159     p_ctrl->p_cfg = p_cfg;
160 
161     fsp_err_t err = r_lpm_configure(p_cfg);
162     FSP_ERROR_RETURN(FSP_SUCCESS == err, err);
163 
164     p_ctrl->lpm_open = LPM_OPEN;
165 
166     return FSP_SUCCESS;
167 }
168 
169 /*******************************************************************************************************************//**
170  * Configure a low power mode
171  *
172  * NOTE: This function does not enter the low power mode, it only configures parameters of the mode. Execution of the
173  * WFI instruction is what causes the low power mode to be entered.
174  *
175  * @retval     FSP_SUCCESS                   Low power mode successfuly applied
176  * @retval     FSP_ERR_ASSERTION             Null Pointer
177  * @retval     FSP_ERR_NOT_OPEN              LPM instance is not open
178  * @retval     FSP_ERR_UNSUPPORTED           This MCU does not support Deep Software Standby
179  * @retval     FSP_ERR_INVALID_ARGUMENT      One of the following:
180  *                                           - Invalid snooze entry source
181  *                                           - Invalid snooze end sources
182  * @retval     FSP_ERR_INVALID_MODE          One of the following:
183  *                                           - Invalid low power mode
184  *                                           - Invalid DTC option for snooze mode
185  *                                           - Invalid deep standby end sources
186  *                                           - Invalid deep standby end sources edges
187  *                                           - Invalid power supply option for deep standby
188  *                                           - Invalid IO port option for deep standby
189  *                                           - Invalid output port state setting for standby or deep standby
190  *                                           - Invalid sources for wake from standby mode
191  *                                           - Invalid power supply option for standby
192  *                                           - Invalid IO port option for standby
193  *                                           - Invalid standby end sources
194  *                                           - Invalid standby end sources edges
195  **********************************************************************************************************************/
R_LPM_LowPowerReconfigure(lpm_ctrl_t * const p_api_ctrl,lpm_cfg_t const * const p_cfg)196 fsp_err_t R_LPM_LowPowerReconfigure (lpm_ctrl_t * const p_api_ctrl, lpm_cfg_t const * const p_cfg)
197 {
198     lpm_instance_ctrl_t * p_ctrl = (lpm_instance_ctrl_t *) p_api_ctrl;
199 
200 #if LPM_CFG_PARAM_CHECKING_ENABLE
201     FSP_ASSERT(NULL != p_api_ctrl);
202     FSP_ERROR_RETURN(LPM_OPEN == p_ctrl->lpm_open, FSP_ERR_NOT_OPEN);
203 #endif
204 
205     /* Save the configuration  */
206     p_ctrl->p_cfg = p_cfg;
207 
208     return r_lpm_configure(p_cfg);
209 }
210 
211 /*******************************************************************************************************************//**
212  * Enter low power mode (sleep/deep sleep/standby/deep standby) using WFI macro.
213  *
214  * Function will return after waking from low power mode.
215  *
216  * @retval     FSP_SUCCESS                   Successful.
217  * @retval     FSP_ERR_ASSERTION             Null pointer.
218  * @retval     FSP_ERR_NOT_OPEN              LPM instance is not open
219  * @retval     FSP_ERR_INVALID_MODE          One of the following:
220  *                                           - HOCO was not system clock when using snooze mode with SCI0/RXD0.
221  *                                           - HOCO was not stable when using snooze mode with SCI0/RXD0.
222  *                                           - MOCO was running when using snooze mode with SCI0/RXD0.
223  *                                           - MAIN OSCILLATOR was running when using snooze mode with SCI0/RXD0.
224  *                                           - PLL was running when using snooze mode with SCI0/RXD0.
225  *                                           - Unable to disable ocillator stop detect when using standby or deep standby.
226  **********************************************************************************************************************/
R_LPM_LowPowerModeEnter(lpm_ctrl_t * const p_api_ctrl)227 fsp_err_t R_LPM_LowPowerModeEnter (lpm_ctrl_t * const p_api_ctrl)
228 {
229     lpm_instance_ctrl_t * p_ctrl = (lpm_instance_ctrl_t *) p_api_ctrl;
230 #if LPM_CFG_PARAM_CHECKING_ENABLE
231     FSP_ASSERT(NULL != p_ctrl);
232     FSP_ERROR_RETURN(LPM_OPEN == p_ctrl->lpm_open, FSP_ERR_NOT_OPEN);
233 
234  #if BSP_FEATURE_LPM_STANDBY_MOCO_REQUIRED
235 
236     /* The MOCO must be running when entering standby mode. */
237     if (LPM_MODE_STANDBY <= p_ctrl->p_cfg->low_power_mode)
238     {
239         FSP_ERROR_RETURN(0 == FSP_STYPE3_REG8_READ(R_SYSTEM->MOCOCR, !R_SYSTEM->CGFSAR_b.NONSEC03),
240                          FSP_ERR_INVALID_MODE);
241     }
242  #endif
243 #endif
244 #if BSP_FEATURE_LPM_SNOOZE_REQUEST_DTCST_DTCST == 1
245     uint8_t saved_dtcst = 0;
246 #endif
247 
248     /* Wait for ongoing operating mode transition (OPCMTSF, SOPCMTSF) */
249     r_lpm_wait_for_operating_mode_flags();
250 
251     /* Must enable writing to Low Power Mode register prior to entering Low Power Mode. */
252     R_BSP_RegisterProtectDisable(BSP_REG_PROTECT_OM_LPC_BATT);
253 #if LPM_CFG_STANDBY_LIMIT
254  #if BSP_FEATURE_LPM_HAS_LPSCR
255     R_SYSTEM->LPSCR = r_lpm_lpscr_calculate(p_ctrl->p_cfg);
256  #endif
257 
258  #if BSP_FEATURE_LPM_HAS_SBYCR_SSBY
259     if (LPM_MODE_SLEEP != p_ctrl->p_cfg->low_power_mode)
260     {
261         R_SYSTEM->SBYCR |= (1U << R_SYSTEM_SBYCR_SSBY_Pos);
262     }
263  #endif
264 #endif
265 #if BSP_FEATURE_LPM_HAS_SNOOZE
266     if (LPM_MODE_STANDBY_SNOOZE == p_ctrl->p_cfg->low_power_mode)
267     {
268         /* Configure Snooze registers */
269  #if BSP_FEATURE_LPM_SNOOZE_REQUEST_DTCST_DTCST == 1
270         if (!p_ctrl->p_cfg->dtc_state_in_snooze)
271         {
272   #if LPM_CFG_PARAM_CHECKING_ENABLE
273             FSP_ERROR_RETURN(0 == R_MSTP->MSTPCRA_b.MSTPA22, FSP_ERR_INVALID_MODE);
274   #endif
275 
276             /* Store the previous state of DTCST. */
277             saved_dtcst = R_DTC->DTCST;
278 
279             /* If snooze mode does not use DTC, DTC should be stopped before entering snooze mode. */
280             R_DTC->DTCST = 0U;
281         }
282  #endif
283     }
284 #endif
285     fsp_err_t err = r_lpm_low_power_enter(p_ctrl);
286 
287 #if LPM_CFG_STANDBY_LIMIT
288  #if BSP_FEATURE_LPM_HAS_LPSCR
289     if ((LPM_MODE_SLEEP != p_ctrl->p_cfg->low_power_mode) && (LPM_MODE_DEEP_SLEEP != p_ctrl->p_cfg->low_power_mode))
290     {
291         R_SYSTEM->LPSCR = 0;
292     }
293  #endif
294  #if BSP_FEATURE_LPM_HAS_SBYCR_SSBY
295     if (LPM_MODE_SLEEP != p_ctrl->p_cfg->low_power_mode)
296     {
297         R_SYSTEM->SBYCR &= (uint16_t) (~(1U << R_SYSTEM_SBYCR_SSBY_Pos));
298     }
299  #endif
300 #endif
301 #if BSP_FEATURE_LPM_HAS_SNOOZE
302     if (LPM_MODE_STANDBY_SNOOZE == p_ctrl->p_cfg->low_power_mode)
303     {
304  #if BSP_FEATURE_LPM_SNOOZE_REQUEST_DTCST_DTCST == 1
305         if (!p_ctrl->p_cfg->dtc_state_in_snooze)
306         {
307             /* If DTC was stopped prior to entering snooze mode, then start it again. */
308             R_DTC->DTCST = saved_dtcst;
309         }
310  #endif
311     }
312 #endif
313 
314     R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_OM_LPC_BATT);
315 
316     return err;
317 }
318 
319 /*******************************************************************************************************************//**
320  * Clear the IOKEEP bit after deep software standby
321  *
322  * @retval     FSP_SUCCESS          DPSBYCR_b.IOKEEP bit cleared Successfully.
323  * @retval     FSP_ERR_UNSUPPORTED  Deep standby mode not supported on this MCU.
324  **********************************************************************************************************************/
R_LPM_IoKeepClear(lpm_ctrl_t * const p_api_ctrl)325 fsp_err_t R_LPM_IoKeepClear (lpm_ctrl_t * const p_api_ctrl)
326 {
327     FSP_PARAMETER_NOT_USED(p_api_ctrl);
328 #if BSP_FEATURE_LPM_HAS_DEEP_STANDBY
329     R_BSP_RegisterProtectDisable(BSP_REG_PROTECT_OM_LPC_BATT);
330 
331     R_SYSTEM->DPSBYCR_b.IOKEEP = 0U;
332 
333     R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_OM_LPC_BATT);
334 
335     return FSP_SUCCESS;
336 #else
337 
338     return FSP_ERR_UNSUPPORTED;
339 #endif
340 }
341 
342 /*******************************************************************************************************************//**
343  * Close the LPM Instance
344  *
345  * @retval     FSP_SUCCESS        LPM driver closed
346  * @retval     FSP_ERR_NOT_OPEN   LPM instance is not open
347  * @retval     FSP_ERR_ASSERTION  Null Pointer
348  **********************************************************************************************************************/
R_LPM_Close(lpm_ctrl_t * const p_api_ctrl)349 fsp_err_t R_LPM_Close (lpm_ctrl_t * const p_api_ctrl)
350 {
351     lpm_instance_ctrl_t * p_ctrl = (lpm_instance_ctrl_t *) p_api_ctrl;
352 #if LPM_CFG_PARAM_CHECKING_ENABLE
353     FSP_ASSERT(NULL != p_api_ctrl);
354     FSP_ERROR_RETURN(LPM_OPEN == p_ctrl->lpm_open, FSP_ERR_NOT_OPEN);
355 #endif
356 
357     p_ctrl->lpm_open = 0;
358 
359     return FSP_SUCCESS;
360 }
361 
362 /*******************************************************************************************************************//**
363  * @} (end addtogroup LPM)
364  **********************************************************************************************************************/
365 
366 #if LPM_CFG_PARAM_CHECKING_ENABLE
367 
368 /*******************************************************************************************************************//**
369  * Verifies all MCU specific settings related to low power modes
370  * @param      p_cfg           the MCU specific configuration
371  *
372  * @retval     FSP_SUCCESS              Configuration is valid
373  * @retval     FSP_ERR_UNSUPPORTED      This MCU does not support Deep Software Standby
374  * @retval     FSP_ERR_INVALID_ARGUMENT One of the following:
375  *                                      - Invalid snooze entry source
376  *                                      - Invalid snooze end sources
377  * @retval     FSP_ERR_INVALID_MODE     One of the following:
378  *                                      - Invalid low power mode
379  *                                      - Invalid DTC option for snooze mode
380  *                                      - Invalid deep standby end sources
381  *                                      - Invalid deep standby end sources edges
382  *                                      - Invalid power supply option for deep standby
383  *                                      - Invalid IO port option for deep standby
384  *                                      - Invalid output port state setting for standby or deep standby
385  *                                      - Invalid sources for wake from standby mode
386  *                                      - Invalid power supply option for standby
387  *                                      - Invalid IO port option for standby
388  *                                      - Invalid standby end sources
389  *                                      - Invalid standby end sources edges
390  *
391  * @note       This function assumes the register has been unlocked by the calling application
392  **********************************************************************************************************************/
r_lpm_mcu_specific_low_power_check(lpm_cfg_t const * const p_cfg)393 fsp_err_t r_lpm_mcu_specific_low_power_check (lpm_cfg_t const * const p_cfg)
394 {
395  #if !BSP_FEATURE_LPM_HAS_DEEP_SLEEP
396     FSP_ERROR_RETURN(LPM_MODE_DEEP_SLEEP != p_cfg->low_power_mode, FSP_ERR_UNSUPPORTED)
397  #endif
398  #if !BSP_FEATURE_LPM_HAS_SNOOZE
399     FSP_ERROR_RETURN(LPM_MODE_STANDBY_SNOOZE != p_cfg->low_power_mode, FSP_ERR_UNSUPPORTED)
400  #endif
401 
402  #if BSP_FEATURE_LPM_HAS_DEEP_SLEEP
403     if ((LPM_MODE_SLEEP != p_cfg->low_power_mode) && (LPM_MODE_DEEP_SLEEP != p_cfg->low_power_mode))
404  #else
405     if (LPM_MODE_SLEEP != p_cfg->low_power_mode)
406  #endif
407     {
408         if (LPM_MODE_STANDBY_SNOOZE == p_cfg->low_power_mode)
409         {
410  #if BSP_FEATURE_LPM_HAS_SNOOZE
411   #if BSP_FEATURE_LPM_SNZREQCR_MASK
412             FSP_ERROR_RETURN(0U == ((uint64_t) p_cfg->snooze_request_source & (~BSP_FEATURE_LPM_SNZREQCR_MASK)),
413                              FSP_ERR_INVALID_ARGUMENT);
414   #endif
415   #if BSP_FEATURE_LPM_SNZEDCR_MASK > 0
416             FSP_ERROR_RETURN(0U == ((uint32_t) p_cfg->snooze_end_sources & (~BSP_FEATURE_LPM_SNZEDCR_MASK)),
417                              FSP_ERR_INVALID_ARGUMENT);
418   #endif
419  #endif
420         }
421         else if (LPM_MODE_DEEP == p_cfg->low_power_mode)
422         {
423  #if BSP_FEATURE_LPM_HAS_DEEP_STANDBY
424 
425             /* Verify the deep software standby interrupt source is valid. */
426             FSP_ERROR_RETURN(0U == (uint32_t) (~BSP_FEATURE_LPM_DPSIER_MASK & p_cfg->deep_standby_cancel_source),
427                              FSP_ERR_INVALID_MODE);
428 
429             /* Verify the deep software standby interrupt edge is valid. */
430             FSP_ERROR_RETURN(0U == (uint32_t) (~BSP_FEATURE_LPM_DPSIEGR_MASK & p_cfg->deep_standby_cancel_edge),
431                              FSP_ERR_INVALID_MODE);
432 
433             /* Verify all configured edges have a source configured. */
434             FSP_ERROR_RETURN(0U ==
435                              (~p_cfg->deep_standby_cancel_source &
436                               (lpm_deep_standby_cancel_source_t) p_cfg->deep_standby_cancel_edge),
437                              FSP_ERR_INVALID_MODE);
438  #else
439 
440             return FSP_ERR_UNSUPPORTED;
441  #endif
442         }
443         else
444         {
445             /* Do nothing. */
446         }
447 
448  #if BSP_FEATURE_ICU_WUPEN_MASK > 0
449         FSP_ERROR_RETURN(0U == ((uint64_t) p_cfg->standby_wake_sources & ~BSP_FEATURE_ICU_WUPEN_MASK),
450                          FSP_ERR_INVALID_MODE);
451  #endif
452  #if BSP_FEATURE_ICU_SBYEDCR_MASK
453         FSP_ERROR_RETURN(0U == ((uint64_t) p_cfg->standby_wake_sources & ~BSP_FEATURE_ICU_SBYEDCR_MASK),
454                          FSP_ERR_INVALID_MODE);
455  #endif
456     }
457 
458  #if BSP_FEATURE_LPM_HAS_HOCO_STARTUP_SPEED_MODE
459     FSP_ERROR_RETURN(((R_SYSTEM->FOCOSCR_b.CKSEL == 0) && (R_SYSTEM->FMAINSCR_b.CKSEL == 0) &&
460                       (R_SYSTEM->ICLKSCR_b.CKSEL == 0) && (R_SYSTEM->HOCODIV == 0)),
461                      FSP_ERR_INVALID_MODE);
462  #endif
463 
464     return FSP_SUCCESS;
465 }
466 
467 #endif
468 
469 /*******************************************************************************************************************//**
470  * Configures all MCU specific settings related to low power modes
471  * @param      p_cfg           the MCU specific configuration
472  *
473  * @note       This function assumes the register has been unlocked by the calling application
474  *
475  * @retval     FSP_SUCCESS                   Configuration is valid
476  * @retval     FSP_ERR_UNSUPPORTED           This MCU does not support Deep Software Standby
477  * @retval     FSP_ERR_ASSERTION             NULL p_extend when low power mode is not Sleep
478  * @retval     FSP_ERR_INVALID_ARGUMENT      One of the following:
479  *                                           - Invalid snooze entry source
480  *                                           - Invalid snooze end sources
481  * @retval     FSP_ERR_INVALID_MODE          One of the following:
482  *                                           - Invalid low power mode
483  *                                           - Invalid DTC option for snooze mode
484  *                                           - Invalid deep standby end sources
485  *                                           - Invalid deep standby end sources edges
486  *                                           - Invalid power supply option for deep standby
487  *                                           - Invalid IO port option for deep standby
488  *                                           - Invalid output port state setting for standby or deep standby
489  *                                           - Invalid sources for wake from standby mode
490  *                                           - Invalid power supply option for standby
491  *                                           - Invalid IO port option for standby
492  *                                           - Invalid standby end sources
493  *                                           - Invalid standby end sources edges
494  **********************************************************************************************************************/
r_lpm_configure(lpm_cfg_t const * const p_cfg)495 fsp_err_t r_lpm_configure (lpm_cfg_t const * const p_cfg)
496 {
497 #if LPM_CFG_PARAM_CHECKING_ENABLE
498     FSP_ASSERT(NULL != p_cfg);
499     fsp_err_t err = r_lpm_mcu_specific_low_power_check(p_cfg);
500     FSP_ERROR_RETURN(FSP_SUCCESS == err, err);
501 #endif
502 #if BSP_FEATURE_ICU_SBYEDCR_MASK > 0
503     uint32_t sbyedcr0 = 0;
504     uint32_t sbyedcr1 = 0;
505 #endif
506 #ifdef R_SYSTEM_SNZCR_SNZE_Msk
507     uint32_t snzcr = 0;
508 #endif
509     uint32_t sbycr = 0;
510 #if BSP_FEATURE_LPM_HAS_DEEP_STANDBY
511     uint32_t dpsbycr = 0;
512 #endif
513 
514 #if BSP_FEATURE_LPM_HAS_LDO_CONTROL
515     if ((R_SYSTEM->PLL1LDOCR_b.SKEEP != p_cfg->ldo_standby_cfg.pll1_ldo) ||
516         (R_SYSTEM->PLL2LDOCR_b.SKEEP != p_cfg->ldo_standby_cfg.pll2_ldo) ||
517         (R_SYSTEM->HOCOLDOCR_b.SKEEP != p_cfg->ldo_standby_cfg.hoco_ldo))
518     {
519         /* Writing to PLL1LDOCR, PLL2LDOCR and HOCOLDOCR registers is only allowed in High Speed Mode. */
520         FSP_ERROR_RETURN(R_SYSTEM->OPCCR_b.OPCM == 0, FSP_ERR_INVALID_MODE);
521     }
522 #endif
523 
524     R_BSP_RegisterProtectDisable(BSP_REG_PROTECT_OM_LPC_BATT);
525 
526     /* Wait for ongoing operating mode transition (OPCMTSF, SOPCMTSF) */
527     r_lpm_wait_for_operating_mode_flags();
528 
529     /* Configure registers for modes other than Sleep */
530     if (LPM_MODE_SLEEP != p_cfg->low_power_mode)
531     {
532 #if BSP_FEATURE_LPM_HAS_DEEP_STANDBY
533 
534         /* Configure Deep Software Standby registers. */
535         if (LPM_MODE_DEEP == p_cfg->low_power_mode)
536         {
537             R_SYSTEM->DPSIER0 = (uint8_t) (p_cfg->deep_standby_cancel_source);
538             R_SYSTEM->DPSIER1 = (uint8_t) (p_cfg->deep_standby_cancel_source >> 8U);
539             R_SYSTEM->DPSIER2 = (uint8_t) (p_cfg->deep_standby_cancel_source >> 16U);
540             R_SYSTEM->DPSIER3 = (uint8_t) (p_cfg->deep_standby_cancel_source >> 24U);
541 
542             R_SYSTEM->DPSIEGR0 = (uint8_t) (p_cfg->deep_standby_cancel_edge);
543             R_SYSTEM->DPSIEGR1 = (uint8_t) (p_cfg->deep_standby_cancel_edge >> 8U);
544             R_SYSTEM->DPSIEGR2 = (uint8_t) (p_cfg->deep_standby_cancel_edge >> 16U);
545 
546  #if BSP_FEATURE_LPM_HAS_DPSBYCR_DPSBY
547             dpsbycr |= R_SYSTEM_DPSBYCR_DPSBY_Msk;
548  #endif
549  #if BSP_FEATURE_LPM_HAS_DPSBYCR_DEEPCUT
550             dpsbycr |= ((uint32_t) p_cfg->power_supply_state << R_SYSTEM_DPSBYCR_DEEPCUT_Pos) &
551                        R_SYSTEM_DPSBYCR_DEEPCUT_Msk;
552  #endif
553             dpsbycr |= ((uint32_t) p_cfg->io_port_state << R_SYSTEM_DPSBYCR_IOKEEP_Pos) & R_SYSTEM_DPSBYCR_IOKEEP_Msk;
554         }
555 #endif
556 
557 #if BSP_FEATURE_LPM_HAS_SNOOZE
558 
559         /* Configure Snooze registers */
560         if (LPM_MODE_STANDBY_SNOOZE == p_cfg->low_power_mode)
561         {
562  #if BSP_FEATURE_LPM_SNZREQCR_MASK > 0
563 
564             /* Configure RXD0 falling edge detect */
565             if (LPM_SNOOZE_REQUEST_RXD0_FALLING == p_cfg->snooze_request_source)
566             {
567                 snzcr = 1U << R_SYSTEM_SNZCR_RXDREQEN_Pos;
568             }
569 
570             /* Set the request condition that can trigger entry in to snooze mode */
571             R_SYSTEM->SNZREQCR = (uint32_t) p_cfg->snooze_request_source & UINT32_MAX;
572  #endif
573  #if BSP_FEATURE_LPM_HAS_SNZREQCR1 == 1
574             R_SYSTEM->SNZREQCR1 = (uint32_t) (p_cfg->snooze_request_source >> LPM_SNZREQCR1_OFFSET) & UINT32_MAX;
575  #endif
576  #if BSP_FEATURE_LPM_HAS_HOCO_STARTUP_SPEED_MODE
577 
578             /* Set the startup speed of the HOCO when entering snooze mode. */
579             sbycr |= (uint32_t) (p_cfg->lpm_hoco_startup_speed << R_SYSTEM_SBYCR_FWKUP_Pos);
580  #endif
581  #if BSP_FEATURE_LPM_HAS_STANDBY_SOSC_SELECT
582 
583             /* Set the SOSC state in snooze mode. */
584             sbycr |= (uint32_t) (p_cfg->lpm_standby_sosc << R_SYSTEM_SBYCR_RTCLPC_Pos);
585  #endif
586  #ifdef R_SYSTEM_SNZCR_SNZE_Msk
587 
588             /* Enable/disable DTC operation */
589             snzcr |= (uint32_t) (p_cfg->dtc_state_in_snooze << R_SYSTEM_SNZCR_SNZDTCEN_Pos);
590 
591             /* Set the source that can cause an exit from snooze to normal mode */
592             R_ICU->SELSR0_b.SELS = R_ICU_SELSR0_SELS_Msk & p_cfg->snooze_cancel_sources;
593  #endif
594  #if BSP_FEATURE_ICU_SBYEDCR_MASK > 0
595 
596             /* Set the source that can cause an exit from snooze to normal mode */
597             sbyedcr0 |= (uint32_t) p_cfg->snooze_cancel_sources & UINT32_MAX;;
598  #endif
599  #if BSP_FEATURE_LPM_SNZREQCR_MASK > 0
600 
601             /* Set all sources that can cause an exit from snooze mode to software standby. */
602             R_SYSTEM->SNZEDCR = (uint8_t) p_cfg->snooze_end_sources & UINT8_MAX;
603  #endif
604  #if BSP_FEATURE_LPM_HAS_SNZEDCR1 == 1
605             R_SYSTEM->SNZEDCR1 = (uint8_t) (p_cfg->snooze_end_sources >> 8U) & UINT8_MAX;
606  #endif
607         }
608 #endif
609 
610 #if BSP_FEATURE_LPM_HAS_DEEP_SLEEP
611         if (LPM_MODE_DEEP_SLEEP != p_cfg->low_power_mode)
612 #endif
613         {
614             /* Set SBYCR to Standby/Deep Standby. */
615 #if BSP_FEATURE_LPM_HAS_SBYCR_OPE
616             sbycr = ((uint32_t) p_cfg->output_port_enable) << R_SYSTEM_SBYCR_OPE_Pos;
617 #elif BSP_FEATURE_LPM_SBYCR_WRITE1_B14
618             sbycr = R_SYSTEM_SBYCR_OPE_Msk;
619 #endif
620 
621 #if BSP_FEATURE_LPM_HAS_SBYCR_SSBY
622             sbycr |= R_SYSTEM_SBYCR_SSBY_Msk;
623 #endif
624 
625 #if BSP_FEATURE_LPM_HAS_DPSBYCR_SRKEEP
626 
627             /* Configure Standby RAM retention in software standby and deep software standby modes. */
628             dpsbycr |= (uint8_t) (p_cfg->ram_retention_cfg.standby_ram_retention << R_SYSTEM_DPSBYCR_SRKEEP_Pos);
629 #endif
630         }
631 
632         if ((LPM_MODE_SLEEP == p_cfg->low_power_mode) || (LPM_MODE_STANDBY_SNOOZE == p_cfg->low_power_mode))
633         {
634 #if BSP_FEATURE_LPM_HAS_FLASH_MODE_SELECT
635 
636             /* Flash mode in sleep mode or in snooze mode. */
637             sbycr |= (uint32_t) (p_cfg->lpm_flash_mode_select << R_SYSTEM_SBYCR_FLSTP_Pos);
638 #endif
639         }
640 
641         if ((LPM_MODE_DEEP_SLEEP == p_cfg->low_power_mode) || (LPM_MODE_STANDBY == p_cfg->low_power_mode))
642         {
643 #if BSP_FEATURE_LPM_HAS_PDRAMSCR
644 
645             /* Configure TCM retention settings in deep sleep or standby mode. */
646             R_SYSTEM->PDRAMSCR1 = p_cfg->ram_retention_cfg.tcm_retention;
647 #endif
648         }
649 
650         if (LPM_MODE_STANDBY == p_cfg->low_power_mode)
651         {
652 #if BSP_FEATURE_LPM_HAS_PDRAMSCR
653 
654             /* Configure RAM retention settings in standby mode. */
655             R_SYSTEM->PDRAMSCR0 = p_cfg->ram_retention_cfg.ram_retention;
656 #endif
657 
658 #if BSP_FEATURE_LPM_HAS_LDO_CONTROL
659 
660             /* PLL1LDOCR may only be written in High Speed Mode. If PLL1DOCR setting is not changed, then skip
661              * writing to it. */
662             if (R_SYSTEM->PLL1LDOCR_b.SKEEP != p_cfg->ldo_standby_cfg.pll1_ldo)
663             {
664                 R_SYSTEM->PLL1LDOCR_b.SKEEP = (uint8_t) (p_cfg->ldo_standby_cfg.pll1_ldo & 0x01);
665             }
666 
667             /* PLL2LDOCR may only be written in High Speed Mode. If PLL2DOCR setting is not changed, then skip
668              * writing to it. */
669             if (R_SYSTEM->PLL2LDOCR_b.SKEEP != p_cfg->ldo_standby_cfg.pll2_ldo)
670             {
671                 R_SYSTEM->PLL2LDOCR_b.SKEEP = (uint8_t) (p_cfg->ldo_standby_cfg.pll2_ldo & 0x01);
672             }
673 
674             /* HOCOLDOCR may only be written in High Speed Mode. If HOCOLDOCR setting is not changed, then skip
675              * writing to it. */
676             if (R_SYSTEM->HOCOLDOCR_b.SKEEP != p_cfg->ldo_standby_cfg.hoco_ldo)
677             {
678                 R_SYSTEM->HOCOLDOCR_b.SKEEP = (uint8_t) (p_cfg->ldo_standby_cfg.hoco_ldo & 0x01);
679             }
680 #endif
681 #if BSP_FEATURE_LPM_HAS_STANDBY_SOSC_SELECT
682 
683             /* Set the SOSC state in standby Mode. */
684             sbycr |= (uint32_t) (p_cfg->lpm_standby_sosc << R_SYSTEM_SBYCR_RTCLPC_Pos);
685 #endif
686         }
687 
688 #if BSP_FEATURE_ICU_WUPEN_MASK > 0
689         R_ICU->WUPEN = (uint32_t) p_cfg->standby_wake_sources & UINT32_MAX;
690 #endif
691 #if BSP_FEATURE_ICU_HAS_WUPEN1 == 1
692         R_ICU->WUPEN1 = (uint32_t) (p_cfg->standby_wake_sources >> LPM_WUPEN1_OFFSET) & UINT32_MAX;
693 #endif
694 #if BSP_FEATURE_ICU_SBYEDCR_MASK > 0
695         sbyedcr0 |= (uint32_t) p_cfg->standby_wake_sources & UINT32_MAX;
696         sbyedcr1 |= (uint32_t) (p_cfg->standby_wake_sources >> LPM_SBYEDCR1_OFFSET) & UINT32_MAX;
697 #endif
698     }
699     else
700     {
701         /* Set SBYCR to Sleep mode. */
702 #if BSP_FEATURE_LPM_SBYCR_WRITE1_B14
703         sbycr = 1U << R_SYSTEM_SBYCR_OPE_Pos;
704 #elif BSP_FEATURE_LPM_HAS_FLASH_MODE_SELECT
705 
706         /* Flash mode in sleep mode or in snooze mode. */
707         sbycr |= (uint32_t) (p_cfg->lpm_flash_mode_select << R_SYSTEM_SBYCR_FLSTP_Pos);
708 #else
709         sbycr = 0;
710 #endif
711     }
712 
713 #if BSP_FEATURE_ICU_SBYEDCR_MASK > 0
714     R_ICU->SBYEDCR0 = sbyedcr0;
715     R_ICU->SBYEDCR1 = sbyedcr1;
716 #endif
717 #if BSP_FEATURE_LPM_HAS_SBYCR_SSBY
718  #if LPM_CFG_STANDBY_LIMIT
719     R_SYSTEM->SBYCR = (uint16_t) (sbycr & ~(1U << R_SYSTEM_SBYCR_SSBY_Pos));
720  #else
721     R_SYSTEM->SBYCR = (uint16_t) sbycr;
722  #endif
723 #else
724     R_SYSTEM->SBYCR = (uint8_t) sbycr;
725 #endif
726 
727 #if BSP_FEATURE_LPM_HAS_LPSCR
728  #if !LPM_CFG_STANDBY_LIMIT
729     R_SYSTEM->LPSCR = r_lpm_lpscr_calculate(p_cfg);
730  #else
731     R_SYSTEM->LPSCR = 0;
732  #endif
733 #endif
734 
735 #ifdef R_SYSTEM_SNZCR_SNZE_Msk
736     R_SYSTEM->SNZCR = (uint8_t) snzcr;
737 #endif
738 
739 #if BSP_FEATURE_LPM_HAS_DEEP_STANDBY
740     R_SYSTEM->DPSBYCR = (uint8_t) dpsbycr;
741 #endif
742 
743     R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_OM_LPC_BATT);
744 
745     return FSP_SUCCESS;
746 }
747 
748 #ifdef R_SYSTEM_SNZCR_SNZE_Msk
749 
750 /*******************************************************************************************************************//**
751  * Check the clock settings
752  *
753  * @param[in]  clock_source  The clock source
754  *
755  * @retval     FSP_SUCCESS                   Clock settings are valid.
756  * @retval     FSP_ERR_INVALID_MODE          One of the following:
757  *                                           - HOCO was not system clock when using snooze mode with SCI0/RXD0.
758  *                                           - HOCO was not stable when using snooze mode with SCI0/RXD0.
759  *                                           - MOCO was running when using snooze mode with SCI0/RXD0.
760  *                                           - MAIN OSCILLATOR was running when using snooze mode with SCI0/RXD0.
761  *                                           - PLL was running when using snooze mode with SCI0/RXD0.
762  *                                           - PLL2 was running when using snooze mode with SCI0/RXD0.
763  **********************************************************************************************************************/
r_lpm_check_clocks(uint32_t clock_source)764 fsp_err_t r_lpm_check_clocks (uint32_t clock_source)
765 {
766     /* Verify the clock source is HOCO */
767     FSP_ERROR_RETURN(LPM_CLOCK_HOCO == clock_source, FSP_ERR_INVALID_MODE);
768 
769     /* Verify Moco, Main Osc and PLL are stopped. */
770     FSP_ERROR_RETURN(1U == (*gp_lpm_clock_stp_registers[LPM_CLOCK_MOCO]), FSP_ERR_INVALID_MODE);
771     FSP_ERROR_RETURN(1U == (*gp_lpm_clock_stp_registers[LPM_CLOCK_MAIN_OSC]), FSP_ERR_INVALID_MODE);
772  #if BSP_FEATURE_CGC_HAS_PLL
773     FSP_ERROR_RETURN(1U == (*gp_lpm_clock_stp_registers[LPM_CLOCK_PLL]), FSP_ERR_INVALID_MODE);
774  #endif
775  #if BSP_FEATURE_CGC_HAS_PLL2
776     FSP_ERROR_RETURN(1U == (*gp_lpm_clock_stp_registers[LPM_CLOCK_PLL2]), FSP_ERR_INVALID_MODE);
777  #endif
778 
779     return FSP_SUCCESS;
780 }
781 
782 #endif
783 
784 /*******************************************************************************************************************//**
785  * Perform pre-WFI execution tasks, enter low power mode, Perform post-WFI execution tasks
786  *
787  * @note       This function will unlock and lock registers as needed
788  *
789  * @retval     FSP_SUCCESS                   Successfully entered and woke from low power mode.
790  * @retval     FSP_ERR_INVALID_MODE          One of the following:
791  *                                           - FLL function is enabled when requesting Software Standby.
792  *                                           - HOCO was not system clock when using snooze mode with SCI0/RXD0.
793  *                                           - HOCO was not stable when using snooze mode with SCI0/RXD0.
794  *                                           - MOCO was running when using snooze mode with SCI0/RXD0.
795  *                                           - MAIN OSCILLATOR was running when using snooze mode with SCI0/RXD0.
796  *                                           - PLL was running when using snooze mode with SCI0/RXD0.
797  *                                           - Unable to disable ocillator stop detect when using standby or deep standby.
798  **********************************************************************************************************************/
r_lpm_low_power_enter(lpm_instance_ctrl_t * const p_instance_ctrl)799 fsp_err_t r_lpm_low_power_enter (lpm_instance_ctrl_t * const p_instance_ctrl)
800 {
801 #if BSP_FEATURE_LPM_HAS_DEEP_STANDBY
802     uint32_t           saved_opccr = 0U;
803     uint8_t volatile * p_opccr     = &R_SYSTEM->OPCCR;
804  #if BSP_FEATURE_CGC_HAS_SOPCCR
805     uint32_t saved_sopccr = 0U;
806  #endif
807     uint32_t           saved_ostdcr_ostde = 0U;
808     uint8_t volatile * p_ostde            = &R_SYSTEM->OSTDCR;
809  #if BSP_FEATURE_CGC_HOCOWTCR_SCI_SNOOZE_VALUE > 0
810     uint32_t saved_hocowtcr = 0U;
811     uint32_t new_hocowtcr   = 0U;
812  #endif
813  #if BSP_FEATURE_BSP_POWER_CHANGE_MSTP_REQUIRED
814     uint32_t stopped_modules = 0;
815  #endif
816 #endif
817 
818 #if BSP_PRV_POWER_USE_DCDC
819     bsp_power_mode_t power_mode = BSP_POWER_MODE_LDO;
820 #endif
821 
822 #if BSP_TZ_SECURE_BUILD && BSP_FEATURE_TZ_VERSION == 2
823     if (1 == R_SYSTEM->LPMSAR_b.NONSEC0)
824     {
825         /* If security attribution of OPCCR is set to non-secure, then use the non-secure alias. */
826         p_opccr = (uint8_t volatile *) ((uint32_t) p_opccr | BSP_FEATURE_TZ_NS_OFFSET);
827     }
828 
829     if (1 == R_SYSTEM->CGFSAR_b.NONSEC06)
830     {
831         /* If security attribution of OSTDCR is set to non-secure, then use the non-secure alias. */
832         p_ostde = (uint8_t volatile *) ((uint32_t) p_ostde | BSP_FEATURE_TZ_NS_OFFSET);
833     }
834 #endif
835 #if BSP_FEATURE_LPM_HAS_SBYCR_SSBY
836     if (1U == R_SYSTEM->SBYCR_b.SSBY)
837 #else
838     if (LPM_LPSCR_SOFTWARE_STANDBY_MODE <= R_SYSTEM->LPSCR)
839 #endif
840     {
841         /* Execute pre-wfi standby tasks */
842 
843 #if BSP_PRV_HOCO_USE_FLL
844 
845         /* If FLL is available it must not be active when entering Software Standby. */
846         FSP_ERROR_RETURN(0U == R_SYSTEM->FLLCR1, FSP_ERR_INVALID_MODE);
847 #endif
848 
849 #if BSP_FEATURE_LPM_HAS_SNOOZE
850 
851         /* Get system clock */
852  #if BSP_FEATURE_CGC_STARTUP_SCKSCR
853         uint32_t clock_source = R_SYSTEM->SCKSCR;
854  #endif
855 #endif
856 
857 #if !BSP_FEATURE_LPM_HAS_DEEP_STANDBY
858  #ifdef R_SYSTEM_SNZCR_SNZE_Msk
859         if (1U == R_SYSTEM->SNZCR_b.RXDREQEN)
860         {
861             /* Verify clock settings. */
862             FSP_ERROR_RETURN(FSP_SUCCESS == r_lpm_check_clocks(clock_source), FSP_ERR_INVALID_MODE);
863         }
864  #endif
865 #else
866 
867         /* Save the OPCCR and SOPCCR registers. When transitioning from Software Standby mode to Normal or Snooze mode
868          * these registers are overwritten. See Section 11.2.6 "Operating Power Control Register" in the RA6M3 manual
869          * R01UM0004EU0110 */
870         saved_opccr = (*p_opccr & R_SYSTEM_OPCCR_OPCM_Msk) >> R_SYSTEM_OPCCR_OPCM_Pos;
871  #if BSP_FEATURE_CGC_HAS_SOPCCR
872         saved_sopccr = R_SYSTEM->SOPCCR_b.SOPCM;
873  #endif
874 
875  #if BSP_FEATURE_CGC_HOCOWTCR_SCI_SNOOZE_VALUE > 0
876 
877         /* Save HOCOWTCR_b.HSTS */
878         saved_hocowtcr = R_SYSTEM->HOCOWTCR_b.HSTS;
879  #endif
880 
881  #if BSP_FEATURE_LPM_HAS_SBYCR_SSBY
882         if (0U == R_SYSTEM->DPSBYCR_b.DPSBY)
883  #else
884         if (LPM_LPSCR_DEEP_SOFTWARE_STANDBY_MODE1 > R_SYSTEM->LPSCR)
885  #endif
886         {
887  #if BSP_FEATURE_LPM_HAS_SNOOZE
888 
889             /* Check Snooze configuration settings. Set HOCOWTCR based on current configuration. See Section 11.2.1
890              * "Standby Control Register" in the RA6M3 manual  R01UM0004EU0110 */
891             if (1U == R_SYSTEM->SNZCR_b.RXDREQEN)
892             {
893                 /* Verify clock settings. */
894                 FSP_ERROR_RETURN(FSP_SUCCESS == r_lpm_check_clocks(clock_source), FSP_ERR_INVALID_MODE);
895   #if BSP_FEATURE_CGC_HOCOWTCR_SCI_SNOOZE_VALUE > 0
896                 new_hocowtcr = BSP_FEATURE_CGC_HOCOWTCR_SCI_SNOOZE_VALUE;
897             }
898             else
899             {
900                 new_hocowtcr = BSP_FEATURE_CGC_HOCOWTCR_VALUE;
901   #endif
902             }
903 
904  #else
905   #if BSP_FEATURE_CGC_HAS_HOCOWTCR == 1
906             new_hocowtcr = LPM_SW_STANDBY_HOCOWTCR_HSTS;
907   #endif
908  #endif
909 
910             /* Enable writing to CGC register. */
911             R_BSP_RegisterProtectDisable(BSP_REG_PROTECT_CGC);
912 
913  #if BSP_FEATURE_LPM_HAS_STCONR == 1
914 
915             /* Set STCONR based on the current system clock. */
916             if (LPM_CLOCK_HOCO == clock_source)
917             {
918   #if BSP_FEATURE_CGC_HOCOWTCR_SCI_SNOOZE_VALUE > 0
919 
920                 /* Set HOCOWTCR_b.HSTS when using HOCO as the system clock */
921                 R_SYSTEM->HOCOWTCR_b.HSTS = R_SYSTEM_HOCOWTCR_HSTS_Msk & (new_hocowtcr << R_SYSTEM_HOCOWTCR_HSTS_Pos);
922   #endif
923 
924                 R_SYSTEM->STCONR = LPM_SW_STANDBY_STCONR;
925             }
926             else
927             {
928                 R_SYSTEM->STCONR = LPM_SW_STANDBY_WAKE_STCONR;
929             }
930  #endif
931         }
932         else
933         {
934             /* Enable writing to CGC register. */
935             R_BSP_RegisterProtectDisable(BSP_REG_PROTECT_CGC);
936 
937             /* Execute pre-wfi deep standby tasks */
938             /* Clear the DOCDF flag to 0 before entering Deep Software Standby mode. */
939             R_SYSTEM->SYOCDCR_b.DOCDF = 0U;
940 
941             /* Clear Deep Software Standby Interrupt Flag Registers. A dummy read is required before writing to DPSIFR.
942              * See Section 11.2.16 "Deep Software Standby Interrupt Flag Register 0" in the
943              * RA6M3 manual  R01UM0004EU0110 */
944             R_SYSTEM->DPSIFR0;
945             R_SYSTEM->DPSIFR0 = 0U;
946 
947             R_SYSTEM->DPSIFR1;
948             R_SYSTEM->DPSIFR1 = 0U;
949 
950             R_SYSTEM->DPSIFR2;
951             R_SYSTEM->DPSIFR2 = 0U;
952 
953             R_SYSTEM->DPSIFR3;
954             R_SYSTEM->DPSIFR3 = 0U;
955         }
956 
957         /* Save oscillator stop detect state. */
958         saved_ostdcr_ostde = (*p_ostde & R_SYSTEM_OSTDCR_OSTDE_Msk) >> R_SYSTEM_OSTDCR_OSTDE_Pos;
959         *p_ostde          &= (uint8_t) ~R_SYSTEM_OSTDCR_OSTDE_Msk;
960 
961  #if BSP_FEATURE_BSP_POWER_CHANGE_MSTP_REQUIRED
962         stopped_modules = bsp_prv_power_change_mstp_set();
963 
964         /* Delay for >750 ns if any modules changed state */
965         if (0 != stopped_modules)
966         {
967             R_BSP_SoftwareDelay(1U, BSP_DELAY_UNITS_MICROSECONDS);
968         }
969  #endif
970 #endif
971 #if BSP_PRV_POWER_USE_DCDC
972 
973         /* DCDC cannot be used in Software Standby, so switch back to LDO if needed (see RA2L1 User's Manual
974          * (R01UH0853EJ0100) Section 40.3 Usage Notes). */
975         if (R_SYSTEM->DCDCCTL & R_SYSTEM_DCDCCTL_DCDCON_Msk)
976         {
977             power_mode = R_BSP_PowerModeSet(BSP_POWER_MODE_LDO_BOOST);
978         }
979 #endif
980     }
981 
982 #if BSP_FEATURE_LPM_HAS_SNOOZE
983     if (LPM_MODE_STANDBY_SNOOZE == p_instance_ctrl->p_cfg->low_power_mode)
984     {
985  #ifdef R_SYSTEM_SNZCR_SNZE_Msk
986 
987         /* Enable Snooze mode (SNZCR.SNZE = 1) immediately before entering to Software Standby mode.
988          * See Section 11.8.2 "Canceling Snooze Mode" in the RA6M3 manual  R01UM0004EU0110 */
989         R_SYSTEM->SNZCR_b.SNZE = 1;
990 
991         /* Dummy read required.
992          * infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dai0321a/BIHICBGB.html */
993         R_SYSTEM->SNZCR;
994  #endif
995     }
996 #endif
997 
998 #if BSP_FEATURE_LPM_HAS_DEEP_SLEEP
999     if (LPM_MODE_SLEEP != p_instance_ctrl->p_cfg->low_power_mode)
1000     {
1001         /* Set the SLEEPDEEP bit. */
1002         SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
1003     }
1004 #endif
1005 
1006 #if BSP_CFG_SLEEP_MODE_DELAY_ENABLE
1007     bool clock_slowed = bsp_prv_clock_prepare_pre_sleep();
1008 #endif
1009 
1010     /* DSB should be last instruction executed before WFI
1011      * infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dai0321a/BIHICBGB.html */
1012     __DSB();
1013 
1014     __WFI();
1015 
1016 #if BSP_CFG_SLEEP_MODE_DELAY_ENABLE
1017     bsp_prv_clock_prepare_post_sleep(clock_slowed);
1018 #endif
1019 
1020 #if BSP_FEATURE_LPM_HAS_DEEP_SLEEP
1021     if (LPM_MODE_SLEEP != p_instance_ctrl->p_cfg->low_power_mode)
1022     {
1023         /* Clear the SLEEPDEEP bit. */
1024         SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
1025     }
1026 #endif
1027 
1028 #ifdef R_SYSTEM_SNZCR_SNZE_Msk
1029 
1030     /* Disable Snooze mode (SNZCR.SNZE = 0) immediately after canceling Snooze mode.
1031      * See Section 11.8.2 "Canceling Snooze Mode" in the RA6M3 manual  R01UM0004EU0110 */
1032     R_SYSTEM->SNZCR_b.SNZE = 0;
1033 #endif
1034 #if BSP_FEATURE_LPM_HAS_DEEP_STANDBY || (BSP_PRV_POWER_USE_DCDC)
1035  #if BSP_FEATURE_LPM_HAS_SBYCR_SSBY
1036     if (1U == R_SYSTEM->SBYCR_b.SSBY)
1037  #else
1038     if (LPM_LPSCR_SOFTWARE_STANDBY_MODE <= R_SYSTEM->LPSCR)
1039  #endif
1040     {
1041  #if BSP_FEATURE_LPM_HAS_DEEP_STANDBY
1042 
1043         /* Wait for ongoing operating mode transition (OPCMTSF, SOPCMTSF) */
1044         r_lpm_wait_for_operating_mode_flags();
1045 
1046         /* Restore system registers to the values prior to entering standby. */
1047         *p_opccr = saved_opccr & R_SYSTEM_OPCCR_OPCM_Msk;
1048 
1049   #if BSP_FEATURE_CGC_HAS_SOPCCR
1050         R_SYSTEM->SOPCCR = saved_sopccr & R_SYSTEM_SOPCCR_SOPCM_Msk;
1051   #endif
1052 
1053         *p_ostde |= (uint8_t) saved_ostdcr_ostde;
1054   #if BSP_FEATURE_CGC_HOCOWTCR_SCI_SNOOZE_VALUE > 0
1055         R_SYSTEM->HOCOWTCR_b.HSTS = R_SYSTEM_HOCOWTCR_HSTS_Msk & (saved_hocowtcr << R_SYSTEM_HOCOWTCR_HSTS_Pos);
1056   #endif
1057 
1058         /* Disable writing to CGC register. */
1059         R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_CGC);
1060 
1061   #if BSP_FEATURE_BSP_POWER_CHANGE_MSTP_REQUIRED
1062         bsp_prv_power_change_mstp_clear(stopped_modules);
1063   #endif
1064  #endif
1065  #if BSP_PRV_POWER_USE_DCDC
1066         if (power_mode < BSP_POWER_MODE_LDO)
1067         {
1068             /* Switch back to DCDC if it was enabled before. */
1069             R_BSP_PowerModeSet(power_mode);
1070         }
1071  #endif
1072     }
1073 #endif
1074 
1075     return FSP_SUCCESS;
1076 }
1077 
1078 /*******************************************************************************************************************//**
1079  * Wait for opccr and sopccr transition flags to clear.
1080  **********************************************************************************************************************/
r_lpm_wait_for_operating_mode_flags(void)1081 void r_lpm_wait_for_operating_mode_flags (void)
1082 {
1083 #if BSP_FEATURE_CGC_HAS_OPCCR
1084 
1085     /* Wait for transition to complete. */
1086     FSP_HARDWARE_REGISTER_WAIT((FSP_STYPE3_REG8_READ(R_SYSTEM->OPCCR,
1087                                                      !R_SYSTEM->LPMSAR_b.NONSEC0) & R_SYSTEM_OPCCR_OPCMTSF_Msk),
1088                                0U);
1089 #endif
1090 
1091 #if BSP_FEATURE_CGC_HAS_SOPCCR
1092 
1093     /* Wait for transition to complete. */
1094     FSP_HARDWARE_REGISTER_WAIT(R_SYSTEM->SOPCCR_b.SOPCMTSF, 0U);
1095 #endif
1096 }
1097 
1098 #if BSP_FEATURE_LPM_HAS_LPSCR
1099 
1100 /*******************************************************************************************************************//**
1101  * Calculate the correct value of LPSCR based on the mode.
1102  **********************************************************************************************************************/
r_lpm_lpscr_calculate(lpm_cfg_t const * p_cfg)1103 static uint8_t r_lpm_lpscr_calculate (lpm_cfg_t const * p_cfg)
1104 {
1105     uint8_t lpscr = 0;
1106 
1107     switch (p_cfg->low_power_mode)
1108     {
1109         case LPM_MODE_SLEEP:
1110         {
1111             lpscr = LPM_LPSCR_SYSTEM_ACTIVE;
1112             break;
1113         }
1114 
1115         case LPM_MODE_DEEP_SLEEP:
1116         {
1117             lpscr = LPM_LPSCR_SYSTEM_ACTIVE;
1118             break;
1119         }
1120 
1121         case LPM_MODE_STANDBY:
1122         {
1123             lpscr = LPM_LPSCR_SOFTWARE_STANDBY_MODE;
1124             break;
1125         }
1126 
1127         case LPM_MODE_DEEP:
1128         {
1129             lpscr  = LPM_LPSCR_DEEP_SOFTWARE_STANDBY_MODE1;
1130             lpscr |= p_cfg->power_supply_state;
1131             break;
1132         }
1133 
1134         default:
1135         {
1136             break;
1137         }
1138     }
1139 
1140     return lpscr;
1141 }
1142 
1143 #endif
1144