1 /*
2  * Copyright (c) 2021 Fabio Baltieri
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 <stm32l0xx_ll_utils.h>
12 #include <stm32l0xx_ll_bus.h>
13 #include <stm32l0xx_ll_cortex.h>
14 #include <stm32l0xx_ll_pwr.h>
15 #include <stm32l0xx_ll_rcc.h>
16 #include <stm32l0xx_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 	ARG_UNUSED(substate_id);
34 
35 	switch (state) {
36 	case PM_STATE_SUSPEND_TO_IDLE:
37 		LL_RCC_SetClkAfterWakeFromStop(RCC_STOP_WAKEUPCLOCK_SELECTED);
38 		LL_PWR_ClearFlag_WU();
39 		LL_PWR_SetPowerMode(LL_PWR_MODE_STOP);
40 		LL_PWR_SetRegulModeLP(LL_PWR_REGU_LPMODES_LOW_POWER);
41 		LL_LPM_EnableDeepSleep();
42 		k_cpu_idle();
43 		break;
44 	default:
45 		LOG_DBG("Unsupported power state %u", state);
46 		break;
47 	}
48 }
49 
50 /* Handle SOC specific activity after Low Power Mode Exit */
pm_state_exit_post_ops(enum pm_state state,uint8_t substate_id)51 void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id)
52 {
53 	ARG_UNUSED(substate_id);
54 
55 	switch (state) {
56 	case PM_STATE_SUSPEND_TO_IDLE:
57 		LL_LPM_DisableSleepOnExit();
58 		LL_LPM_EnableSleep();
59 		LL_PWR_SetRegulModeLP(LL_PWR_REGU_LPMODES_MAIN);
60 
61 		/* Restore the clock setup. */
62 		stm32_clock_control_init(NULL);
63 		break;
64 	default:
65 		LOG_DBG("Unsupported power substate-id %u", state);
66 		break;
67 	}
68 
69 	/*
70 	 * System is now in active mode. Reenable interrupts which were
71 	 * disabled when OS started idling code.
72 	 */
73 	irq_unlock(0);
74 }
75