1 /*
2 * Copyright (c) 2023 Google LLC
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <clock_control/clock_stm32_ll_common.h>
8 #include <soc.h>
9
10 #include <stm32f4xx_ll_bus.h>
11 #include <stm32f4xx_ll_cortex.h>
12 #include <stm32f4xx_ll_pwr.h>
13 #include <stm32f4xx.h>
14
15 #include <zephyr/drivers/clock_control/stm32_clock_control.h>
16 #include <zephyr/drivers/counter.h>
17 #include <zephyr/drivers/interrupt_controller/gic.h>
18 #include <zephyr/kernel.h>
19 #include <zephyr/logging/log.h>
20 #include <zephyr/pm/pm.h>
21 #include <zephyr/init.h>
22
23 LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL);
24
25 BUILD_ASSERT(DT_SAME_NODE(DT_CHOSEN(zephyr_cortex_m_idle_timer), DT_NODELABEL(rtc)),
26 "STM32Fx series needs RTC as an additional IDLE timer for power management");
27
pm_state_set(enum pm_state state,uint8_t substate_id)28 void pm_state_set(enum pm_state state, uint8_t substate_id)
29 {
30 ARG_UNUSED(substate_id);
31
32 switch (state) {
33 case PM_STATE_SUSPEND_TO_IDLE:
34 LL_LPM_DisableEventOnPend();
35 LL_PWR_ClearFlag_WU();
36 /* According to datasheet (DS11139 Rev 8,Table 38.), wakeup with regulator in
37 * low-power mode takes typically 8us, max 13us more time than with the main
38 * regulator. We are using RTC as a wakeup source, which has a tick 62,5us.
39 * It means we have to add significant margin to the exit-latency anyway,
40 * so it is worth always using the low-power regulator.
41 */
42 LL_PWR_SetPowerMode(LL_PWR_MODE_STOP_LPREGU);
43 LL_LPM_EnableDeepSleep();
44
45 k_cpu_idle();
46
47 break;
48 default:
49 LOG_DBG("Unsupported power state %u", state);
50 break;
51 }
52 }
53
pm_state_exit_post_ops(enum pm_state state,uint8_t substate_id)54 void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id)
55 {
56 ARG_UNUSED(substate_id);
57
58 switch (state) {
59 case PM_STATE_SUSPEND_TO_IDLE:
60 LL_LPM_DisableSleepOnExit();
61 LL_LPM_EnableSleep();
62
63 /* Restore the clock setup. */
64 stm32_clock_control_init(NULL);
65 break;
66 default:
67 LOG_DBG("Unsupported power substate-id %u", state);
68 break;
69 }
70
71 /*
72 * System is now in active mode. Reenable interrupts which were
73 * disabled when OS started idling code.
74 */
75 irq_unlock(0);
76 }
77
stm32_power_init(void)78 void stm32_power_init(void)
79 {
80 /* Enable Power clock. It should by done by default, but make sure to
81 * enable it for all STM32F4x chips.
82 */
83 LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_PWR);
84 }
85