Skip to main content

esp_hal/rtc_cntl/sleep/
esp32h2.rs

1use core::ops::Not;
2
3use crate::{
4    peripherals::{LP_AON, PMU},
5    private::DropGuard,
6    rtc_cntl::{
7        Rtc,
8        rtc::{HpSysCntlReg, HpSysPower, LpSysPower},
9        sleep::{SleepKind, pmu_common::SleepTimeConfig},
10    },
11    soc::{
12        clocks::{self, ClockTree, CpuClkConfig, HpRootClkConfig, LpSlowClkConfig},
13        xtal32k,
14    },
15};
16
17/// Configuration for controlling the behavior during sleep modes.
18#[derive(Clone, Copy)]
19// Note: from all the fields defined in ESP-IDF's `pmu_sleep_analog_config_t`
20// the only one documented in Hardware Technical Reference Manual is `hp_sys.analog.xpd`
21// (corresponds to `PMU_HP_ACTIVE_HP_REGULATOR_XPD` in the Manual). Therefore only this
22// field is stored as bool without any nested structures.
23pub struct AnalogSleepConfig {
24    /// High-power system configuration.
25    pub regulator_xpd: bool,
26}
27
28impl AnalogSleepConfig {
29    fn defaults_deep_sleep() -> Self {
30        Self {
31            // PMU_SLEEP_ANALOG_DSLP_CONFIG_DEFAULT
32            regulator_xpd: false,
33        }
34    }
35
36    fn defaults_light_sleep() -> Self {
37        Self {
38            // PMU_SLEEP_ANALOG_LSLP_CONFIG_DEFAULT
39            regulator_xpd: true,
40        }
41    }
42
43    fn apply(&self) {
44        // based on pmu_sleep_analog_init, with undocumented registers omitted
45        PMU::regs().hp_sleep_hp_regulator0().modify(|_, w| {
46            w.hp_sleep_hp_regulator_xpd() // pmu_ll_hp_set_regulator_xpd
47                .bit(self.regulator_xpd)
48        });
49    }
50}
51
52/// Configuration for controlling the behavior of digital peripherals during
53/// sleep modes.
54#[derive(Clone, Copy)]
55// pmu_sleep_digital_config_t
56pub struct DigitalSleepConfig {
57    /// High-power system control register configuration.
58    pub syscntl: HpSysCntlReg,
59    /// ICG function control flags.
60    pub icg_func: u32,
61    /// Indicates whether deep sleep mode is requested.
62    pub deep_sleep: bool,
63}
64
65impl DigitalSleepConfig {
66    fn defaults_light_sleep(pd_flags: PowerDownFlags) -> Self {
67        Self {
68            // PMU_SLEEP_DIGITAL_LSLP_CONFIG_DEFAULT
69            syscntl: {
70                let mut cfg = HpSysCntlReg::default();
71
72                cfg.set_dig_pad_slp_sel(pd_flags.pd_top().not());
73
74                cfg
75            },
76            icg_func: 0xffff_ffff, // TODO: ESP-IDF determines this using get_sleep_clock_icg_flags
77            deep_sleep: false,
78        }
79    }
80
81    fn defaults_deep_sleep() -> Self {
82        Self {
83            // PMU_SLEEP_DIGITAL_DSLP_CONFIG_DEFAULT
84            syscntl: HpSysCntlReg::default(),
85            icg_func: 0,
86            deep_sleep: true,
87        }
88    }
89
90    fn apply(&self) {
91        // pmu_sleep_digital_init
92        PMU::regs().hp_sleep_sysclk().modify(|_, w| {
93            w.hp_sleep_icg_sys_clock_en().bit(self.icg_func != 0) // pmu_ll_hp_set_icg_sysclk_enable
94        });
95        PMU::regs().hp_sleep_icg_hp_func().modify(|_, w| unsafe {
96            w.hp_sleep_dig_icg_func_en().bits(self.icg_func) // pmu_ll_hp_set_icg_func
97        });
98        if !self.deep_sleep {
99            PMU::regs().hp_sleep_hp_sys_cntl().modify(|_, w| {
100                w.hp_sleep_dig_pad_slp_sel()
101                    .bit(self.syscntl.dig_pad_slp_sel()) // pmu_ll_hp_set_dig_pad_slp_sel
102            });
103        }
104    }
105}
106
107/// Configuration for controlling the power settings of high-power and low-power
108/// systems during sleep modes.
109#[derive(Clone, Copy)]
110// pmu_sleep_power_config_t
111pub struct PowerSleepConfig {
112    /// Power configuration for the high-power system during sleep.
113    pub hp_sys: HpSysPower,
114    /// Power configuration for the low-power system when it is active.
115    pub lp_sys_active: LpSysPower,
116    /// Power configuration for the low-power system when it is in sleep mode.
117    pub lp_sys_sleep: LpSysPower,
118}
119
120impl PowerSleepConfig {
121    fn defaults(pd_flags: PowerDownFlags) -> Self {
122        let mut this = Self {
123            hp_sys: HpSysPower::default(),
124            lp_sys_active: LpSysPower::default(),
125            lp_sys_sleep: LpSysPower::default(),
126        };
127        this.apply_flags(pd_flags);
128        this
129    }
130
131    fn apply_flags(&mut self, pd_flags: PowerDownFlags) {
132        // PMU_SLEEP_POWER_CONFIG_DEFAULT
133        self.hp_sys
134            .dig_power
135            .set_vdd_spi_pd_en(pd_flags.pd_vddsdio());
136        self.hp_sys.dig_power.set_modem_pd_en(pd_flags.pd_modem());
137        self.hp_sys.dig_power.set_cpu_pd_en(pd_flags.pd_cpu());
138        self.hp_sys.dig_power.set_top_pd_en(pd_flags.pd_top());
139
140        self.hp_sys.clk.set_xpd_bbpll(false);
141
142        self.hp_sys.xtal.set_xpd_xtal(pd_flags.pd_xtal().not());
143
144        self.lp_sys_active
145            .clk_power
146            .set_xpd_xtal32k(xtal32k::use_xtal32k());
147        self.lp_sys_active.clk_power.set_xpd_fosc(true);
148
149        self.lp_sys_sleep.dig_power.set_mem_dslp(true);
150        self.lp_sys_sleep.dig_power.set_vddbat_mode(0);
151        self.lp_sys_sleep.dig_power.set_bod_source_sel(true);
152
153        self.lp_sys_sleep
154            .clk_power
155            .set_xpd_xtal32k(pd_flags.pd_xtal32k().not());
156        self.lp_sys_sleep
157            .clk_power
158            .set_xpd_fosc(pd_flags.pd_rc_fast().not());
159
160        self.lp_sys_sleep
161            .xtal
162            .set_xpd_xtal(pd_flags.pd_xtal().not());
163    }
164
165    fn apply(&self) {
166        // pmu_sleep_power_init
167        // HP SLEEP (hp_sleep_*)
168        PMU::regs()
169            .hp_sleep_dig_power()
170            .modify(|_, w| unsafe { w.bits(self.hp_sys.dig_power.0) });
171        PMU::regs()
172            .hp_sleep_hp_ck_power()
173            .modify(|_, w| unsafe { w.bits(self.hp_sys.clk.0) });
174        PMU::regs()
175            .hp_sleep_xtal()
176            .modify(|_, w| w.hp_sleep_xpd_xtal().bit(self.hp_sys.xtal.xpd_xtal()));
177
178        // LP ACTIVE (hp_sleep_lp_*)
179        PMU::regs()
180            .hp_sleep_lp_dig_power()
181            .modify(|_, w| unsafe { w.bits(self.lp_sys_active.dig_power.0) });
182        PMU::regs()
183            .hp_sleep_lp_ck_power()
184            .modify(|_, w| unsafe { w.bits(self.lp_sys_active.clk_power.0) });
185
186        // LP SLEEP (lp_sleep_*)
187        PMU::regs()
188            .lp_sleep_lp_dig_power()
189            .modify(|_, w| unsafe { w.bits(self.lp_sys_sleep.dig_power.0) });
190        PMU::regs()
191            .lp_sleep_lp_ck_power()
192            .modify(|_, w| unsafe { w.bits(self.lp_sys_sleep.clk_power.0) });
193        PMU::regs()
194            .lp_sleep_xtal()
195            .modify(|_, w| w.lp_sleep_xpd_xtal().bit(self.lp_sys_sleep.xtal.xpd_xtal()));
196    }
197}
198
199/// Parameters for high-power system configurations during sleep modes.
200#[derive(Clone, Copy)]
201// pmu_hp_param_t
202pub struct HpParam {
203    /// Number of cycles to wait for the modem to wake up.
204    pub modem_wakeup_wait_cycle: u32,
205    /// Number of cycles to wait for the analog component stabilization.
206    pub analog_wait_target_cycle: u16,
207    /// Number of cycles to wait for the digital power-down sequence.
208    pub digital_power_down_wait_cycle: u16,
209    /// Number of cycles to wait for the digital power supply to stabilize.
210    pub digital_power_supply_wait_cycle: u16,
211    /// Number of cycles to wait for the digital power-up sequence.
212    pub digital_power_up_wait_cycle: u16,
213    /// Number of cycles to wait for the PLL to stabilize.
214    pub pll_stable_wait_cycle: u16,
215    /// Number of cycles to wait for modifying the ICG control.
216    pub modify_icg_cntl_wait_cycle: u8,
217    /// Number of cycles to wait for switching the ICG control.
218    pub switch_icg_cntl_wait_cycle: u8,
219    /// Minimum sleep time measured in slow clock cycles.
220    pub min_slp_slow_clk_cycle: u8,
221}
222
223/// Parameters for low-power system configurations during sleep modes.
224#[derive(Clone, Copy)]
225// pmu_lp_param_t
226pub struct LpParam {
227    /// Number of cycles to wait for the digital power supply to stabilize.
228    pub digital_power_supply_wait_cycle: u16,
229    /// Minimum sleep time measured in slow clock cycles.
230    pub min_slp_slow_clk_cycle: u8,
231    /// Number of cycles to wait for the analog component stabilization.
232    pub analog_wait_target_cycle: u8,
233    /// Number of cycles to wait for the digital power-down sequence.
234    pub digital_power_down_wait_cycle: u8,
235    /// Number of cycles to wait for the digital power-up sequence.
236    pub digital_power_up_wait_cycle: u8,
237}
238
239/// Parameters for high-power and low-power system configurations during sleep
240/// modes.
241#[derive(Clone, Copy)]
242// pmu_hp_lp_param_t
243pub struct HpLpParam {
244    /// Union of two u16 variants
245    pub xtal_stable_wait_cycle: u16,
246}
247
248/// Configuration of parameters for sleep modes
249#[derive(Clone, Copy)]
250// pmu_sleep_param_config_t
251pub struct ParamSleepConfig {
252    /// Configuration of high-power system parameters.
253    pub hp_sys: HpParam,
254    /// Configuration of low-power system parameters.
255    pub lp_sys: LpParam,
256    /// Shared configuration parameters for high-power and low-power systems.
257    pub hp_lp: HpLpParam,
258}
259impl ParamSleepConfig {
260    const PMU_SLEEP_PARAM_CONFIG_DEFAULT: Self = Self {
261        hp_sys: HpParam {
262            min_slp_slow_clk_cycle: 10,
263            analog_wait_target_cycle: 1700,
264            digital_power_supply_wait_cycle: 32,
265            digital_power_up_wait_cycle: 32,
266            modem_wakeup_wait_cycle: 0,
267            pll_stable_wait_cycle: 2,
268
269            digital_power_down_wait_cycle: 0,
270            modify_icg_cntl_wait_cycle: 0,
271            switch_icg_cntl_wait_cycle: 0,
272        },
273        lp_sys: LpParam {
274            min_slp_slow_clk_cycle: 10,
275            analog_wait_target_cycle: 15,
276            digital_power_supply_wait_cycle: 32,
277            digital_power_up_wait_cycle: 32,
278
279            digital_power_down_wait_cycle: 0,
280        },
281        hp_lp: HpLpParam {
282            xtal_stable_wait_cycle: 30,
283        },
284    };
285
286    fn apply(&self) {
287        // pmu_sleep_param_init
288        unsafe {
289            PMU::regs().slp_wakeup_cntl3().modify(|_, w| {
290                // pmu_ll_hp_set_min_sleep_cycle
291                w.hp_min_slp_val().bits(self.hp_sys.min_slp_slow_clk_cycle);
292                // pmu_ll_lp_set_min_sleep_cycle
293                w.lp_min_slp_val().bits(self.lp_sys.min_slp_slow_clk_cycle)
294            });
295
296            PMU::regs().slp_wakeup_cntl7().modify(|_, w| {
297                w.ana_wait_target() // pmu_ll_hp_set_analog_wait_target_cycle
298                    .bits(self.hp_sys.analog_wait_target_cycle)
299            });
300
301            PMU::regs().slp_wakeup_cntl5().modify(|_, w| {
302                w.lp_ana_wait_target() // pmu_ll_lp_set_analog_wait_target_cycle
303                    .bits(self.lp_sys.analog_wait_target_cycle)
304            });
305
306            PMU::regs().power_wait_timer0().modify(|_, w| {
307                // pmu_ll_hp_set_digital_power_supply_wait_cycle
308                w.dg_hp_wait_timer()
309                    .bits(self.hp_sys.digital_power_supply_wait_cycle);
310                // pmu_ll_hp_set_digital_power_up_wait_cycle
311                w.dg_hp_powerup_timer()
312                    .bits(self.hp_sys.digital_power_up_wait_cycle)
313            });
314
315            PMU::regs().power_wait_timer1().modify(|_, w| {
316                // pmu_ll_lp_set_digital_power_supply_wait_cycle
317                w.dg_lp_wait_timer()
318                    .bits(self.lp_sys.digital_power_supply_wait_cycle);
319                // pmu_ll_lp_set_digital_power_up_wait_cycle
320                w.dg_lp_powerup_timer()
321                    .bits(self.lp_sys.digital_power_up_wait_cycle)
322            });
323
324            PMU::regs().power_ck_wait_cntl().modify(|_, w| {
325                // pmu_ll_set_xtal_stable_wait_cycle
326                w.wait_xtl_stable().bits(self.hp_lp.xtal_stable_wait_cycle);
327                // pmu_ll_set_pll_stable_wait_cycle
328                w.wait_pll_stable().bits(self.hp_sys.pll_stable_wait_cycle)
329            });
330        }
331    }
332
333    fn defaults(config: SleepTimeConfig, pd_xtal: bool) -> Self {
334        let mut param = Self::PMU_SLEEP_PARAM_CONFIG_DEFAULT;
335
336        // pmu_sleep_param_config_default
337        param.hp_sys.min_slp_slow_clk_cycle =
338            config.us_to_slowclk(machine_constants::HP_MIN_SLP_TIME_US) as u8;
339        param.hp_sys.analog_wait_target_cycle =
340            config.us_to_fastclk(machine_constants::HP_ANALOG_WAIT_TIME_US) as u16;
341        param.hp_sys.digital_power_supply_wait_cycle =
342            config.us_to_fastclk(machine_constants::HP_POWER_SUPPLY_WAIT_TIME_US) as u16;
343        param.hp_sys.digital_power_up_wait_cycle =
344            config.us_to_fastclk(machine_constants::HP_POWER_UP_WAIT_TIME_US) as u16;
345        param.hp_sys.pll_stable_wait_cycle =
346            config.us_to_fastclk(machine_constants::HP_PLL_WAIT_STABLE_TIME_US) as u16;
347
348        param.lp_sys.min_slp_slow_clk_cycle =
349            config.us_to_slowclk(machine_constants::LP_MIN_SLP_TIME_US) as u8;
350        param.lp_sys.analog_wait_target_cycle =
351            config.us_to_slowclk(machine_constants::LP_ANALOG_WAIT_TIME_US) as u8;
352        param.lp_sys.digital_power_supply_wait_cycle =
353            config.us_to_fastclk(machine_constants::LP_POWER_SUPPLY_WAIT_TIME_US) as u16;
354        param.lp_sys.digital_power_up_wait_cycle =
355            config.us_to_fastclk(machine_constants::LP_POWER_UP_WAIT_TIME_US) as u8;
356
357        // This looks different from esp-idf but it is the same:
358        // Both `xtal_stable_wait_cycle` and `xtal_stable_wait_slow_clk_cycle` are
359        // u16 variants of the same union
360        param.hp_lp.xtal_stable_wait_cycle = if pd_xtal {
361            config.us_to_slowclk(machine_constants::LP_XTAL_WAIT_STABLE_TIME_US) as u16
362        } else {
363            config.us_to_fastclk(machine_constants::HP_XTAL_WAIT_STABLE_TIME_US) as u16
364        };
365
366        param
367    }
368}
369
370impl SleepTimeConfig {
371    pub(crate) const CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ: u32 = 96;
372    pub(crate) const LIGHT_SLEEP_TIME_OVERHEAD_US: u32 = 9;
373
374    pub(crate) fn pmu_sleep_calculate_hw_wait_time(&self, pd_flags: PowerDownFlags) -> u32 {
375        let lp_clk_switch_time_us = self.slowclk_to_us(machine_constants::LP_CLK_SWITCH_CYCLE);
376        let lp_clk_power_on_wait_time_us = if pd_flags.pd_xtal() {
377            machine_constants::LP_XTAL_WAIT_STABLE_TIME_US
378        } else {
379            self.slowclk_to_us(machine_constants::LP_CLK_POWER_ON_WAIT_CYCLE)
380        };
381
382        let lp_hw_wait_time_us = machine_constants::LP_MIN_SLP_TIME_US
383            + machine_constants::LP_ANALOG_WAIT_TIME_US
384            + lp_clk_power_on_wait_time_us
385            + lp_clk_switch_time_us
386            + machine_constants::LP_POWER_SUPPLY_WAIT_TIME_US
387            + machine_constants::LP_POWER_UP_WAIT_TIME_US;
388
389        let hp_digital_power_up_wait_time_us = machine_constants::HP_POWER_SUPPLY_WAIT_TIME_US
390            + machine_constants::HP_POWER_UP_WAIT_TIME_US;
391        let hp_regdma_wait_time_us = if pd_flags.pd_top() {
392            machine_constants::HP_REGDMA_S2A_WORK_TIME_PD_TOP_US
393        } else {
394            machine_constants::HP_REGDMA_S2A_WORK_TIME_PU_TOP_US
395        };
396        let hp_clock_wait_time_us = machine_constants::HP_XTAL_WAIT_STABLE_TIME_US
397            + machine_constants::HP_PLL_WAIT_STABLE_TIME_US;
398
399        let hp_hw_wait_time_us = machine_constants::HP_ANALOG_WAIT_TIME_US
400            + hp_digital_power_up_wait_time_us
401            + hp_regdma_wait_time_us
402            + hp_clock_wait_time_us;
403
404        lp_hw_wait_time_us + hp_hw_wait_time_us
405    }
406}
407
408/// Configuration for the RTC sleep behavior.
409#[derive(Clone, Copy)]
410pub struct RtcSleepConfig {
411    /// Deep Sleep flag
412    pub deep: bool,
413    /// Power Down flags
414    pub pd_flags: PowerDownFlags,
415    /// Indicates whether the top power domain should remain enabled during sleep.
416    need_pd_top: bool,
417}
418
419impl Default for RtcSleepConfig {
420    fn default() -> Self {
421        // from pmu_sleep_param_config_default
422        // sleep flags will be applied by wakeup methods and apply
423
424        Self {
425            deep: false,
426            pd_flags: PowerDownFlags(0),
427            need_pd_top: false,
428        }
429    }
430}
431
432bitfield::bitfield! {
433    #[derive(Clone, Copy)]
434    /// Power domains to be powered down during sleep
435    pub struct PowerDownFlags(u32);
436
437    /// Controls the power-down status of the top power domain.
438    pub u32, pd_top      , set_pd_top      : 0;
439    /// Controls the power-down status of the VDD_SDIO power domain.
440    pub u32, pd_vddsdio  , set_pd_vddsdio  : 1;
441    /// Controls the power-down status of the modem power domain.
442    pub u32, pd_modem    , set_pd_modem    : 2;
443    /// Controls the power-down status of the CPU power domain.
444    pub u32, pd_cpu      , set_pd_cpu      : 3;
445    /// Controls the power-down status of the crystal oscillator.
446    pub u32, pd_xtal     , set_pd_xtal     : 4;
447    /// Controls the power-down status of the fast RC oscillator.
448    pub u32, pd_rc_fast  , set_pd_rc_fast  : 5;
449    /// Controls the power-down status of the 32kHz crystal oscillator.
450    pub u32, pd_xtal32k  , set_pd_xtal32k  : 6;
451}
452
453/// Constants defined in `PMU_SLEEP_MC_DEFAULT()`
454mod machine_constants {
455    pub const LP_MIN_SLP_TIME_US: u32 = 450;
456    pub const LP_ANALOG_WAIT_TIME_US: u32 = 154;
457    pub const LP_XTAL_WAIT_STABLE_TIME_US: u32 = 250;
458    pub const LP_CLK_SWITCH_CYCLE: u32 = 1;
459    pub const LP_CLK_POWER_ON_WAIT_CYCLE: u32 = 1;
460    pub const LP_POWER_SUPPLY_WAIT_TIME_US: u32 = 2;
461    pub const LP_POWER_UP_WAIT_TIME_US: u32 = 2;
462
463    pub const HP_MIN_SLP_TIME_US: u32 = 450;
464    pub const HP_ANALOG_WAIT_TIME_US: u32 = 154;
465    pub const HP_POWER_SUPPLY_WAIT_TIME_US: u32 = 2;
466    pub const HP_POWER_UP_WAIT_TIME_US: u32 = 2;
467    pub const HP_REGDMA_S2A_WORK_TIME_PD_TOP_US: u32 = 480;
468    pub const HP_REGDMA_S2A_WORK_TIME_PU_TOP_US: u32 = 390;
469    pub const HP_XTAL_WAIT_STABLE_TIME_US: u32 = 250;
470    pub const HP_PLL_WAIT_STABLE_TIME_US: u32 = 50;
471}
472
473impl RtcSleepConfig {
474    /// Returns whether the device is in deep sleep mode.
475    pub fn deep_slp(&self) -> bool {
476        self.deep
477    }
478
479    /// Configures the device for deep sleep mode with ultra-low power settings.
480    pub fn deep() -> Self {
481        // Set up for ultra-low power sleep. Wakeup sources may modify these settings.
482        Self {
483            deep: true,
484            ..Self::default()
485        }
486    }
487
488    pub(crate) fn is_deep_sleep(&self) -> bool {
489        self.deep
490    }
491
492    pub(crate) fn set_sleep_kind(&mut self, kind: SleepKind) {
493        self.deep = kind == SleepKind::Deep;
494    }
495
496    pub(crate) fn base_settings(_rtc: &Rtc<'_>) {}
497
498    /// Finalize power-down flags, apply configuration based on the flags.
499    pub(crate) fn apply(&mut self) {
500        let lp_slow_uses_xtal32k = ClockTree::with(|clocks| {
501            matches!(
502                clocks::lp_slow_clk_config(clocks),
503                Some(LpSlowClkConfig::Xtal32k)
504            )
505        });
506
507        if self.deep {
508            // force-disable certain power domains
509            self.pd_flags.set_pd_top(self.need_pd_top.not());
510            self.pd_flags.set_pd_vddsdio(true);
511            self.pd_flags.set_pd_modem(true);
512            self.pd_flags.set_pd_cpu(true);
513            self.pd_flags.set_pd_xtal(true);
514            self.pd_flags.set_pd_rc_fast(true);
515            self.pd_flags.set_pd_xtal32k(!lp_slow_uses_xtal32k);
516        } else {
517            // Light sleep: the digital and top domains stay powered (so execution
518            // resumes in place; the top domain must also stay on for any EXT1/GPIO
519            // wakeup). Power down the analog clock sources nothing needs while the
520            // core is clock-gated to cut power. Unlike the C5/C6 family, H2's
521            // light-sleep analog config does not lower the HP voltage, so this saves
522            // the oscillator current but not regulator power.
523            self.pd_flags.set_pd_xtal(true);
524            self.pd_flags.set_pd_rc_fast(true);
525            self.pd_flags.set_pd_xtal32k(!lp_slow_uses_xtal32k);
526        }
527    }
528
529    /// Configures the wakeup options and requests the sleep.
530    ///
531    /// The caller waits for the result of the request. The return value is a guard that restores
532    /// what sleep entry changed for the sleep only, so the caller keeps it until the sleep ends.
533    pub(crate) fn start_sleep(&self, wakeup_mask: u32, reject_mask: u32) -> impl Sized {
534        let restore_clock_config = ClockTree::with(|clocks| {
535            let old_hp_root_clk = clocks.hp_root_clk();
536            let old_cpu_divider = clocks.cpu_clk();
537
538            clocks::configure_hp_root_clk(clocks, HpRootClkConfig::Xtal);
539            clocks::configure_cpu_clk(clocks, CpuClkConfig::new(0));
540
541            // Restore the old clock settings when we return
542            DropGuard::new((), move |_| {
543                ClockTree::with(|clocks| {
544                    if let Some(old_hp_root_clk) = old_hp_root_clk {
545                        clocks::configure_hp_root_clk(clocks, old_hp_root_clk);
546                    }
547                    if let Some(old_cpu_divider) = old_cpu_divider {
548                        clocks::configure_cpu_clk(clocks, old_cpu_divider);
549                    }
550                });
551            })
552        });
553
554        // misc_modules_sleep_prepare
555
556        // pmu_sleep_config_default + pmu_sleep_init
557
558        let power = PowerSleepConfig::defaults(self.pd_flags);
559        power.apply();
560
561        // Needs to happen after rtc_clk_cpu_freq_set_xtal
562        let config = if self.deep {
563            SleepTimeConfig::deep_sleep()
564        } else {
565            SleepTimeConfig::light_sleep(self.pd_flags)
566        };
567
568        let param = ParamSleepConfig::defaults(config, power.hp_sys.xtal.xpd_xtal());
569
570        if self.deep {
571            DigitalSleepConfig::defaults_deep_sleep().apply();
572            AnalogSleepConfig::defaults_deep_sleep().apply();
573        } else {
574            DigitalSleepConfig::defaults_light_sleep(self.pd_flags).apply();
575            AnalogSleepConfig::defaults_light_sleep().apply();
576        }
577
578        param.apply();
579
580        // pmu_sleep_start
581
582        // lp_aon_hal_inform_wakeup_type - tells ROM which wakeup stub to run
583        LP_AON::regs()
584            .store9()
585            .modify(|r, w| unsafe { w.bits(r.bits() & !0x01 | self.deep as u32) });
586
587        // pmu_ll_hp_set_wakeup_enable
588        PMU::regs()
589            .slp_wakeup_cntl2()
590            .write(|w| unsafe { w.bits(wakeup_mask) });
591
592        // pmu_ll_hp_set_reject_enable
593        PMU::regs().slp_wakeup_cntl1().modify(|_, w| unsafe {
594            w.slp_reject_en().bit(reject_mask != 0);
595            w.sleep_reject_ena().bits(reject_mask)
596        });
597
598        PMU::regs().int_clr().write(|w| {
599            // pmu_ll_hp_clear_wakeup_intr_status
600            w.soc_wakeup().clear_bit_by_one();
601            // pmu_ll_hp_clear_reject_intr_status
602            w.soc_sleep_reject().clear_bit_by_one()
603        });
604
605        // pmu_ll_hp_clear_reject_cause
606        PMU::regs()
607            .slp_wakeup_cntl4()
608            .write(|w| w.slp_reject_cause_clr().bit(true));
609
610        // Start entry into sleep mode
611
612        // pmu_ll_hp_set_sleep_enable
613        PMU::regs()
614            .slp_wakeup_cntl0()
615            .write(|w| w.sleep_req().bit(true));
616
617        restore_clock_config
618    }
619
620    /// Cleans up after sleep
621    pub(crate) fn finish_sleep(&self) {
622        // The post-wake hook of the GPIO driver releases the pads that the sleep armed. Only that
623        // driver knows which pads it prepared.
624    }
625}