1 /*
2 * Copyright (c) 2021 STMicroelectronics.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #include <zephyr/kernel.h>
7 #include <zephyr/pm/pm.h>
8 #include <soc.h>
9 #include <zephyr/init.h>
10
11 #include <stm32l5xx_ll_utils.h>
12 #include <stm32l5xx_ll_bus.h>
13 #include <stm32l5xx_ll_cortex.h>
14 #include <stm32l5xx_ll_pwr.h>
15 #include <stm32l5xx_ll_rcc.h>
16 #include <stm32l5xx_ll_system.h>
17 #include <clock_control/clock_stm32_ll_common.h>
18 #include <zephyr/drivers/clock_control/stm32_clock_control.h>
19
20 #include <zephyr/logging/log.h>
21 LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL);
22
23 /* select MSI as wake-up system clock if configured, HSI otherwise */
24 #if STM32_SYSCLK_SRC_MSI
25 #define RCC_STOP_WAKEUPCLOCK_SELECTED LL_RCC_STOP_WAKEUPCLOCK_MSI
26 #else
27 #define RCC_STOP_WAKEUPCLOCK_SELECTED LL_RCC_STOP_WAKEUPCLOCK_HSI
28 #endif
29
30 /* Invoke Low Power/System Off specific Tasks */
pm_state_set(enum pm_state state,uint8_t substate_id)31 void pm_state_set(enum pm_state state, uint8_t substate_id)
32 {
33 if (state != PM_STATE_SUSPEND_TO_IDLE) {
34 LOG_DBG("Unsupported power state %u", state);
35 return;
36 }
37
38 /* ensure the proper wake-up system clock */
39 LL_RCC_SetClkAfterWakeFromStop(RCC_STOP_WAKEUPCLOCK_SELECTED);
40
41 switch (substate_id) {
42 case 1: /* this corresponds to the STOP0 mode: */
43 /* enter STOP0 mode */
44 LL_PWR_SetPowerMode(LL_PWR_MODE_STOP0);
45 break;
46 case 2: /* this corresponds to the STOP1 mode: */
47 /* enter STOP1 mode */
48 LL_PWR_SetPowerMode(LL_PWR_MODE_STOP1);
49 break;
50 case 3: /* this corresponds to the STOP2 mode: */
51 #ifdef PWR_CR1_RRSTP
52 LL_PWR_DisableSRAM3Retention();
53 #endif /* PWR_CR1_RRSTP */
54 /* enter STOP2 mode */
55 LL_PWR_SetPowerMode(LL_PWR_MODE_STOP2);
56 break;
57 default:
58 LOG_DBG("Unsupported power state substate-id %u",
59 substate_id);
60 break;
61 }
62
63 LL_LPM_EnableDeepSleep();
64 /* enter SLEEP mode : WFE or WFI */
65 k_cpu_idle();
66 }
67
68 /* Handle SOC specific activity after Low Power Mode Exit */
pm_state_exit_post_ops(enum pm_state state,uint8_t substate_id)69 void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id)
70 {
71 if (state != PM_STATE_SUSPEND_TO_IDLE) {
72 LOG_DBG("Unsupported power substate-id %u", state);
73 } else {
74 switch (substate_id) {
75 case 1: /* STOP0 */
76 __fallthrough;
77 case 2: /* STOP1 */
78 __fallthrough;
79 case 3: /* STOP2 */
80 LL_LPM_DisableSleepOnExit();
81 LL_LPM_EnableSleep();
82 break;
83 default:
84 LOG_DBG("Unsupported power substate-id %u",
85 substate_id);
86 break;
87 }
88 /* need to restore the clock */
89 stm32_clock_control_init(NULL);
90 }
91
92 /*
93 * System is now in active mode.
94 * Reenable interrupts which were disabled
95 * when OS started idling code.
96 */
97 irq_unlock(0);
98 }
99
100 /* Initialize STM32 Power */
stm32_power_init(void)101 void stm32_power_init(void)
102 {
103
104 /* enable Power clock */
105 LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_PWR);
106 }
107