Skip to main content

esp_hal/rtc_cntl/sleep/
esp32s2.rs

1use super::{
2    Ext0WakeupSource,
3    Ext1WakeupSource,
4    TimerWakeupSource,
5    UlpWakeupSource,
6    WakeSource,
7    WakeTriggers,
8    WakeupLevel,
9};
10use crate::{
11    gpio::{RtcFunction, RtcPin},
12    peripherals::{EXTMEM, LPWR, RTC_IO, SENS, SPI0, SPI1, SYSTEM},
13    rtc_cntl::{Rtc, sleep::RtcioWakeupSource},
14    soc::regi2c,
15};
16
17// Approximate mapping of voltages to RTC_CNTL_DBIAS_WAK, RTC_CNTL_DBIAS_SLP,
18// RTC_CNTL_DIG_DBIAS_WAK, RTC_CNTL_DIG_DBIAS_SLP values.
19// Valid if RTC_CNTL_DBG_ATTEN is 0.
20/// Digital bias setting for 0.90V.
21pub const RTC_CNTL_DBIAS_0V90: u8 = 0;
22/// Digital bias setting for 0.95V.
23pub const RTC_CNTL_DBIAS_0V95: u8 = 1;
24/// Digital bias setting for 1.00V.
25pub const RTC_CNTL_DBIAS_1V00: u8 = 2;
26/// Digital bias setting for 1.05V.
27pub const RTC_CNTL_DBIAS_1V05: u8 = 3;
28/// Digital bias setting for 1.10V.
29pub const RTC_CNTL_DBIAS_1V10: u8 = 4;
30/// Digital bias setting for 1.15V.
31pub const RTC_CNTL_DBIAS_1V15: u8 = 5;
32/// Digital bias setting for 1.20V.
33pub const RTC_CNTL_DBIAS_1V20: u8 = 6;
34/// Digital bias setting for 1.25V.
35pub const RTC_CNTL_DBIAS_1V25: u8 = 7;
36/// Default monitor debug attenuation value.
37pub const RTC_CNTL_DBG_ATTEN_MONITOR_DEFAULT: u8 = 0;
38/// ULP co-processor touch start wait time during sleep, set to maximum.
39pub const RTC_CNTL_ULPCP_TOUCH_START_WAIT_IN_SLEEP: u16 = 0xFF;
40/// ULP co-processor touch start wait time default value.
41pub const RTC_CNTL_ULPCP_TOUCH_START_WAIT_DEFAULT: u16 = 0x10;
42/// Default wait time for PLL buffer during startup.
43pub const RTC_CNTL_PLL_BUF_WAIT_DEFAULT: u8 = 20;
44/// Default wait time for CK8M during startup.
45pub const RTC_CNTL_CK8M_WAIT_DEFAULT: u8 = 20;
46/// Default wait time for XTL buffer during startup.
47pub const RTC_CNTL_XTL_BUF_WAIT_DEFAULT: u8 = 100;
48/// Minimum sleep value.
49pub const RTC_CNTL_MIN_SLP_VAL_MIN: u8 = 2;
50/// Deep sleep debug attenuation setting for ultra-low power mode.
51pub const RTC_CNTL_DBG_ATTEN_DEEPSLEEP_DEFAULT: u8 = 15;
52/// Power-up setting for other blocks.
53pub const OTHER_BLOCKS_POWERUP: u8 = 1;
54/// Wait cycles for other blocks.
55pub const OTHER_BLOCKS_WAIT: u16 = 1;
56/// WiFi power-up cycles.
57pub const WIFI_POWERUP_CYCLES: u8 = OTHER_BLOCKS_POWERUP;
58/// WiFi wait cycles.
59pub const WIFI_WAIT_CYCLES: u16 = OTHER_BLOCKS_WAIT;
60/// RTC power-up cycles.
61pub const RTC_POWERUP_CYCLES: u8 = OTHER_BLOCKS_POWERUP;
62/// RTC wait cycles.
63pub const RTC_WAIT_CYCLES: u16 = OTHER_BLOCKS_WAIT;
64/// DG wrap power-up cycles.
65pub const DG_WRAP_POWERUP_CYCLES: u8 = OTHER_BLOCKS_POWERUP;
66/// DG wrap wait cycles.
67pub const DG_WRAP_WAIT_CYCLES: u16 = OTHER_BLOCKS_WAIT;
68/// DG peripheral power-up cycles.
69pub const DG_PERI_POWERUP_CYCLES: u8 = OTHER_BLOCKS_POWERUP;
70/// DG peripheral wait cycles.
71pub const DG_PERI_WAIT_CYCLES: u16 = OTHER_BLOCKS_WAIT;
72/// RTC memory power-up cycles.
73pub const RTC_MEM_POWERUP_CYCLES: u8 = OTHER_BLOCKS_POWERUP;
74/// RTC memory wait cycles.
75pub const RTC_MEM_WAIT_CYCLES: u16 = OTHER_BLOCKS_WAIT;
76
77impl WakeSource for UlpWakeupSource {
78    fn apply(
79        &self,
80        _rtc: &Rtc<'_>,
81        triggers: &mut WakeTriggers,
82        sleep_config: &mut RtcSleepConfig,
83    ) {
84        triggers.set_ulp(self.wake_on_interrupt);
85        triggers.set_ulp_riscv_trap(self.wake_on_trap);
86
87        if self.clear_interrupts_on_sleep {
88            self.clear_interrupts();
89        }
90
91        // This one needs to be false to keep the ULP timer and ULP GPIO happy!
92        // Possibly relevant issue: https://github.com/espressif/esp-idf/issues/10595
93        sleep_config.set_rtc_peri_pd_en(false);
94    }
95}
96
97impl WakeSource for TimerWakeupSource {
98    fn apply(
99        &self,
100        rtc: &Rtc<'_>,
101        triggers: &mut WakeTriggers,
102        _sleep_config: &mut RtcSleepConfig,
103    ) {
104        triggers.set_timer(true);
105        let rtc_cntl = LPWR::regs();
106        // TODO: maybe add check to prevent overflow?
107        let ticks = crate::clock::us_to_rtc_ticks(self.duration.as_micros() as u64);
108        // "alarm" time in slow rtc ticks
109        let now = rtc.time_since_boot_raw();
110        let time_in_ticks = now + ticks;
111        unsafe {
112            rtc_cntl
113                .slp_timer0()
114                .write(|w| w.slp_val_lo().bits((time_in_ticks & 0xffffffff) as u32));
115
116            rtc_cntl
117                .int_clr()
118                .write(|w| w.main_timer().clear_bit_by_one());
119
120            rtc_cntl.slp_timer1().write(|w| {
121                w.slp_val_hi().bits(((time_in_ticks >> 32) & 0xffff) as u16);
122                w.main_timer_alarm_en().set_bit()
123            });
124        }
125    }
126}
127
128impl<P: RtcPin> WakeSource for Ext0WakeupSource<P> {
129    fn apply(
130        &self,
131        _rtc: &Rtc<'_>,
132        triggers: &mut WakeTriggers,
133        sleep_config: &mut RtcSleepConfig,
134    ) {
135        sleep_config.set_rtc_peri_pd_en(false);
136        triggers.set_ext0(true);
137
138        // TODO: disable clock when not in use
139        SENS::regs()
140            .sar_io_mux_conf()
141            .modify(|_, w| w.iomux_clk_gate_en().set_bit());
142
143        // set pin to RTC function
144        self.pin
145            .borrow_mut()
146            .rtc_set_config(true, true, RtcFunction::Rtc);
147
148        // rtcio_hal_ext0_set_wakeup_pin
149        unsafe {
150            let rtc_io = RTC_IO::regs();
151            // set pin register field
152            rtc_io
153                .ext_wakeup0()
154                .modify(|_, w| w.sel().bits(self.pin.borrow().rtc_number()));
155            // set level register field
156            let rtc_cntl = LPWR::regs();
157            rtc_cntl
158                .ext_wakeup_conf()
159                .modify(|_r, w| w.ext_wakeup0_lv().bit(self.level == WakeupLevel::High));
160        }
161    }
162}
163
164impl<P: RtcPin> Drop for Ext0WakeupSource<P> {
165    fn drop(&mut self) {
166        // should we have saved the pin configuration first?
167        // set pin back to IO_MUX (input_enable and func have no effect when pin is sent
168        // to IO_MUX)
169        self.pin
170            .borrow_mut()
171            .rtc_set_config(true, false, RtcFunction::Rtc);
172    }
173}
174
175impl WakeSource for Ext1WakeupSource<'_, '_> {
176    fn apply(
177        &self,
178        _rtc: &Rtc<'_>,
179        triggers: &mut WakeTriggers,
180        _sleep_config: &mut RtcSleepConfig,
181    ) {
182        triggers.set_ext1(true);
183
184        // TODO: disable clock when not in use
185        SENS::regs()
186            .sar_io_mux_conf()
187            .modify(|_, w| w.iomux_clk_gate_en().set_bit());
188
189        // set pins to RTC function
190        let mut pins = self.pins.borrow_mut();
191        let mut bits = 0u32;
192        for pin in pins.iter_mut() {
193            pin.rtc_set_config(true, true, RtcFunction::Rtc);
194            pin.rtcio_pad_hold(true);
195            bits |= 1 << pin.rtc_number();
196        }
197
198        unsafe {
199            let rtc_cntl = LPWR::regs();
200            // clear previous wakeup status
201            rtc_cntl
202                .ext_wakeup1()
203                .modify(|_, w| w.status_clr().set_bit());
204            // set pin register field
205            rtc_cntl.ext_wakeup1().modify(|_, w| w.sel().bits(bits));
206            // set level register field
207            rtc_cntl
208                .ext_wakeup_conf()
209                .modify(|_r, w| w.ext_wakeup1_lv().bit(self.level == WakeupLevel::High));
210        }
211    }
212}
213
214impl Drop for Ext1WakeupSource<'_, '_> {
215    fn drop(&mut self) {
216        // should we have saved the pin configuration first?
217        // set pin back to IO_MUX (input_enable and func have no effect when pin is sent
218        // to IO_MUX)
219        let mut pins = self.pins.borrow_mut();
220        for pin in pins.iter_mut() {
221            pin.rtc_set_config(true, false, RtcFunction::Rtc);
222        }
223    }
224}
225
226impl RtcioWakeupSource<'_, '_> {
227    fn apply_pin(&self, pin: &mut dyn RtcPin, level: WakeupLevel) {
228        let rtcio = RTC_IO::regs();
229
230        pin.rtc_set_config(true, true, RtcFunction::Rtc);
231
232        rtcio.pin(pin.number() as usize).modify(|_, w| unsafe {
233            w.gpio_pin_wakeup_enable().set_bit();
234            w.gpio_pin_int_type().bits(match level {
235                WakeupLevel::Low => 4,
236                WakeupLevel::High => 5,
237            })
238        });
239    }
240}
241
242impl WakeSource for RtcioWakeupSource<'_, '_> {
243    fn apply(
244        &self,
245        _rtc: &Rtc<'_>,
246        triggers: &mut WakeTriggers,
247        sleep_config: &mut RtcSleepConfig,
248    ) {
249        let mut pins = self.pins.borrow_mut();
250
251        if pins.is_empty() {
252            return;
253        }
254
255        // don't power down RTC peripherals
256        sleep_config.set_rtc_peri_pd_en(false);
257        triggers.set_gpio(true);
258
259        // Since we only use RTCIO pins, we can keep deep sleep enabled.
260        let sens = crate::peripherals::SENS::regs();
261
262        // TODO: disable clock when not in use
263        sens.sar_io_mux_conf()
264            .modify(|_, w| w.iomux_clk_gate_en().set_bit());
265
266        for (pin, level) in pins.iter_mut() {
267            self.apply_pin(*pin, *level);
268        }
269    }
270}
271
272impl Drop for RtcioWakeupSource<'_, '_> {
273    fn drop(&mut self) {
274        // should we have saved the pin configuration first?
275        // set pin back to IO_MUX (input_enable and func have no effect when pin is sent
276        // to IO_MUX)
277        let mut pins = self.pins.borrow_mut();
278        for (pin, _level) in pins.iter_mut() {
279            pin.rtc_set_config(true, false, RtcFunction::Rtc);
280        }
281    }
282}
283
284bitfield::bitfield! {
285    /// Configuration for the RTC sleep behavior.
286    #[derive(Clone, Copy)]
287    pub struct RtcSleepConfig(u64);
288    impl Debug;
289    /// force normal voltage in sleep mode (digital domain memory)
290    pub lslp_mem_inf_fpu, set_lslp_mem_inf_fpu: 0;
291    /// keep low voltage in sleep mode (even if ULP/touch is used)
292    pub rtc_mem_inf_follow_cpu, set_rtc_mem_inf_follow_cpu: 1;
293    /// power down RTC fast memory
294    pub rtc_fastmem_pd_en, set_rtc_fastmem_pd_en: 2;
295    /// power down RTC slow memory
296    pub rtc_slowmem_pd_en, set_rtc_slowmem_pd_en: 3;
297    /// power down RTC peripherals
298    pub rtc_peri_pd_en, set_rtc_peri_pd_en: 4;
299    /// power down Wifi
300    pub wifi_pd_en, set_wifi_pd_en: 5;
301    /// Power down Internal 8M oscillator
302    pub int_8m_pd_en, set_int_8m_pd_en: 6;
303    /// power down digital domain
304    pub deep_slp, set_deep_slp: 8;
305    /// enable WDT flashboot mode
306    pub wdt_flashboot_mod_en, set_wdt_flashboot_mod_en: 9;
307    /// set bias for digital domain, in sleep mode
308    pub u8, dig_dbias_slp, set_dig_dbias_slp: 12, 10;
309    /// set bias for RTC domain, in sleep mode
310    pub u8, rtc_dbias_slp, set_rtc_dbias_slp: 16, 13;
311    /// circuit control parameter, in monitor mode
312    pub bias_sleep_monitor, set_bias_sleep_monitor: 17;
313    /// voltage parameter, in sleep mode
314    pub u8, dbg_atten_slp, set_dbg_atten_slp: 22, 18;
315    /// circuit control parameter, in sleep mode
316    pub bias_sleep_slp, set_bias_sleep_slp: 23;
317    /// circuit control parameter, in monitor mode
318    pub pd_cur_monitor, set_pd_cur_monitor: 24;
319    /// circuit control parameter, in sleep mode
320    pub pd_cur_slp, set_pd_cur_slp: 25;
321    /// power down VDDSDIO regulator
322    pub vddsdio_pd_en, set_vddsdio_pd_en: 26;
323    /// keep main XTAL powered up in sleep
324    pub xtal_fpu, set_xtal_fpu: 27;
325    /// keep rtc regulator powered up in sleep
326    pub rtc_regulator_fpu, set_rtc_regulator_fpu: 28;
327    /// enable deep sleep reject
328    pub deep_slp_reject, set_deep_slp_reject: 29;
329    /// enable light sleep reject
330    pub light_slp_reject, set_light_slp_reject: 30;
331}
332
333impl Default for RtcSleepConfig {
334    fn default() -> Self {
335        let mut cfg = Self(Default::default());
336        cfg.set_deep_slp_reject(true);
337        cfg.set_light_slp_reject(true);
338        cfg.set_rtc_dbias_slp(RTC_CNTL_DBIAS_1V10);
339        cfg.set_dig_dbias_slp(RTC_CNTL_DBIAS_1V10);
340        cfg.set_rtc_slowmem_pd_en(true);
341        cfg.set_rtc_fastmem_pd_en(true);
342        cfg
343    }
344}
345
346fn rtc_sleep_pu(val: bool) {
347    // Note: Called rtc_sleep_pd in idf, but makes more sense like this with the
348    // single boolean argument
349    let rtc_cntl = LPWR::regs();
350    let syscon = unsafe { &*esp32s2::SYSCON::ptr() };
351    let bb = unsafe { &*esp32s2::BB::ptr() };
352    let i2s = unsafe { &*esp32s2::I2S0::ptr() };
353    let nrx = unsafe { &*esp32s2::NRX::ptr() };
354    let fe = unsafe { &*esp32s2::FE::ptr() };
355    let fe2 = unsafe { &*esp32s2::FE2::ptr() };
356
357    rtc_cntl
358        .dig_pwc()
359        .modify(|_, w| w.lslp_mem_force_pu().bit(val));
360
361    rtc_cntl
362        .pwc()
363        .modify(|_, w| w.slowmem_force_lpu().bit(val).fastmem_force_lpu().bit(val));
364
365    i2s.pd_conf()
366        .write(|w| w.plc_mem_force_pu().bit(val).fifo_force_pu().bit(val));
367
368    syscon.front_end_mem_pd().modify(|_r, w| {
369        w.dc_mem_force_pu()
370            .bit(val)
371            .pbus_mem_force_pu()
372            .bit(val)
373            .agc_mem_force_pu()
374            .bit(val)
375    });
376
377    bb.bbpd_ctrl()
378        .modify(|_r, w| w.fft_force_pu().bit(val).dc_est_force_pu().bit(val));
379
380    nrx.nrxpd_ctrl().modify(|_, w| {
381        w.rx_rot_force_pu()
382            .bit(val)
383            .vit_force_pu()
384            .bit(val)
385            .demap_force_pu()
386            .bit(val)
387    });
388
389    fe.gen_ctrl().modify(|_, w| w.iq_est_force_pu().bit(val));
390
391    fe2.tx_interp_ctrl()
392        .modify(|_, w| w.tx_inf_force_pu().bit(val));
393}
394
395impl RtcSleepConfig {
396    /// Configures the RTC for deep sleep mode.
397    pub fn deep() -> Self {
398        // Set up for ultra-low power sleep. Wakeup sources may modify these settings.
399        let mut cfg = Self::default();
400
401        cfg.set_lslp_mem_inf_fpu(false);
402        cfg.set_rtc_mem_inf_follow_cpu(true); // ?
403        cfg.set_rtc_fastmem_pd_en(true);
404        cfg.set_rtc_slowmem_pd_en(true);
405        cfg.set_rtc_peri_pd_en(true);
406        cfg.set_wifi_pd_en(true);
407        cfg.set_int_8m_pd_en(true);
408
409        // Because of force_flags
410        cfg.set_vddsdio_pd_en(true);
411
412        // because of dig_peri_pd_en
413        cfg.set_dig_dbias_slp(0);
414
415        cfg.set_deep_slp(true);
416        cfg.set_wdt_flashboot_mod_en(false);
417        cfg.set_vddsdio_pd_en(true);
418        cfg.set_xtal_fpu(false);
419        cfg.set_deep_slp_reject(true);
420        cfg.set_light_slp_reject(true);
421
422        // because of RTC_SLEEP_PD_DIG
423        // NOTE: Might be the a different case for RTC_SLEEP_PD_DIG in
424        // rtc_sleep_get_default_config
425        cfg.set_rtc_regulator_fpu(false);
426        cfg.set_dbg_atten_slp(RTC_CNTL_DBG_ATTEN_DEEPSLEEP_DEFAULT);
427        cfg.set_rtc_dbias_slp(0);
428
429        // because of xtal_fpu
430        cfg.set_xtal_fpu(false);
431        cfg.set_bias_sleep_monitor(true);
432        cfg.set_pd_cur_monitor(true);
433        cfg.set_bias_sleep_slp(true);
434        cfg.set_pd_cur_slp(true);
435
436        cfg
437    }
438
439    pub(crate) fn base_settings(_rtc: &Rtc<'_>) {
440        // settings derived from esp_clk_init -> rtc_init
441        unsafe {
442            let rtc_cntl = LPWR::regs();
443            let extmem = EXTMEM::regs();
444            let system = SYSTEM::regs();
445
446            rtc_cntl
447                .dig_pwc()
448                .modify(|_, w| w.wifi_force_pd().clear_bit());
449            rtc_cntl
450                .dig_iso()
451                .modify(|_, w| w.wifi_force_iso().clear_bit());
452
453            rtc_cntl.ana_conf().modify(|_, w| w.pvtmon_pu().clear_bit());
454
455            rtc_cntl.timer1().modify(|_, w| {
456                w.pll_buf_wait().bits(RTC_CNTL_PLL_BUF_WAIT_DEFAULT);
457                w.ck8m_wait().bits(RTC_CNTL_CK8M_WAIT_DEFAULT)
458            });
459
460            // idf: "Moved from rtc sleep to rtc init to save sleep function running time
461            // set shortest possible sleep time limit"
462
463            rtc_cntl
464                .timer5()
465                .modify(|_, w| w.min_slp_val().bits(RTC_CNTL_MIN_SLP_VAL_MIN));
466
467            rtc_cntl.timer3().modify(|_, w| {
468                // set wifi timer
469                w.wifi_powerup_timer().bits(WIFI_POWERUP_CYCLES);
470                w.wifi_wait_timer().bits(WIFI_WAIT_CYCLES)
471            });
472
473            rtc_cntl.timer4().modify(|_, w| {
474                // set rtc peri timer
475                w.powerup_timer().bits(RTC_POWERUP_CYCLES);
476                w.wait_timer().bits(RTC_WAIT_CYCLES);
477                // set digital wrap timer
478                w.dg_wrap_powerup_timer().bits(DG_WRAP_POWERUP_CYCLES);
479                w.dg_wrap_wait_timer().bits(DG_WRAP_WAIT_CYCLES)
480            });
481
482            rtc_cntl.timer5().modify(|_, w| {
483                w.rtcmem_powerup_timer().bits(RTC_MEM_POWERUP_CYCLES);
484                w.rtcmem_wait_timer().bits(RTC_MEM_WAIT_CYCLES)
485            });
486
487            rtc_cntl.bias_conf().modify(|_, w| {
488                w.dec_heartbeat_width().set_bit();
489                w.inc_heartbeat_period().set_bit()
490            });
491
492            // Reset RTC bias to default value (needed if waking up from deep sleep)
493            rtc_cntl.reg().modify(|_, w| {
494                w.dbias_wak().bits(RTC_CNTL_DBIAS_1V10);
495                w.dbias_slp().bits(RTC_CNTL_DBIAS_1V10)
496            });
497
498            // Set the wait time to the default value.
499            rtc_cntl.timer2().modify(|_, w| {
500                w.ulpcp_touch_start_wait()
501                    .bits(RTC_CNTL_ULPCP_TOUCH_START_WAIT_DEFAULT)
502            });
503
504            // clkctl_init
505            {
506                // clear CMMU clock force on
507                extmem
508                    .pro_cache_mmu_power_ctrl()
509                    .modify(|_, w| w.pro_cache_mmu_mem_force_on().clear_bit());
510
511                // clear tag clock force on
512                extmem
513                    .pro_dcache_tag_power_ctrl()
514                    .modify(|_, w| w.pro_dcache_tag_mem_force_on().clear_bit());
515
516                extmem
517                    .pro_icache_tag_power_ctrl()
518                    .modify(|_, w| w.pro_icache_tag_mem_force_on().clear_bit());
519
520                system.rom_ctrl_0().modify(|_, w| w.rom_fo().bits(0));
521                system.sram_ctrl_0().modify(|_, w| w.sram_fo().bits(0));
522
523                // clear register clock force on
524                SPI0::regs()
525                    .clock_gate()
526                    .modify(|_, w| w.clk_en().clear_bit());
527                SPI1::regs()
528                    .clock_gate()
529                    .modify(|_, w| w.clk_en().clear_bit());
530            }
531
532            // pwrctl_init
533            {
534                rtc_cntl
535                    .clk_conf()
536                    .modify(|_, w| w.ck8m_force_pu().clear_bit());
537
538                rtc_cntl
539                    .options0()
540                    .modify(|_, w| w.xtl_force_pu().clear_bit());
541
542                // CLEAR APLL close
543                rtc_cntl.ana_conf().modify(|_, w| {
544                    w.plla_force_pu().clear_bit();
545                    w.plla_force_pd().set_bit()
546                });
547
548                // cancel bbpll force pu if setting no force power up
549                rtc_cntl.options0().modify(|_, w| {
550                    w.bbpll_force_pu().clear_bit();
551                    w.bbpll_i2c_force_pu().clear_bit();
552                    w.bb_i2c_force_pu().clear_bit()
553                });
554
555                // cancel RTC REG force PU
556
557                rtc_cntl.pwc().modify(|_, w| w.force_pu().clear_bit());
558                rtc_cntl.reg().modify(|_, w| {
559                    w.regulator_force_pu().clear_bit();
560                    w.dboost_force_pu().clear_bit()
561                });
562
563                rtc_cntl.pwc().modify(|_, w| {
564                    w.slowmem_force_pu().clear_bit();
565                    w.fastmem_force_pu().clear_bit();
566                    w.slowmem_force_noiso().clear_bit();
567                    w.fastmem_force_noiso().clear_bit()
568                });
569
570                rtc_cntl.reg().modify(|_, w| w.dboost_force_pd().set_bit());
571
572                // cancel sar i2c pd force
573                rtc_cntl
574                    .ana_conf()
575                    .modify(|_, w| w.sar_i2c_force_pd().clear_bit());
576                // cancel digital pu force
577                // NOTE: duplicate from idf
578                rtc_cntl.pwc().modify(|_, w| {
579                    w.slowmem_force_pu().clear_bit();
580                    w.fastmem_force_pu().clear_bit()
581                });
582
583                // If this mask is enabled, all soc memories cannot enter power down mode
584                // We should control soc memory power down mode from RTC, so we will not touch
585                // this register any more
586
587                system
588                    .mem_pd_mask()
589                    .modify(|_, w| w.lslp_mem_pd_mask().clear_bit());
590
591                // If this pd_cfg is set to 1, all memory won't enter low power mode during
592                // light sleep If this pd_cfg is set to 0, all memory will enter low
593                // power mode during light sleep
594                rtc_sleep_pu(false);
595
596                rtc_cntl.dig_pwc().modify(|_, w| {
597                    w.dg_wrap_force_pu().clear_bit();
598                    w.wifi_force_pu().clear_bit()
599                });
600
601                rtc_cntl.dig_iso().modify(|_, w| {
602                    w.dg_wrap_force_noiso().clear_bit();
603                    // NOTE: not present in idf.
604                    w.dg_wrap_force_iso().clear_bit()
605                });
606
607                rtc_cntl.dig_iso().modify(|_, w| {
608                    w.wifi_force_noiso().clear_bit();
609                    // NOTE: not present in idf.
610                    w.wifi_force_iso().clear_bit()
611                });
612
613                rtc_cntl.pwc().modify(|_, w| w.force_noiso().clear_bit());
614
615                // cancel digital PADS force no iso
616                system
617                    .cpu_per_conf()
618                    .modify(|_, w| w.cpu_wait_mode_force_on().clear_bit());
619
620                // if DPORT_CPU_WAIT_MODE_FORCE_ON == 0,
621                // the cpu clk will be closed when cpu enter WAITI mode
622                rtc_cntl.dig_iso().modify(|_, w| {
623                    w.dg_pad_force_unhold().clear_bit();
624                    w.dg_pad_force_noiso().clear_bit()
625                });
626            }
627
628            // force power down wifi and bt power domain
629            rtc_cntl
630                .dig_iso()
631                .modify(|_, w| w.wifi_force_iso().set_bit());
632
633            rtc_cntl
634                .dig_pwc()
635                .modify(|_, w| w.wifi_force_pd().set_bit());
636
637            rtc_cntl.int_ena().write(|w| w.bits(0));
638            rtc_cntl.int_clr().write(|w| w.bits(u32::MAX));
639        }
640    }
641
642    pub(crate) fn apply(&self) {
643        // like esp-idf rtc_sleep_init() and deep_sleep_start()
644        let rtc_cntl = LPWR::regs();
645
646        if self.deep_slp() {
647            // "Due to hardware limitations, on S2 the brownout detector
648            // sometimes trigger during deep sleep to circumvent
649            // this we disable the brownout detector before sleeping' - from
650            // idf's deep_sleep_start()
651            unsafe {
652                // brownout_hal_config(brownlout_hal_config_t{0})
653                rtc_cntl.brown_out().modify(|_, w| {
654                    w.int_wait().bits(2);
655                    w.close_flash_ena().clear_bit();
656                    w.pd_rf_ena().clear_bit();
657                    w.cnt_clr().set_bit()
658                });
659                rtc_cntl.brown_out().modify(|_, w| {
660                    // Set followed by clear in idf
661                    w.cnt_clr().clear_bit();
662                    w.rst_wait().bits(0x3fff);
663                    w.rst_ena().clear_bit();
664                    w.brown_out2_ena().set_bit();
665                    w.rst_sel().set_bit()
666                });
667                regi2c::I2C_BOD_REG_THRESHOLD.write_field(0);
668                rtc_cntl.brown_out().modify(|_, w| w.ena().clear_bit());
669                rtc_cntl.int_ena().modify(|_, w| w.brown_out().clear_bit());
670                // NOTE: rtc_isr_deregister?
671            }
672        }
673
674        if self.lslp_mem_inf_fpu() {
675            rtc_sleep_pu(true);
676        }
677
678        let mem_folw_cpu = self.rtc_mem_inf_follow_cpu();
679        rtc_cntl.pwc().modify(|_, w| {
680            w.slowmem_folw_cpu().bit(mem_folw_cpu);
681            w.fastmem_folw_cpu().bit(mem_folw_cpu)
682        });
683
684        let rtc_fastmem_pd_en = self.rtc_fastmem_pd_en();
685        rtc_cntl.pwc().modify(|_, w| {
686            w.fastmem_pd_en().bit(rtc_fastmem_pd_en);
687            w.fastmem_force_pu().bit(!rtc_fastmem_pd_en);
688            w.fastmem_force_noiso().bit(!rtc_fastmem_pd_en)
689        });
690
691        let rtc_slowmem_pd_en = self.rtc_slowmem_pd_en();
692        rtc_cntl.pwc().modify(|_, w| {
693            w.slowmem_pd_en().bit(rtc_slowmem_pd_en);
694            w.slowmem_force_pu().bit(!rtc_slowmem_pd_en);
695            w.slowmem_force_noiso().bit(!rtc_slowmem_pd_en)
696        });
697
698        let rtc_peri_pd_en = self.rtc_peri_pd_en();
699        rtc_cntl.pwc().modify(|_, w| w.pd_en().bit(rtc_peri_pd_en));
700
701        if self.wifi_pd_en() {
702            rtc_cntl
703                .dig_iso()
704                .modify(|_, w| w.wifi_force_noiso().clear_bit());
705
706            rtc_cntl.dig_pwc().modify(|_, w| {
707                w.wifi_force_pu().clear_bit();
708                w.wifi_pd_en().set_bit()
709            });
710        } else {
711            rtc_cntl.dig_pwc().modify(|_, w| w.wifi_pd_en().clear_bit());
712        }
713
714        unsafe {
715            rtc_cntl.reg().modify(|_, w| {
716                w.dbias_slp().bits(self.rtc_dbias_slp());
717                w.dig_reg_dbias_slp().bits(self.dig_dbias_slp())
718            });
719
720            rtc_cntl.bias_conf().modify(|_, w| {
721                w.dbg_atten_monitor()
722                    .bits(RTC_CNTL_DBG_ATTEN_MONITOR_DEFAULT);
723                w.bias_sleep_monitor().bit(self.bias_sleep_monitor());
724                w.bias_sleep_deep_slp().bit(self.bias_sleep_slp());
725                w.pd_cur_monitor().bit(self.pd_cur_monitor());
726                w.pd_cur_deep_slp().bit(self.pd_cur_slp());
727                w.dbg_atten_deep_slp().bits(self.dbg_atten_slp())
728            });
729
730            if self.deep_slp() {
731                rtc_cntl
732                    .dig_pwc()
733                    .modify(|_, w| w.dg_wrap_pd_en().set_bit());
734
735                rtc_cntl.ana_conf().modify(|_, w| {
736                    w.ckgen_i2c_pu().clear_bit();
737                    w.pll_i2c_pu().clear_bit();
738                    w.rfrx_pbus_pu().clear_bit();
739                    w.txrf_i2c_pu().clear_bit()
740                });
741
742                rtc_cntl
743                    .options0()
744                    .modify(|_, w| w.bb_i2c_force_pu().clear_bit());
745            } else {
746                rtc_cntl
747                    .dig_pwc()
748                    .modify(|_, w| w.dg_wrap_pd_en().clear_bit());
749            }
750
751            let rtc_regulator_fpu = self.rtc_regulator_fpu();
752            rtc_cntl
753                .reg()
754                .modify(|_, w| w.regulator_force_pu().bit(rtc_regulator_fpu));
755
756            let int_8m_pd_en = self.int_8m_pd_en();
757            rtc_cntl
758                .clk_conf()
759                .modify(|_, w| w.ck8m_force_pu().bit(!int_8m_pd_en));
760
761            // enable VDDSDIO control by state machine
762            rtc_cntl.sdio_conf().modify(|_, w| {
763                w.sdio_force().clear_bit();
764                w.sdio_reg_pd_en().bit(self.vddsdio_pd_en())
765            });
766
767            rtc_cntl.slp_reject_conf().modify(|_, w| {
768                w.deep_slp_reject_en().bit(self.deep_slp_reject());
769                w.light_slp_reject_en().bit(self.light_slp_reject())
770            });
771
772            // Set wait cycle for touch or COCPU after deep sleep and light
773            // sleep.
774
775            rtc_cntl.timer2().modify(|_, w| {
776                w.ulpcp_touch_start_wait()
777                    .bits(RTC_CNTL_ULPCP_TOUCH_START_WAIT_IN_SLEEP)
778            });
779
780            rtc_cntl
781                .options0()
782                .modify(|_, w| w.xtl_force_pu().bit(self.xtal_fpu()));
783        }
784    }
785
786    pub(crate) fn start_sleep(&self, wakeup_triggers: WakeTriggers) {
787        // TODO: Add reject triggers
788        unsafe {
789            LPWR::regs()
790                .reset_state()
791                .modify(|_, w| w.procpu_stat_vector_sel().set_bit());
792
793            // set bits for what can wake us up
794            LPWR::regs()
795                .wakeup_state()
796                .modify(|_, w| w.wakeup_ena().bits(wakeup_triggers.0.into()));
797
798            // WARN: slp_wakeup is not set in esp-idf
799            LPWR::regs().state0().write(|w| {
800                w.sleep_en().set_bit();
801                w.slp_wakeup().set_bit()
802            });
803        }
804    }
805
806    pub(crate) fn finish_sleep(&self) {
807        // In deep sleep mode, we never get here
808        unsafe {
809            LPWR::regs().int_clr().write(|w| {
810                w.slp_reject()
811                    .clear_bit_by_one()
812                    .slp_wakeup()
813                    .clear_bit_by_one()
814            });
815
816            // restore config if it is a light sleep
817            if self.lslp_mem_inf_fpu() {
818                rtc_sleep_pu(true);
819            }
820
821            // Recover default wait cycle for touch or COCPU after wakeup.
822
823            LPWR::regs().timer2().modify(|_, w| {
824                w.ulpcp_touch_start_wait()
825                    .bits(RTC_CNTL_ULPCP_TOUCH_START_WAIT_DEFAULT)
826            });
827        }
828    }
829}