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