Skip to main content

esp_hal/rtc_cntl/sleep/
esp32s3.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::{APB_CTRL, EXTMEM, LPWR, RTC_IO, 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 = 13;
22/// Digital bias setting for 0.95V.
23pub const RTC_CNTL_DBIAS_0V95: u8 = 16;
24/// Digital bias setting for 1.00V.
25pub const RTC_CNTL_DBIAS_1V00: u8 = 18;
26/// Digital bias setting for 1.05V.
27pub const RTC_CNTL_DBIAS_1V05: u8 = 20;
28/// Digital bias setting for 1.10V.
29pub const RTC_CNTL_DBIAS_1V10: u8 = 23;
30/// Digital bias setting for 1.15V.
31pub const RTC_CNTL_DBIAS_1V15: u8 = 25;
32/// Digital bias setting for 1.20V.
33pub const RTC_CNTL_DBIAS_1V20: u8 = 28;
34/// Digital bias setting for 1.25V.
35pub const RTC_CNTL_DBIAS_1V25: u8 = 30;
36/// Digital bias setting for 1.30V. Voltage is approximately 1.34V in practice.
37pub const RTC_CNTL_DBIAS_1V30: u8 = 31;
38/// Default monitor debug attenuation value.
39pub const RTC_CNTL_DBG_ATTEN_MONITOR_DEFAULT: u8 = 0;
40/// ULP co-processor touch start wait time during sleep, set to maximum.
41pub const RTC_CNTL_ULPCP_TOUCH_START_WAIT_IN_SLEEP: u16 = 0xFF;
42/// ULP co-processor touch start wait time default value.
43pub const RTC_CNTL_ULPCP_TOUCH_START_WAIT_DEFAULT: u16 = 0x10;
44/// Default wait time for PLL buffer during startup.
45pub const RTC_CNTL_PLL_BUF_WAIT_DEFAULT: u8 = 20;
46/// Default wait time for CK8M during startup.
47pub const RTC_CNTL_CK8M_WAIT_DEFAULT: u8 = 20;
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_ULTRA_LOW: 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/// Bluetooth power-up cycles.
61pub const BT_POWERUP_CYCLES: u8 = OTHER_BLOCKS_POWERUP;
62/// Bluetooth wait cycles.
63pub const BT_WAIT_CYCLES: u16 = OTHER_BLOCKS_WAIT;
64/// RTC power-up cycles.
65pub const RTC_POWERUP_CYCLES: u8 = OTHER_BLOCKS_POWERUP;
66/// RTC wait cycles.
67pub const RTC_WAIT_CYCLES: u16 = OTHER_BLOCKS_WAIT;
68/// CPU top power-up cycles.
69pub const CPU_TOP_POWERUP_CYCLES: u8 = OTHER_BLOCKS_POWERUP;
70/// CPU top wait cycles.
71pub const CPU_TOP_WAIT_CYCLES: u16 = OTHER_BLOCKS_WAIT;
72/// DG wrap power-up cycles.
73pub const DG_WRAP_POWERUP_CYCLES: u8 = OTHER_BLOCKS_POWERUP;
74/// DG wrap wait cycles.
75pub const DG_WRAP_WAIT_CYCLES: u16 = OTHER_BLOCKS_WAIT;
76/// DG peripheral power-up cycles.
77pub const DG_PERI_POWERUP_CYCLES: u8 = OTHER_BLOCKS_POWERUP;
78/// DG peripheral wait cycles.
79pub const DG_PERI_WAIT_CYCLES: u16 = OTHER_BLOCKS_WAIT;
80/// RTC memory power-up cycles.
81pub const RTC_MEM_POWERUP_CYCLES: u8 = OTHER_BLOCKS_POWERUP;
82/// RTC memory wait cycles.
83pub const RTC_MEM_WAIT_CYCLES: u16 = OTHER_BLOCKS_WAIT;
84
85impl WakeSource for UlpWakeupSource {
86    fn apply(
87        &self,
88        _rtc: &Rtc<'_>,
89        triggers: &mut WakeTriggers,
90        sleep_config: &mut RtcSleepConfig,
91    ) {
92        triggers.set_ulp_fsm(self.wake_on_interrupt);
93        triggers.set_ulp_riscv(self.wake_on_interrupt);
94        triggers.set_ulp_riscv_trap(self.wake_on_trap);
95
96        if self.clear_interrupts_on_sleep {
97            self.clear_interrupts();
98        }
99
100        // This one needs to be false to keep the ULP timer and ULP GPIO happy!
101        // Possibly relevant issue: https://github.com/espressif/esp-idf/issues/10595
102        sleep_config.set_rtc_peri_pd_en(false);
103    }
104}
105
106impl WakeSource for TimerWakeupSource {
107    fn apply(
108        &self,
109        rtc: &Rtc<'_>,
110        triggers: &mut WakeTriggers,
111        _sleep_config: &mut RtcSleepConfig,
112    ) {
113        triggers.set_timer(true);
114        let rtc_cntl = LPWR::regs();
115        // TODO: maybe add check to prevent overflow?
116        let ticks = crate::clock::us_to_rtc_ticks(self.duration.as_micros() as u64);
117        // "alarm" time in slow rtc ticks
118        let now = rtc.time_since_boot_raw();
119        let time_in_ticks = now + ticks;
120        unsafe {
121            rtc_cntl
122                .slp_timer0()
123                .write(|w| w.slp_val_lo().bits((time_in_ticks & 0xffffffff) as u32));
124
125            rtc_cntl
126                .int_clr()
127                .write(|w| w.main_timer().clear_bit_by_one());
128
129            rtc_cntl.slp_timer1().write(|w| {
130                w.slp_val_hi().bits(((time_in_ticks >> 32) & 0xffff) as u16);
131                w.main_timer_alarm_en().set_bit()
132            });
133        }
134    }
135}
136
137impl<P: RtcPin> WakeSource for Ext0WakeupSource<P> {
138    fn apply(
139        &self,
140        _rtc: &Rtc<'_>,
141        triggers: &mut WakeTriggers,
142        sleep_config: &mut RtcSleepConfig,
143    ) {
144        // don't power down RTC peripherals
145        sleep_config.set_rtc_peri_pd_en(false);
146        triggers.set_ext0(true);
147
148        // set pin to RTC function
149        self.pin
150            .borrow_mut()
151            .rtc_set_config(true, true, RtcFunction::Rtc);
152
153        unsafe {
154            let rtc_io = RTC_IO::regs();
155            // set pin register field
156            rtc_io
157                .ext_wakeup0()
158                .modify(|_, w| w.sel().bits(self.pin.borrow().rtc_number()));
159            // set level register field
160            let rtc_cntl = LPWR::regs();
161            rtc_cntl
162                .ext_wakeup_conf()
163                .modify(|_r, w| w.ext_wakeup0_lv().bit(self.level == WakeupLevel::High));
164        }
165    }
166}
167
168impl<P: RtcPin> Drop for Ext0WakeupSource<P> {
169    fn drop(&mut self) {
170        // should we have saved the pin configuration first?
171        // set pin back to IO_MUX (input_enable and func have no effect when pin is sent
172        // to IO_MUX)
173        self.pin
174            .borrow_mut()
175            .rtc_set_config(true, false, RtcFunction::Rtc);
176    }
177}
178
179impl WakeSource for Ext1WakeupSource<'_, '_> {
180    fn apply(
181        &self,
182        _rtc: &Rtc<'_>,
183        triggers: &mut WakeTriggers,
184        sleep_config: &mut RtcSleepConfig,
185    ) {
186        // don't power down RTC peripherals
187        sleep_config.set_rtc_peri_pd_en(false);
188        triggers.set_ext1(true);
189
190        // set pins to RTC function
191        let mut pins = self.pins.borrow_mut();
192        let mut bits = 0u32;
193        for pin in pins.iter_mut() {
194            pin.rtc_set_config(true, true, RtcFunction::Rtc);
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.ext_wakeup1_status_clr().set_bit());
204            // set pin register field
205            rtc_cntl
206                .ext_wakeup1()
207                .modify(|_, w| w.ext_wakeup1_sel().bits(bits));
208            // set level register field
209            rtc_cntl
210                .ext_wakeup_conf()
211                .modify(|_r, w| w.ext_wakeup1_lv().bit(self.level == WakeupLevel::High));
212        }
213    }
214}
215
216impl Drop for Ext1WakeupSource<'_, '_> {
217    fn drop(&mut self) {
218        // should we have saved the pin configuration first?
219        // set pin back to IO_MUX (input_enable and func have no effect when pin is sent
220        // to IO_MUX)
221        let mut pins = self.pins.borrow_mut();
222        for pin in pins.iter_mut() {
223            pin.rtc_set_config(true, false, RtcFunction::Rtc);
224        }
225    }
226}
227
228impl RtcioWakeupSource<'_, '_> {
229    fn apply_pin(&self, pin: &mut dyn RtcPin, level: WakeupLevel) {
230        let rtcio = RTC_IO::regs();
231
232        pin.rtc_set_config(true, true, RtcFunction::Rtc);
233
234        rtcio.pin(pin.number() as usize).modify(|_, w| unsafe {
235            w.wakeup_enable().set_bit().int_type().bits(match level {
236                WakeupLevel::Low => 4,
237                WakeupLevel::High => 5,
238            })
239        });
240    }
241}
242
243impl WakeSource for RtcioWakeupSource<'_, '_> {
244    fn apply(
245        &self,
246        _rtc: &Rtc<'_>,
247        triggers: &mut WakeTriggers,
248        sleep_config: &mut RtcSleepConfig,
249    ) {
250        let mut pins = self.pins.borrow_mut();
251
252        if pins.is_empty() {
253            return;
254        }
255
256        // don't power down RTC peripherals
257        sleep_config.set_rtc_peri_pd_en(false);
258        triggers.set_gpio(true);
259
260        // Since we only use RTCIO pins, we can keep deep sleep enabled.
261        let sens = crate::peripherals::SENS::regs();
262
263        // TODO: disable clock when not in use
264        sens.sar_peri_clk_gate_conf()
265            .modify(|_, w| w.iomux_clk_en().set_bit());
266
267        for (pin, level) in pins.iter_mut() {
268            self.apply_pin(*pin, *level);
269        }
270    }
271}
272
273impl Drop for RtcioWakeupSource<'_, '_> {
274    fn drop(&mut self) {
275        // should we have saved the pin configuration first?
276        // set pin back to IO_MUX (input_enable and func have no effect when pin is sent
277        // to IO_MUX)
278        let mut pins = self.pins.borrow_mut();
279        for (pin, _level) in pins.iter_mut() {
280            pin.rtc_set_config(true, false, RtcFunction::Rtc);
281        }
282    }
283}
284
285bitfield::bitfield! {
286    /// Configuration for the RTC sleep behavior.
287    #[derive(Clone, Copy)]
288    pub struct RtcSleepConfig(u64);
289    impl Debug;
290    /// force normal voltage in sleep mode (digital domain memory)
291    pub lslp_mem_inf_fpu, set_lslp_mem_inf_fpu: 0;
292    /// keep low voltage in sleep mode (even if ULP/touch is used)
293    pub rtc_mem_inf_follow_cpu, set_rtc_mem_inf_follow_cpu: 1;
294    /// power down RTC fast memory
295    pub rtc_fastmem_pd_en, set_rtc_fastmem_pd_en: 2;
296    /// power down RTC slow memory
297    pub rtc_slowmem_pd_en, set_rtc_slowmem_pd_en: 3;
298    /// power down RTC peripherals
299    pub rtc_peri_pd_en, set_rtc_peri_pd_en: 4;
300    /// power down Modem(wifi and ble)
301    pub modem_pd_en, set_modem_pd_en: 5;
302    /// power down CPU, but not restart when lightsleep.
303    pub cpu_pd_en, set_cpu_pd_en: 6;
304    /// Power down Internal 8M oscillator
305    pub int_8m_pd_en, set_int_8m_pd_en: 7;
306    /// power down digital peripherals
307    pub dig_peri_pd_en, set_dig_peri_pd_en: 8;
308    /// power down digital domain
309    pub deep_slp, set_deep_slp: 9;
310    /// enable WDT flashboot mode
311    pub wdt_flashboot_mod_en, set_wdt_flashboot_mod_en: 10;
312    /// set bias for digital domain, in sleep mode
313    pub u8, dig_dbias_slp, set_dig_dbias_slp: 15, 11;
314    /// set bias for RTC domain, in sleep mode
315    pub u8, rtc_dbias_slp, set_rtc_dbias_slp: 20, 16;
316    /// circuit control parameter, in monitor mode
317    pub bias_sleep_monitor, set_bias_sleep_monitor: 21;
318    /// voltage parameter, in sleep mode
319    pub u8, dbg_atten_slp, set_dbg_atten_slp: 25, 22;
320    /// circuit control parameter, in sleep mode
321    pub bias_sleep_slp, set_bias_sleep_slp: 26;
322    /// circuit control parameter, in monitor mode
323    pub pd_cur_monitor, set_pd_cur_monitor: 27;
324    /// circuit control parameter, in sleep mode
325    pub pd_cur_slp, set_pd_cur_slp: 28;
326    /// power down VDDSDIO regulator
327    pub vddsdio_pd_en, set_vddsdio_pd_en: 29;
328    /// keep main XTAL powered up in sleep
329    pub xtal_fpu, set_xtal_fpu: 30;
330    /// keep rtc regulator powered up in sleep
331    pub rtc_regulator_fpu, set_rtc_regulator_fpu: 31;
332    /// enable deep sleep reject
333    pub deep_slp_reject, set_deep_slp_reject: 32;
334    /// enable light sleep reject
335    pub light_slp_reject, set_light_slp_reject: 33;
336}
337
338impl Default for RtcSleepConfig {
339    fn default() -> Self {
340        let mut cfg = Self(Default::default());
341        cfg.set_deep_slp_reject(true);
342        cfg.set_light_slp_reject(true);
343        cfg.set_rtc_dbias_slp(RTC_CNTL_DBIAS_1V10);
344        cfg.set_dig_dbias_slp(RTC_CNTL_DBIAS_1V10);
345        cfg
346    }
347}
348
349const SYSCON_SRAM_POWER_UP: u16 = 0x7FF;
350const SYSCON_ROM_POWER_UP: u8 = 0x7;
351
352fn rtc_sleep_pu(val: bool) {
353    let rtc_cntl = LPWR::regs();
354    let syscon = unsafe { &*esp32s3::APB_CTRL::ptr() };
355    let bb = unsafe { &*esp32s3::BB::ptr() };
356    let nrx = unsafe { &*esp32s3::NRX::ptr() };
357    let fe = unsafe { &*esp32s3::FE::ptr() };
358    let fe2 = unsafe { &*esp32s3::FE2::ptr() };
359
360    rtc_cntl
361        .dig_pwc()
362        .modify(|_, w| w.lslp_mem_force_pu().bit(val));
363
364    rtc_cntl
365        .pwc()
366        .modify(|_, w| w.slowmem_force_lpu().bit(val).fastmem_force_lpu().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    syscon.mem_power_up().modify(|_r, w| unsafe {
395        w.sram_power_up()
396            .bits(if val { SYSCON_SRAM_POWER_UP } else { 0 })
397            .rom_power_up()
398            .bits(if val { SYSCON_ROM_POWER_UP } else { 0 })
399    });
400}
401
402impl RtcSleepConfig {
403    /// Configures the RTC for deep sleep mode.
404    pub fn deep() -> Self {
405        // Set up for ultra-low power sleep. Wakeup sources may modify these settings.
406        let mut cfg = Self::default();
407
408        cfg.set_lslp_mem_inf_fpu(false);
409        cfg.set_rtc_mem_inf_follow_cpu(true); // ?
410        cfg.set_rtc_fastmem_pd_en(true);
411        cfg.set_rtc_slowmem_pd_en(true);
412        cfg.set_rtc_peri_pd_en(true);
413        cfg.set_modem_pd_en(true);
414        cfg.set_cpu_pd_en(true);
415        cfg.set_int_8m_pd_en(true);
416
417        cfg.set_dig_peri_pd_en(true);
418        cfg.set_dig_dbias_slp(0); // because of dig_peri_pd_en
419
420        cfg.set_deep_slp(true);
421        cfg.set_wdt_flashboot_mod_en(false);
422        cfg.set_vddsdio_pd_en(true);
423        cfg.set_xtal_fpu(false);
424        cfg.set_deep_slp_reject(true);
425        cfg.set_light_slp_reject(true);
426        cfg.set_rtc_dbias_slp(RTC_CNTL_DBIAS_1V10);
427
428        // because of dig_peri_pd_en
429        cfg.set_rtc_regulator_fpu(false);
430        cfg.set_dbg_atten_slp(RTC_CNTL_DBG_ATTEN_DEEPSLEEP_ULTRA_LOW);
431
432        // because of xtal_fpu
433        cfg.set_bias_sleep_monitor(true);
434        cfg.set_pd_cur_monitor(true);
435        cfg.set_bias_sleep_slp(true);
436        cfg.set_pd_cur_slp(true);
437
438        cfg
439    }
440
441    pub(crate) fn base_settings(_rtc: &Rtc<'_>) {
442        // settings derived from esp_clk_init -> rtc_init
443        unsafe {
444            let rtc_cntl = LPWR::regs();
445            let syscon = APB_CTRL::regs();
446            let extmem = EXTMEM::regs();
447            let system = SYSTEM::regs();
448
449            rtc_cntl
450                .dig_pwc()
451                .modify(|_, w| w.wifi_force_pd().clear_bit());
452
453            regi2c::I2C_DIG_REG_XPD_RTC_REG.write_field(0);
454            regi2c::I2C_DIG_REG_XPD_DIG_REG.write_field(0);
455
456            rtc_cntl.ana_conf().modify(|_, w| w.pvtmon_pu().clear_bit());
457
458            rtc_cntl.timer1().modify(|_, w| {
459                w.pll_buf_wait()
460                    .bits(RTC_CNTL_PLL_BUF_WAIT_DEFAULT)
461                    .ck8m_wait()
462                    .bits(RTC_CNTL_CK8M_WAIT_DEFAULT)
463            });
464
465            // Moved from rtc sleep to rtc init to save sleep function running time
466            // set shortest possible sleep time limit
467
468            rtc_cntl
469                .timer5()
470                .modify(|_, w| w.min_slp_val().bits(RTC_CNTL_MIN_SLP_VAL_MIN));
471
472            rtc_cntl.timer3().modify(|_, w| {
473                // set wifi timer
474                w.wifi_powerup_timer().bits(WIFI_POWERUP_CYCLES);
475                // set bt timer
476                w.wifi_wait_timer().bits(WIFI_WAIT_CYCLES);
477                w.bt_powerup_timer().bits(BT_POWERUP_CYCLES);
478                w.bt_wait_timer().bits(BT_WAIT_CYCLES)
479            });
480
481            rtc_cntl.timer6().modify(|_, w| {
482                w.cpu_top_powerup_timer().bits(CPU_TOP_POWERUP_CYCLES);
483                w.cpu_top_wait_timer().bits(CPU_TOP_WAIT_CYCLES)
484            });
485
486            rtc_cntl.timer4().modify(|_, w| {
487                // set rtc peri timer
488                w.powerup_timer().bits(RTC_POWERUP_CYCLES);
489                // set digital wrap timer
490                w.wait_timer().bits(RTC_WAIT_CYCLES);
491                w.dg_wrap_powerup_timer().bits(DG_WRAP_POWERUP_CYCLES);
492                w.dg_wrap_wait_timer().bits(DG_WRAP_WAIT_CYCLES)
493            });
494
495            rtc_cntl.timer6().modify(|_, w| {
496                w.dg_peri_powerup_timer().bits(DG_PERI_POWERUP_CYCLES);
497                w.dg_peri_wait_timer().bits(DG_PERI_WAIT_CYCLES)
498            });
499
500            // Reset RTC bias to default value (needed if waking up from deep sleep)
501            regi2c::I2C_DIG_REG_EXT_RTC_DREG_SLEEP.write_field(RTC_CNTL_DBIAS_1V10);
502            regi2c::I2C_DIG_REG_EXT_RTC_DREG.write_field(RTC_CNTL_DBIAS_1V10);
503
504            // Set the wait time to the default value.
505
506            rtc_cntl.timer2().modify(|_, w| {
507                w.ulpcp_touch_start_wait()
508                    .bits(RTC_CNTL_ULPCP_TOUCH_START_WAIT_DEFAULT)
509            });
510
511            // LDO dbias initialization
512            // TODO: this modifies g_rtc_dbias_pvt_non_240m and g_dig_dbias_pvt_non_240m.
513            //       We're using a high enough default but we should read from the efuse.
514            // rtc_set_stored_dbias();
515
516            regi2c::I2C_DIG_REG_EXT_RTC_DREG.write_field(RTC_CNTL_DBIAS_1V25);
517            regi2c::I2C_DIG_REG_EXT_DIG_DREG.write_field(RTC_CNTL_DBIAS_1V25);
518
519            // clear CMMU clock force on
520
521            extmem
522                .cache_mmu_power_ctrl()
523                .modify(|_, w| w.cache_mmu_mem_force_on().clear_bit());
524
525            // clear clkgate force on
526            syscon.clkgate_force_on().write(|w| w.bits(0));
527
528            // clear tag clock force on
529
530            extmem
531                .dcache_tag_power_ctrl()
532                .modify(|_, w| w.dcache_tag_mem_force_on().clear_bit());
533
534            extmem
535                .icache_tag_power_ctrl()
536                .modify(|_, w| w.icache_tag_mem_force_on().clear_bit());
537
538            // clear register clock force on
539            SPI0::regs()
540                .clock_gate()
541                .modify(|_, w| w.clk_en().clear_bit());
542            SPI1::regs()
543                .clock_gate()
544                .modify(|_, w| w.clk_en().clear_bit());
545
546            rtc_cntl
547                .clk_conf()
548                .modify(|_, w| w.ck8m_force_pu().clear_bit());
549
550            rtc_cntl
551                .options0()
552                .modify(|_, w| w.xtl_force_pu().clear_bit());
553
554            rtc_cntl.ana_conf().modify(|_, w| {
555                w
556                    // open sar_i2c protect function to avoid sar_i2c reset when rtc_ldo is low.
557                    // clear i2c_reset_protect pd force, need tested in low temperature.
558                    // NOTE: this bit is written again in esp-idf, but it's not clear why.
559                    .i2c_reset_por_force_pd()
560                    .clear_bit()
561            });
562
563            // cancel bbpll force pu if setting no force power up
564
565            rtc_cntl.options0().modify(|_, w| {
566                w.bbpll_force_pu().clear_bit();
567                w.bbpll_i2c_force_pu().clear_bit();
568                w.bb_i2c_force_pu().clear_bit()
569            });
570
571            // cancel RTC REG force PU
572
573            rtc_cntl.pwc().modify(|_, w| w.force_pu().clear_bit());
574
575            rtc_cntl.rtc().modify(|_, w| {
576                w.regulator_force_pu().clear_bit();
577                w.dboost_force_pu().clear_bit()
578            });
579
580            rtc_cntl.pwc().modify(|_, w| {
581                w.slowmem_force_noiso().clear_bit();
582                w.fastmem_force_noiso().clear_bit()
583            });
584
585            rtc_cntl.rtc().modify(|_, w| w.dboost_force_pd().set_bit());
586
587            // If this mask is enabled, all soc memories cannot enter power down mode
588            // We should control soc memory power down mode from RTC, so we will not touch
589            // this register any more
590
591            system
592                .mem_pd_mask()
593                .modify(|_, w| w.lslp_mem_pd_mask().clear_bit());
594
595            // If this pd_cfg is set to 1, all memory won't enter low power mode during
596            // light sleep If this pd_cfg is set to 0, all memory will enter low
597            // power mode during light sleep
598            rtc_sleep_pu(false);
599
600            rtc_cntl
601                .dig_pwc()
602                .modify(|_, w| w.dg_wrap_force_pu().clear_bit());
603
604            rtc_cntl.dig_iso().modify(|_, w| {
605                w.dg_wrap_force_noiso().clear_bit();
606                w.dg_wrap_force_iso().clear_bit()
607            });
608
609            rtc_cntl.dig_iso().modify(|_, w| {
610                w.wifi_force_noiso().clear_bit();
611                w.wifi_force_iso().clear_bit()
612            });
613
614            rtc_cntl
615                .dig_pwc()
616                .modify(|_, w| w.wifi_force_pu().clear_bit());
617
618            rtc_cntl
619                .dig_iso()
620                .modify(|_, w| w.bt_force_noiso().clear_bit().bt_force_iso().clear_bit());
621
622            rtc_cntl
623                .dig_pwc()
624                .modify(|_, w| w.bt_force_pu().clear_bit());
625
626            rtc_cntl.dig_iso().modify(|_, w| {
627                w.cpu_top_force_noiso().clear_bit();
628                w.cpu_top_force_iso().clear_bit()
629            });
630
631            rtc_cntl
632                .dig_pwc()
633                .modify(|_, w| w.cpu_top_force_pu().clear_bit());
634
635            rtc_cntl.dig_iso().modify(|_, w| {
636                w.dg_peri_force_noiso().clear_bit();
637                w.dg_peri_force_iso().clear_bit()
638            });
639
640            rtc_cntl
641                .dig_pwc()
642                .modify(|_, w| w.dg_peri_force_pu().clear_bit());
643
644            rtc_cntl.pwc().modify(|_, w| {
645                w.force_noiso().clear_bit();
646                w.force_iso().clear_bit();
647                w.force_pu().clear_bit()
648            });
649
650            // if SYSTEM_CPU_WAIT_MODE_FORCE_ON == 0,
651            // the cpu clk will be closed when cpu enter WAITI mode
652
653            system
654                .cpu_per_conf()
655                .modify(|_, w| w.cpu_wait_mode_force_on().clear_bit());
656
657            // cancel digital PADS force no iso
658
659            rtc_cntl.dig_iso().modify(|_, w| {
660                w.dg_pad_force_unhold().clear_bit();
661                w.dg_pad_force_noiso().clear_bit()
662            });
663
664            // force power down modem(wifi and ble) power domain
665
666            rtc_cntl
667                .dig_iso()
668                .modify(|_, w| w.wifi_force_iso().set_bit());
669
670            rtc_cntl
671                .dig_pwc()
672                .modify(|_, w| w.wifi_force_pd().set_bit());
673
674            rtc_cntl.int_ena().write(|w| w.bits(0));
675            rtc_cntl.int_clr().write(|w| w.bits(u32::MAX));
676        }
677    }
678
679    pub(crate) fn apply(&self) {
680        // like esp-idf rtc_sleep_init()
681        let rtc_cntl = LPWR::regs();
682
683        if self.lslp_mem_inf_fpu() {
684            rtc_sleep_pu(true);
685        }
686
687        if self.modem_pd_en() {
688            rtc_cntl.dig_iso().modify(|_, w| {
689                w.wifi_force_noiso().clear_bit();
690                w.wifi_force_iso().clear_bit()
691            });
692
693            rtc_cntl
694                .dig_pwc()
695                .modify(|_, w| w.wifi_force_pu().clear_bit().wifi_pd_en().set_bit());
696        } else {
697            rtc_cntl.options0().modify(|_, w| {
698                w.bbpll_force_pu().set_bit();
699                w.bbpll_i2c_force_pu().set_bit();
700                w.bb_i2c_force_pu().set_bit()
701            });
702
703            rtc_cntl
704                .dig_pwc()
705                .modify(|_, w| w.wifi_force_pu().set_bit().wifi_pd_en().clear_bit());
706        }
707
708        if self.cpu_pd_en() {
709            rtc_cntl.dig_iso().modify(|_, w| {
710                w.cpu_top_force_noiso().clear_bit();
711                w.cpu_top_force_iso().clear_bit()
712            });
713
714            rtc_cntl
715                .dig_pwc()
716                .modify(|_, w| w.cpu_top_force_pu().clear_bit().cpu_top_pd_en().set_bit());
717        } else {
718            rtc_cntl
719                .dig_pwc()
720                .modify(|_, w| w.cpu_top_pd_en().clear_bit());
721        }
722
723        if self.dig_peri_pd_en() {
724            rtc_cntl.dig_iso().modify(|_, w| {
725                w.dg_peri_force_noiso().clear_bit();
726                w.dg_peri_force_iso().clear_bit()
727            });
728
729            rtc_cntl
730                .dig_pwc()
731                .modify(|_, w| w.dg_peri_force_pu().clear_bit().dg_peri_pd_en().set_bit());
732        } else {
733            rtc_cntl
734                .dig_pwc()
735                .modify(|_, w| w.dg_peri_pd_en().clear_bit());
736        }
737
738        if self.rtc_peri_pd_en() {
739            rtc_cntl.pwc().modify(|_, w| {
740                w.force_noiso().clear_bit();
741                w.force_iso().clear_bit();
742                w.force_pu().clear_bit();
743                w.pd_en().set_bit()
744            });
745        } else {
746            rtc_cntl.pwc().modify(|_, w| w.pd_en().clear_bit());
747        }
748
749        unsafe {
750            regi2c::I2C_DIG_REG_EXT_RTC_DREG_SLEEP.write_field(self.rtc_dbias_slp());
751            regi2c::I2C_DIG_REG_EXT_DIG_DREG_SLEEP.write_field(self.dig_dbias_slp());
752
753            rtc_cntl.bias_conf().modify(|_, w| {
754                w.dbg_atten_deep_slp().bits(self.dbg_atten_slp());
755                w.bias_sleep_deep_slp().bit(self.bias_sleep_slp());
756                w.pd_cur_deep_slp().bit(self.pd_cur_slp());
757                w.dbg_atten_monitor()
758                    .bits(RTC_CNTL_DBG_ATTEN_MONITOR_DEFAULT);
759                w.bias_sleep_monitor().bit(self.bias_sleep_monitor());
760                w.pd_cur_monitor().bit(self.pd_cur_monitor())
761            });
762
763            if self.deep_slp() {
764                rtc_cntl
765                    .dig_pwc()
766                    .modify(|_, w| w.dg_wrap_pd_en().set_bit());
767
768                rtc_cntl.ana_conf().modify(|_, w| {
769                    w.ckgen_i2c_pu().clear_bit();
770                    w.pll_i2c_pu().clear_bit();
771                    w.rfrx_pbus_pu().clear_bit();
772                    w.txrf_i2c_pu().clear_bit()
773                });
774
775                rtc_cntl
776                    .options0()
777                    .modify(|_, w| w.bb_i2c_force_pu().clear_bit());
778            } else {
779                rtc_cntl
780                    .regulator_drv_ctrl()
781                    .modify(|_, w| w.dg_vdd_drv_b_slp().bits(0xF));
782
783                rtc_cntl
784                    .dig_pwc()
785                    .modify(|_, w| w.dg_wrap_pd_en().clear_bit());
786            }
787
788            // mem force pu
789
790            rtc_cntl
791                .dig_pwc()
792                .modify(|_, w| w.lslp_mem_force_pu().set_bit());
793
794            rtc_cntl
795                .rtc()
796                .modify(|_, w| w.regulator_force_pu().bit(self.rtc_regulator_fpu()));
797
798            rtc_cntl
799                .clk_conf()
800                .modify(|_, w| w.ck8m_force_pu().bit(!self.int_8m_pd_en()));
801
802            // enable VDDSDIO control by state machine
803
804            rtc_cntl.sdio_conf().modify(|_, w| {
805                w.sdio_force().clear_bit();
806                w.sdio_reg_pd_en().bit(self.vddsdio_pd_en())
807            });
808
809            rtc_cntl.slp_reject_conf().modify(|_, w| {
810                w.deep_slp_reject_en().bit(self.deep_slp_reject());
811                w.light_slp_reject_en().bit(self.light_slp_reject())
812            });
813
814            // Set wait cycle for touch or COCPU after deep sleep and light
815            // sleep.
816
817            rtc_cntl.timer2().modify(|_, w| {
818                w.ulpcp_touch_start_wait()
819                    .bits(RTC_CNTL_ULPCP_TOUCH_START_WAIT_IN_SLEEP)
820            });
821
822            rtc_cntl
823                .options0()
824                .modify(|_, w| w.xtl_force_pu().bit(self.xtal_fpu()));
825
826            rtc_cntl
827                .clk_conf()
828                .modify(|_, w| w.xtal_global_force_nogating().bit(self.xtal_fpu()));
829        }
830    }
831
832    pub(crate) fn start_sleep(&self, wakeup_triggers: WakeTriggers) {
833        unsafe {
834            LPWR::regs()
835                .reset_state()
836                .modify(|_, w| w.procpu_stat_vector_sel().set_bit());
837
838            // set bits for what can wake us up
839            LPWR::regs()
840                .wakeup_state()
841                .modify(|_, w| w.wakeup_ena().bits(wakeup_triggers.0.into()));
842
843            LPWR::regs()
844                .state0()
845                .write(|w| w.sleep_en().set_bit().slp_wakeup().set_bit());
846        }
847    }
848
849    pub(crate) fn finish_sleep(&self) {
850        // In deep sleep mode, we never get here
851        unsafe {
852            LPWR::regs().int_clr().write(|w| {
853                w.slp_reject()
854                    .clear_bit_by_one()
855                    .slp_wakeup()
856                    .clear_bit_by_one()
857            });
858
859            // restore config if it is a light sleep
860            if self.lslp_mem_inf_fpu() {
861                rtc_sleep_pu(true);
862            }
863
864            // Recover default wait cycle for touch or COCPU after wakeup.
865
866            LPWR::regs().timer2().modify(|_, w| {
867                w.ulpcp_touch_start_wait()
868                    .bits(RTC_CNTL_ULPCP_TOUCH_START_WAIT_DEFAULT)
869            });
870        }
871    }
872}