esp_hal/rtc_cntl/rtc/
esp32h2.rs

1use strum::FromRepr;
2
3use crate::{
4    clock::{clocks_ll::regi2c_write_mask, Clock, XtalClock},
5    peripherals::{LPWR, LP_AON, PCR, PMU, TIMG0},
6    rtc_cntl::RtcClock,
7    time::Rate,
8};
9
10const I2C_PMU: u8 = 0x6d;
11const I2C_PMU_HOSTID: u8 = 0;
12
13const I2C_PMU_EN_I2C_RTC_DREG: u8 = 8;
14const I2C_PMU_EN_I2C_RTC_DREG_MSB: u8 = 0;
15const I2C_PMU_EN_I2C_RTC_DREG_LSB: u8 = 0;
16
17const I2C_PMU_EN_I2C_DIG_DREG: u8 = 8;
18const I2C_PMU_EN_I2C_DIG_DREG_MSB: u8 = 1;
19const I2C_PMU_EN_I2C_DIG_DREG_LSB: u8 = 1;
20
21const I2C_PMU_EN_I2C_RTC_DREG_SLP: u8 = 8;
22const I2C_PMU_EN_I2C_RTC_DREG_SLP_MSB: u8 = 2;
23const I2C_PMU_EN_I2C_RTC_DREG_SLP_LSB: u8 = 2;
24
25const I2C_PMU_EN_I2C_DIG_DREG_SLP: u8 = 8;
26const I2C_PMU_EN_I2C_DIG_DREG_SLP_MSB: u8 = 3;
27const I2C_PMU_EN_I2C_DIG_DREG_SLP_LSB: u8 = 3;
28
29const I2C_PMU_OR_XPD_RTC_REG: u8 = 8;
30const I2C_PMU_OR_XPD_RTC_REG_MSB: u8 = 4;
31const I2C_PMU_OR_XPD_RTC_REG_LSB: u8 = 4;
32
33const I2C_PMU_OR_XPD_DIG_REG: u8 = 8;
34const I2C_PMU_OR_XPD_DIG_REG_MSB: u8 = 5;
35const I2C_PMU_OR_XPD_DIG_REG_LSB: u8 = 5;
36
37const I2C_PMU_OR_XPD_TRX: u8 = 15;
38const I2C_PMU_OR_XPD_TRX_MSB: u8 = 2;
39const I2C_PMU_OR_XPD_TRX_LSB: u8 = 2;
40
41pub(crate) fn init() {
42    // * No peripheral reg i2c power up required on the target */
43    unsafe {
44        regi2c_write_mask(
45            I2C_PMU,
46            I2C_PMU_HOSTID,
47            I2C_PMU_EN_I2C_RTC_DREG,
48            I2C_PMU_EN_I2C_RTC_DREG_MSB,
49            I2C_PMU_EN_I2C_RTC_DREG_LSB,
50            0,
51        );
52        regi2c_write_mask(
53            I2C_PMU,
54            I2C_PMU_HOSTID,
55            I2C_PMU_EN_I2C_DIG_DREG,
56            I2C_PMU_EN_I2C_DIG_DREG_MSB,
57            I2C_PMU_EN_I2C_DIG_DREG_LSB,
58            0,
59        );
60        regi2c_write_mask(
61            I2C_PMU,
62            I2C_PMU_HOSTID,
63            I2C_PMU_EN_I2C_RTC_DREG_SLP,
64            I2C_PMU_EN_I2C_RTC_DREG_SLP_MSB,
65            I2C_PMU_EN_I2C_RTC_DREG_SLP_LSB,
66            0,
67        );
68        regi2c_write_mask(
69            I2C_PMU,
70            I2C_PMU_HOSTID,
71            I2C_PMU_EN_I2C_DIG_DREG_SLP,
72            I2C_PMU_EN_I2C_DIG_DREG_SLP_MSB,
73            I2C_PMU_EN_I2C_DIG_DREG_SLP_LSB,
74            0,
75        );
76        regi2c_write_mask(
77            I2C_PMU,
78            I2C_PMU_HOSTID,
79            I2C_PMU_OR_XPD_RTC_REG,
80            I2C_PMU_OR_XPD_RTC_REG_MSB,
81            I2C_PMU_OR_XPD_RTC_REG_LSB,
82            0,
83        );
84        regi2c_write_mask(
85            I2C_PMU,
86            I2C_PMU_HOSTID,
87            I2C_PMU_OR_XPD_DIG_REG,
88            I2C_PMU_OR_XPD_DIG_REG_MSB,
89            I2C_PMU_OR_XPD_DIG_REG_LSB,
90            0,
91        );
92        regi2c_write_mask(
93            I2C_PMU,
94            I2C_PMU_HOSTID,
95            I2C_PMU_OR_XPD_TRX,
96            I2C_PMU_OR_XPD_TRX_MSB,
97            I2C_PMU_OR_XPD_TRX_LSB,
98            0,
99        );
100
101        let pmu = PMU::regs();
102
103        pmu.power_pd_top_cntl().write(|w| w.bits(0));
104        pmu.power_pd_hpaon_cntl().write(|w| w.bits(0));
105        pmu.power_pd_hpcpu_cntl().write(|w| w.bits(0));
106        pmu.power_pd_hpperi_reserve().write(|w| w.bits(0));
107        pmu.power_pd_hpwifi_cntl().write(|w| w.bits(0));
108        pmu.power_pd_lpperi_cntl().write(|w| w.bits(0));
109
110        pmu.hp_active_hp_regulator0()
111            .modify(|_, w| w.hp_active_hp_regulator_dbias().bits(25));
112        pmu.hp_sleep_lp_regulator0()
113            .modify(|_, w| w.hp_sleep_lp_regulator_dbias().bits(26));
114
115        pmu.slp_wakeup_cntl5()
116            .modify(|_, w| w.lp_ana_wait_target().bits(15));
117        pmu.slp_wakeup_cntl7()
118            .modify(|_, w| w.ana_wait_target().bits(1700));
119    }
120}
121
122pub(crate) fn configure_clock() {
123    assert!(matches!(RtcClock::xtal_freq(), XtalClock::_32M));
124
125    RtcClock::set_fast_freq(RtcFastClock::RtcFastClockRcFast);
126
127    let cal_val = loop {
128        RtcClock::set_slow_freq(RtcSlowClock::RtcSlowClockRcSlow);
129
130        let res = RtcClock::calibrate(RtcCalSel::RtcCalRtcMux, 1024);
131        if res != 0 {
132            break res;
133        }
134    };
135
136    LP_AON::regs()
137        .store1()
138        .modify(|_, w| unsafe { w.bits(cal_val) });
139}
140
141// Terminology:
142//
143// CPU Reset:    Reset CPU core only, once reset done, CPU will execute from
144//               reset vector
145// Core Reset:   Reset the whole digital system except RTC sub-system
146// System Reset: Reset the whole digital system, including RTC sub-system
147// Chip Reset:   Reset the whole chip, including the analog part
148
149/// SOC Reset Reason.
150#[derive(Debug, Clone, Copy, PartialEq, Eq, FromRepr)]
151pub enum SocResetReason {
152    /// Power on reset
153    ///
154    /// In ESP-IDF this value (0x01) can *also* be `ChipBrownOut` or
155    /// `ChipSuperWdt`, however that is not really compatible with Rust-style
156    /// enums.
157    ChipPowerOn   = 0x01,
158    /// Software resets the digital core by RTC_CNTL_SW_SYS_RST
159    CoreSw        = 0x03,
160    /// Deep sleep reset the digital core
161    CoreDeepSleep = 0x05,
162    /// Main watch dog 0 resets digital core
163    CoreMwdt0     = 0x07,
164    /// Main watch dog 1 resets digital core
165    CoreMwdt1     = 0x08,
166    /// RTC watch dog resets digital core
167    CoreRtcWdt    = 0x09,
168    /// Main watch dog 0 resets CPU 0
169    Cpu0Mwdt0     = 0x0B,
170    /// Software resets CPU 0 by RTC_CNTL_SW_PROCPU_RST
171    Cpu0Sw        = 0x0C,
172    /// RTC watch dog resets CPU 0
173    Cpu0RtcWdt    = 0x0D,
174    /// VDD voltage is not stable and resets the digital core
175    SysBrownOut   = 0x0F,
176    /// RTC watch dog resets digital core and rtc module
177    SysRtcWdt     = 0x10,
178    /// Main watch dog 1 resets CPU 0
179    Cpu0Mwdt1     = 0x11,
180    /// Super watch dog resets the digital core and rtc module
181    SysSuperWdt   = 0x12,
182    /// Glitch on clock resets the digital core and rtc module
183    SysClkGlitch  = 0x13,
184    /// eFuse CRC error resets the digital core
185    CoreEfuseCrc  = 0x14,
186    /// USB UART resets the digital core
187    CoreUsbUart   = 0x15,
188    /// USB JTAG resets the digital core
189    CoreUsbJtag   = 0x16,
190    /// Glitch on power resets the digital core
191    CorePwrGlitch = 0x17,
192}
193
194/// RTC SLOW_CLK frequency values
195#[derive(Debug, Clone, Copy)]
196pub(crate) enum RtcFastClock {
197    /// Select RC_FAST_CLK as RTC_FAST_CLK source
198    RtcFastClockRcFast = 0,
199    #[allow(dead_code)]
200    /// Select XTAL_D2_CLK as RTC_FAST_CLK source
201    RtcFastClockXtalD2 = 1,
202}
203
204impl Clock for RtcFastClock {
205    fn frequency(&self) -> Rate {
206        match self {
207            RtcFastClock::RtcFastClockXtalD2 => Rate::from_hz(16_000_000),
208            RtcFastClock::RtcFastClockRcFast => Rate::from_hz(8_000_000),
209        }
210    }
211}
212
213/// RTC SLOW_CLK frequency values
214#[allow(clippy::enum_variant_names)]
215#[derive(Debug, Clone, Copy)]
216#[non_exhaustive]
217pub enum RtcSlowClock {
218    /// Select RC_SLOW_CLK as RTC_SLOW_CLK source
219    RtcSlowClockRcSlow  = 0,
220    /// Select XTAL32K_CLK as RTC_SLOW_CLK source
221    RtcSlowClock32kXtal = 1,
222    /// Select RC32K_CLK as RTC_SLOW_CLK source
223    RtcSlowClock32kRc   = 2,
224    /// Select OSC_SLOW_CLK (external slow clock) as RTC_SLOW_CLK source
225    RtcSlowOscSlow      = 3,
226}
227
228impl Clock for RtcSlowClock {
229    fn frequency(&self) -> Rate {
230        match self {
231            RtcSlowClock::RtcSlowClockRcSlow => Rate::from_hz(150_000),
232            RtcSlowClock::RtcSlowClock32kXtal => Rate::from_hz(32_768),
233            RtcSlowClock::RtcSlowClock32kRc => Rate::from_hz(32_768),
234            RtcSlowClock::RtcSlowOscSlow => Rate::from_hz(32_768),
235        }
236    }
237}
238
239#[derive(Debug, Clone, Copy, PartialEq)]
240/// Clock source to be calibrated using rtc_clk_cal function
241pub(crate) enum RtcCalSel {
242    /// Currently selected RTC SLOW_CLK
243    RtcCalRtcMux     = -1,
244    /// Internal 150kHz RC oscillator
245    RtcCalRcSlow     = 0,
246    /// External 32kHz XTAL, as one type of 32k clock
247    RtcCal32kXtal    = 1,
248    /// Internal 32kHz RC oscillator, as one type of 32k clock
249    RtcCal32kRc      = 2,
250    /// External slow clock signal input by lp_pad_gpio0, as one type of 32k
251    /// clock
252    RtcCal32kOscSlow = 3,
253    /// Internal 20MHz RC oscillator
254    RtcCalRcFast,
255}
256
257#[derive(Clone)]
258pub(crate) enum RtcCaliClkSel {
259    CaliClkRcSlow = 0,
260    CaliClkRcFast = 1,
261    CaliClk32k    = 2,
262}
263
264/// RTC Watchdog Timer driver
265impl RtcClock {
266    /// Get main XTAL frequency.
267    /// This is the value stored in RTC register RTC_XTAL_FREQ_REG by the
268    /// bootloader, as passed to rtc_clk_init function.
269    pub fn xtal_freq() -> XtalClock {
270        match Self::read_xtal_freq_mhz() {
271            None | Some(32) => XtalClock::_32M,
272            Some(other) => XtalClock::Other(other),
273        }
274    }
275
276    fn set_fast_freq(fast_freq: RtcFastClock) {
277        // components/hal/esp32s2/include/hal/clk_tree_ll.h
278        unsafe {
279            let lp_clkrst = LPWR::regs();
280            lp_clkrst.lp_clk_conf().modify(|_, w| {
281                w.fast_clk_sel().bits(match fast_freq {
282                    RtcFastClock::RtcFastClockRcFast => 0b00,
283                    RtcFastClock::RtcFastClockXtalD2 => 0b01,
284                })
285            });
286        }
287
288        crate::rom::ets_delay_us(3);
289    }
290
291    fn set_slow_freq(slow_freq: RtcSlowClock) {
292        unsafe {
293            let lp_clkrst = LPWR::regs();
294
295            lp_clkrst
296                .lp_clk_conf()
297                .modify(|_, w| w.slow_clk_sel().bits(slow_freq as u8));
298            lp_clkrst.clk_to_hp().modify(|_, w| {
299                w.icg_hp_xtal32k()
300                    .bit(matches!(slow_freq, RtcSlowClock::RtcSlowClock32kXtal))
301                    .icg_hp_xtal32k()
302                    .bit(matches!(slow_freq, RtcSlowClock::RtcSlowClock32kXtal))
303            });
304        }
305    }
306
307    /// Get the RTC_SLOW_CLK source
308    pub fn slow_freq() -> RtcSlowClock {
309        let lp_clrst = LPWR::regs();
310
311        let slow_freq = lp_clrst.lp_clk_conf().read().slow_clk_sel().bits();
312        match slow_freq {
313            0 => RtcSlowClock::RtcSlowClockRcSlow,
314            1 => RtcSlowClock::RtcSlowClock32kXtal,
315            2 => RtcSlowClock::RtcSlowClock32kRc,
316            3 => RtcSlowClock::RtcSlowOscSlow,
317            _ => unreachable!(),
318        }
319    }
320
321    fn calibrate(cal_clk: RtcCalSel, slowclk_cycles: u32) -> u32 {
322        let xtal_freq = RtcClock::xtal_freq();
323        let xtal_cycles = RtcClock::calibrate_internal(cal_clk, slowclk_cycles) as u64;
324        let divider = xtal_freq.mhz() as u64 * slowclk_cycles as u64;
325        let period_64 = ((xtal_cycles << RtcClock::CAL_FRACT) + divider / 2u64 - 1u64) / divider;
326
327        (period_64 & u32::MAX as u64) as u32
328    }
329
330    /// Calibration of RTC_SLOW_CLK is performed using a special feature of
331    /// TIMG0. This feature counts the number of XTAL clock cycles within a
332    /// given number of RTC_SLOW_CLK cycles.
333    fn calibrate_internal(mut cal_clk: RtcCalSel, slowclk_cycles: u32) -> u32 {
334        const SOC_CLK_RC_FAST_FREQ_APPROX: u32 = 17_500_000;
335        const SOC_CLK_RC_SLOW_FREQ_APPROX: u32 = 136_000;
336        const SOC_CLK_XTAL32K_FREQ_APPROX: u32 = 32768;
337
338        if cal_clk == RtcCalSel::RtcCalRtcMux {
339            cal_clk = match cal_clk {
340                RtcCalSel::RtcCalRtcMux => match RtcClock::slow_freq() {
341                    RtcSlowClock::RtcSlowClock32kXtal => RtcCalSel::RtcCal32kXtal,
342                    RtcSlowClock::RtcSlowClock32kRc => RtcCalSel::RtcCal32kRc,
343                    _ => cal_clk,
344                },
345                RtcCalSel::RtcCal32kOscSlow => RtcCalSel::RtcCalRtcMux,
346                _ => cal_clk,
347            };
348        }
349
350        let lp_clkrst = LPWR::regs();
351        let pcr = PCR::regs();
352        let pmu = PMU::regs();
353
354        let clk_src = RtcClock::slow_freq();
355
356        if cal_clk == RtcCalSel::RtcCalRtcMux {
357            cal_clk = match clk_src {
358                RtcSlowClock::RtcSlowClockRcSlow => RtcCalSel::RtcCalRcSlow,
359                RtcSlowClock::RtcSlowClock32kXtal => RtcCalSel::RtcCal32kXtal,
360                RtcSlowClock::RtcSlowClock32kRc => RtcCalSel::RtcCal32kRc,
361                RtcSlowClock::RtcSlowOscSlow => RtcCalSel::RtcCal32kOscSlow,
362            };
363        }
364
365        let cali_clk_sel;
366        if cal_clk == RtcCalSel::RtcCalRtcMux {
367            cal_clk = match clk_src {
368                RtcSlowClock::RtcSlowClockRcSlow => RtcCalSel::RtcCalRcSlow,
369                RtcSlowClock::RtcSlowClock32kXtal => RtcCalSel::RtcCal32kXtal,
370                RtcSlowClock::RtcSlowClock32kRc => RtcCalSel::RtcCal32kRc,
371                RtcSlowClock::RtcSlowOscSlow => RtcCalSel::RtcCalRcSlow,
372            }
373        }
374
375        if cal_clk == RtcCalSel::RtcCalRcFast {
376            cali_clk_sel = RtcCaliClkSel::CaliClkRcFast;
377        } else if cal_clk == RtcCalSel::RtcCalRcSlow {
378            cali_clk_sel = RtcCaliClkSel::CaliClkRcSlow;
379        } else {
380            cali_clk_sel = RtcCaliClkSel::CaliClk32k;
381            match cal_clk {
382                RtcCalSel::RtcCalRtcMux | RtcCalSel::RtcCalRcSlow | RtcCalSel::RtcCalRcFast => {}
383                RtcCalSel::RtcCal32kRc => {
384                    pcr.ctrl_32k_conf()
385                        .modify(|_, w| unsafe { w.clk_32k_sel().bits(0) });
386                }
387                RtcCalSel::RtcCal32kXtal => {
388                    pcr.ctrl_32k_conf()
389                        .modify(|_, w| unsafe { w.clk_32k_sel().bits(1) });
390                }
391                RtcCalSel::RtcCal32kOscSlow => {
392                    pcr.ctrl_32k_conf()
393                        .modify(|_, w| unsafe { w.clk_32k_sel().bits(2) });
394                }
395            }
396        }
397
398        // Enable requested clock (150k is always on)
399        // Some delay is required before the time is stable
400        // Only enable if originaly was disabled
401        // If clock is already on, do nothing
402
403        let dig_32k_xtal_enabled = lp_clkrst.clk_to_hp().read().icg_hp_xtal32k().bit_is_set();
404
405        if cal_clk == RtcCalSel::RtcCal32kXtal && !dig_32k_xtal_enabled {
406            lp_clkrst
407                .clk_to_hp()
408                .modify(|_, w| w.icg_hp_xtal32k().set_bit());
409        }
410
411        // TODO: very hacky
412        // in ESP-IDF these are not called in this function but the fields are set
413        lp_clkrst
414            .clk_to_hp()
415            .modify(|_, w| w.icg_hp_xtal32k().set_bit());
416        pmu.hp_sleep_lp_ck_power()
417            .modify(|_, w| w.hp_sleep_xpd_xtal32k().set_bit());
418
419        pmu.hp_sleep_lp_ck_power()
420            .modify(|_, w| w.hp_sleep_xpd_rc32k().set_bit());
421
422        let rc_fast_enabled = pmu
423            .hp_sleep_lp_ck_power()
424            .read()
425            .hp_sleep_xpd_fosc_clk()
426            .bit_is_set();
427        let dig_rc_fast_enabled = lp_clkrst.clk_to_hp().read().icg_hp_fosc().bit_is_set();
428
429        if cal_clk == RtcCalSel::RtcCalRcFast {
430            if !rc_fast_enabled {
431                pmu.hp_sleep_lp_ck_power()
432                    .modify(|_, w| w.hp_sleep_xpd_fosc_clk().set_bit());
433                crate::rom::ets_delay_us(50);
434            }
435
436            if !dig_rc_fast_enabled {
437                lp_clkrst
438                    .clk_to_hp()
439                    .modify(|_, w| w.icg_hp_fosc().set_bit());
440                crate::rom::ets_delay_us(5);
441            }
442        }
443
444        let rc32k_enabled = pmu
445            .hp_sleep_lp_ck_power()
446            .read()
447            .hp_sleep_xpd_rc32k()
448            .bit_is_set();
449        let dig_rc32k_enabled = lp_clkrst.clk_to_hp().read().icg_hp_osc32k().bit_is_set();
450
451        if cal_clk == RtcCalSel::RtcCal32kRc {
452            if !rc32k_enabled {
453                pmu.hp_sleep_lp_ck_power()
454                    .modify(|_, w| w.hp_sleep_xpd_rc32k().set_bit());
455                crate::rom::ets_delay_us(300);
456            }
457
458            if !dig_rc32k_enabled {
459                lp_clkrst
460                    .clk_to_hp()
461                    .modify(|_, w| w.icg_hp_osc32k().set_bit());
462            }
463        }
464
465        // Check if there is already running calibration process
466        // TODO: &mut TIMG0 for calibration
467        let timg0 = TIMG0::regs();
468
469        if timg0
470            .rtccalicfg()
471            .read()
472            .rtc_cali_start_cycling()
473            .bit_is_set()
474        {
475            timg0
476                .rtccalicfg2()
477                .modify(|_, w| unsafe { w.rtc_cali_timeout_thres().bits(1) });
478
479            // Set small timeout threshold to accelerate the generation of timeot
480            // Internal circuit will be reset when timeout occurs and will not affect the
481            // next calibration
482            while !timg0.rtccalicfg().read().rtc_cali_rdy().bit_is_set()
483                && !timg0.rtccalicfg2().read().rtc_cali_timeout().bit_is_set()
484            {}
485        }
486
487        // Prepare calibration
488        timg0
489            .rtccalicfg()
490            .modify(|_, w| unsafe { w.rtc_cali_clk_sel().bits(cali_clk_sel.clone() as u8) });
491        timg0
492            .rtccalicfg()
493            .modify(|_, w| w.rtc_cali_start_cycling().clear_bit());
494        timg0
495            .rtccalicfg()
496            .modify(|_, w| unsafe { w.rtc_cali_max().bits(slowclk_cycles as u16) });
497
498        let expected_freq = match cali_clk_sel {
499            RtcCaliClkSel::CaliClk32k => {
500                timg0.rtccalicfg2().modify(|_, w| unsafe {
501                    w.rtc_cali_timeout_thres().bits(slowclk_cycles << 12)
502                });
503                SOC_CLK_XTAL32K_FREQ_APPROX
504            }
505            RtcCaliClkSel::CaliClkRcFast => {
506                timg0
507                    .rtccalicfg2()
508                    .modify(|_, w| unsafe { w.rtc_cali_timeout_thres().bits(0x01FFFFFF) });
509                SOC_CLK_RC_FAST_FREQ_APPROX
510            }
511            _ => {
512                timg0.rtccalicfg2().modify(|_, w| unsafe {
513                    w.rtc_cali_timeout_thres().bits(slowclk_cycles << 10)
514                });
515                SOC_CLK_RC_SLOW_FREQ_APPROX
516            }
517        };
518
519        let us_time_estimate = (Rate::from_mhz(slowclk_cycles) / expected_freq).as_hz();
520
521        // Start calibration
522        timg0
523            .rtccalicfg()
524            .modify(|_, w| w.rtc_cali_start().clear_bit());
525        timg0
526            .rtccalicfg()
527            .modify(|_, w| w.rtc_cali_start().set_bit());
528
529        // Wait for calibration to finish up to another us_time_estimate
530        crate::rom::ets_delay_us(us_time_estimate);
531
532        let cal_val = loop {
533            if timg0.rtccalicfg().read().rtc_cali_rdy().bit_is_set() {
534                break timg0.rtccalicfg1().read().rtc_cali_value().bits();
535            }
536
537            if timg0.rtccalicfg2().read().rtc_cali_timeout().bit_is_set() {
538                // Timed out waiting for calibration
539                break 0;
540            }
541        };
542
543        timg0
544            .rtccalicfg()
545            .modify(|_, w| w.rtc_cali_start().clear_bit());
546
547        if cal_clk == RtcCalSel::RtcCal32kXtal && !dig_32k_xtal_enabled {
548            lp_clkrst
549                .clk_to_hp()
550                .modify(|_, w| w.icg_hp_xtal32k().clear_bit());
551        }
552
553        if cal_clk == RtcCalSel::RtcCalRcFast {
554            if rc_fast_enabled {
555                pmu.hp_sleep_lp_ck_power()
556                    .modify(|_, w| w.hp_sleep_xpd_fosc_clk().set_bit());
557                crate::rom::ets_delay_us(50);
558            }
559
560            if dig_rc_fast_enabled {
561                lp_clkrst
562                    .clk_to_hp()
563                    .modify(|_, w| w.icg_hp_fosc().set_bit());
564                crate::rom::ets_delay_us(5);
565            }
566        }
567
568        if cal_clk == RtcCalSel::RtcCal32kRc {
569            if rc32k_enabled {
570                pmu.hp_sleep_lp_ck_power()
571                    .modify(|_, w| w.hp_sleep_xpd_rc32k().set_bit());
572                crate::rom::ets_delay_us(300);
573            }
574            if dig_rc32k_enabled {
575                lp_clkrst
576                    .clk_to_hp()
577                    .modify(|_, w| w.icg_hp_osc32k().set_bit());
578            }
579        }
580
581        cal_val
582    }
583
584    pub(crate) fn cycles_to_1ms() -> u16 {
585        let period_13q19 = RtcClock::calibrate(
586            match RtcClock::slow_freq() {
587                RtcSlowClock::RtcSlowClockRcSlow => RtcCalSel::RtcCalRtcMux,
588                RtcSlowClock::RtcSlowClock32kXtal => RtcCalSel::RtcCal32kXtal,
589                RtcSlowClock::RtcSlowClock32kRc => RtcCalSel::RtcCal32kRc,
590                RtcSlowClock::RtcSlowOscSlow => RtcCalSel::RtcCal32kOscSlow,
591                // RtcSlowClock::RtcCalRcFast => RtcCalSel::RtcCalRcFast,
592            },
593            1024,
594        );
595
596        // 100_000_000 is used to get rid of `float` calculations
597        let period = (100_000_000 * period_13q19 as u64) / (1 << RtcClock::CAL_FRACT);
598
599        (100_000_000 * 1000 / period) as u16
600    }
601
602    pub(crate) fn estimate_xtal_frequency() -> u32 {
603        let timg0 = TIMG0::regs();
604        while timg0.rtccalicfg().read().rtc_cali_rdy().bit_is_clear() {}
605
606        timg0.rtccalicfg().modify(|_, w| unsafe {
607            w.rtc_cali_clk_sel()
608                .bits(0) // RTC_SLOW_CLK
609                .rtc_cali_max()
610                .bits(100)
611                .rtc_cali_start_cycling()
612                .clear_bit()
613                .rtc_cali_start()
614                .set_bit()
615        });
616
617        timg0
618            .rtccalicfg()
619            .modify(|_, w| w.rtc_cali_start().set_bit());
620
621        while timg0.rtccalicfg().read().rtc_cali_rdy().bit_is_clear() {}
622
623        (timg0.rtccalicfg1().read().rtc_cali_value().bits()
624            * (RtcSlowClock::RtcSlowClockRcSlow.frequency().as_hz() / 100))
625            / 1_000_000
626    }
627}