esp_hal/rtc_cntl/sleep/
esp32s2.rs

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