Skip to main content

esp_hal/soc/esp32c6/
clocks.rs

1//! Clock tree definitions and implementations for ESP32-C6.
2//!
3//! Remarks:
4//! - Enabling a clock node assumes it has first been configured. Some fixed clock nodes don't need
5//!   to be configured.
6//! - Some information may be assumed, e.g. the possibility to disable watchdog timers before clock
7//!   configuration.
8//! - Internal RC oscillators (136k RC_SLOW and 17.5M RC_FAST) are not calibrated here, this system
9//!   can only give a rough estimate of their frequency. They can be calibrated separately using a
10//!   known crystal frequency.
11//! - Some of the SOC capabilities are not implemented: I2S external pad clock source, external 32k
12//!   oscillator, LP_DYN_FAST_CLK, APB_DECREASE_DIV (which seems unnecessary to model),
13//!   PCR_CPU_HS_120M_FORCE.
14#![allow(dead_code, reason = "Some of this is bound to be unused")]
15#![allow(missing_docs, reason = "Experimental")]
16
17// TODO: This is a temporary place for this, should probably be moved into clocks_ll.
18
19use crate::{
20    peripherals::{I2C_ANA_MST, LP_CLKRST, PCR, PMU, TIMG0},
21    soc::{regi2c, xtal32k},
22};
23
24define_clock_tree_types!();
25
26/// Clock configuration options.
27#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
28#[cfg_attr(feature = "defmt", derive(defmt::Format))]
29#[allow(
30    clippy::enum_variant_names,
31    reason = "MHz suffix indicates physical unit."
32)]
33#[non_exhaustive]
34pub enum CpuClock {
35    /// 80 MHz CPU clock
36    #[default]
37    _80MHz  = 80,
38
39    /// 160 MHz CPU clock
40    _160MHz = 160,
41}
42
43impl CpuClock {
44    const PRESET_80: ClockConfig = ClockConfig {
45        xtal_clk: None,
46        soc_root_clk: Some(SocRootClkConfig::Pll),
47        cpu_hs_div: Some(CpuHsDivConfig::new(CpuHsDivDivisor::_1)),
48        cpu_ls_div: None, // Unused when root clock is PLL
49        ahb_hs_div: Some(AhbHsDivConfig::new(AhbHsDivDivisor::_3)),
50        ahb_ls_div: None, // Unused when root clock is PLL
51        // Configures 80MHz MSPI clock
52        mspi_fast_hs_clk: Some(MspiFastHsClkConfig::new(MspiFastHsClkDivisor::_5)),
53        mspi_fast_ls_clk: None, // Unused when root clock is PLL
54        apb_clk: Some(ApbClkConfig::new(ApbClkDivisor::_0)),
55        ledc_sclk: Some(LedcSclkConfig::PllF80m),
56        iomux_function_clock: Some(IomuxFunctionClockConfig::PllF80m),
57        lp_fast_clk: Some(LpFastClkConfig::RcFastClk),
58        lp_slow_clk: Some(xtal32k::default_lp_slow_clk()),
59        timg_calibration_clock: None,
60    };
61    const PRESET_160: ClockConfig = ClockConfig {
62        xtal_clk: None,
63        soc_root_clk: Some(SocRootClkConfig::Pll),
64        cpu_hs_div: Some(CpuHsDivConfig::new(CpuHsDivDivisor::_0)),
65        cpu_ls_div: None, // Unused when root clock is PLL
66        ahb_hs_div: Some(AhbHsDivConfig::new(AhbHsDivDivisor::_3)),
67        ahb_ls_div: None, // Unused when root clock is PLL
68        // Configures 80MHz MSPI clock
69        mspi_fast_hs_clk: Some(MspiFastHsClkConfig::new(MspiFastHsClkDivisor::_5)),
70        mspi_fast_ls_clk: None, // Unused when root clock is PLL
71        apb_clk: Some(ApbClkConfig::new(ApbClkDivisor::_0)),
72        ledc_sclk: Some(LedcSclkConfig::PllF80m),
73        iomux_function_clock: Some(IomuxFunctionClockConfig::PllF80m),
74        lp_fast_clk: Some(LpFastClkConfig::RcFastClk),
75        lp_slow_clk: Some(xtal32k::default_lp_slow_clk()),
76        timg_calibration_clock: None,
77    };
78}
79
80impl From<CpuClock> for ClockConfig {
81    fn from(value: CpuClock) -> ClockConfig {
82        match value {
83            CpuClock::_80MHz => CpuClock::PRESET_80,
84            CpuClock::_160MHz => CpuClock::PRESET_160,
85        }
86    }
87}
88
89impl Default for ClockConfig {
90    fn default() -> Self {
91        Self::from(CpuClock::default())
92    }
93}
94
95impl ClockConfig {
96    pub(crate) fn try_get_preset(self) -> Option<CpuClock> {
97        match self {
98            v if v == CpuClock::PRESET_80 => Some(CpuClock::_80MHz),
99            v if v == CpuClock::PRESET_160 => Some(CpuClock::_160MHz),
100            _ => None,
101        }
102    }
103
104    pub(crate) fn configure(mut self, clocks: &mut ClockTree) {
105        if self.xtal_clk.is_none() {
106            self.xtal_clk = Some(XtalClkConfig::_40);
107        }
108
109        // On ESP32C6, MSPI source clock's default HS divider leads to 120MHz, which is unusable
110        // before calibration. Therefore, before switching SOC_ROOT_CLK to HS, we need to set
111        // MSPI source clock HS divider to make it run at 80MHz after the switch.
112        // PLL = 480MHz, so divider is 6.
113        configure_mspi_fast_hs_clk(clocks, MspiFastHsClkConfig::new(MspiFastHsClkDivisor::_5));
114
115        self.apply(clocks);
116    }
117}
118
119// XTAL_CLK
120
121fn configure_xtal_clk_impl(
122    _clocks: &mut ClockTree,
123    _old_config: Option<XtalClkConfig>,
124    _config: XtalClkConfig,
125) {
126    // The stored configuration affects PLL settings instead.
127}
128
129// PLL_CLK
130
131fn enable_pll_clk_impl(_clocks: &mut ClockTree, en: bool) {
132    if en {
133        // TODO: these are WT fields, PAC should be fixed accordingly
134        PMU::regs().imm_hp_ck_power().modify(|_, w| {
135            w.tie_high_xpd_bb_i2c().set_bit();
136            w.tie_high_xpd_bbpll().set_bit();
137            w.tie_high_xpd_bbpll_i2c().set_bit()
138        });
139        PMU::regs()
140            .imm_hp_ck_power()
141            .modify(|_, w| w.tie_high_global_bbpll_icg().set_bit());
142    } else {
143        PMU::regs()
144            .imm_hp_ck_power()
145            .modify(|_, w| w.tie_low_global_bbpll_icg().set_bit());
146        PMU::regs().imm_hp_ck_power().modify(|_, w| {
147            w.tie_low_xpd_bb_i2c().set_bit();
148            w.tie_low_xpd_bbpll().set_bit();
149            w.tie_low_xpd_bbpll_i2c().set_bit()
150        });
151
152        return;
153    }
154
155    // BBPLL CALIBRATION START
156    I2C_ANA_MST::regs().ana_conf0().modify(|_, w| {
157        w.bbpll_stop_force_high().clear_bit();
158        w.bbpll_stop_force_low().set_bit()
159    });
160
161    const DIV_REF: u8 = 0; // Do not divide reference clock
162    const DCHGP: u8 = 5;
163    const DCUR: u8 = 3;
164
165    const I2C_BBPLL_OC_DCHGP_LSB: u32 = 4;
166    const I2C_BBPLL_OC_DHREF_SEL_LSB: u32 = 4;
167    const I2C_BBPLL_OC_DLREF_SEL_LSB: u32 = 6;
168
169    const I2C_BBPLL_LREF: u8 = (DCHGP << I2C_BBPLL_OC_DCHGP_LSB) | DIV_REF;
170    const I2C_BBPLL_DCUR: u8 =
171        (1 << I2C_BBPLL_OC_DLREF_SEL_LSB) | (3 << I2C_BBPLL_OC_DHREF_SEL_LSB) | DCUR;
172
173    regi2c::I2C_BBPLL_OC_REF.write_reg(I2C_BBPLL_LREF);
174    regi2c::I2C_BBPLL_OC_DIV_REG.write_reg(8); // multiply 40MHz XTAL by 8+4
175    regi2c::I2C_BBPLL_OC_DR1.write_field(0);
176    regi2c::I2C_BBPLL_OC_DR3.write_field(0);
177    regi2c::I2C_BBPLL_REG6.write_reg(I2C_BBPLL_DCUR);
178    regi2c::I2C_BBPLL_OC_VCO_DBIAS.write_field(2);
179
180    // WAIT CALIBRATION DONE
181    while I2C_ANA_MST::regs()
182        .ana_conf0()
183        .read()
184        .cal_done()
185        .bit_is_clear()
186    {}
187
188    // workaround bbpll calibration might stop early
189    crate::rom::ets_delay_us(10);
190
191    // BBPLL CALIBRATION STOP
192    I2C_ANA_MST::regs().ana_conf0().modify(|_, w| {
193        w.bbpll_stop_force_high().set_bit();
194        w.bbpll_stop_force_low().clear_bit()
195    });
196}
197
198// RC_FAST_CLK
199
200fn enable_rc_fast_clk_impl(_clocks: &mut ClockTree, en: bool) {
201    PMU::regs()
202        .hp_sleep_lp_ck_power()
203        .modify(|_, w| w.hp_sleep_xpd_fosc_clk().bit(en));
204    // TODO: Should the digital clock gate be a different clock node?
205    LP_CLKRST::regs()
206        .clk_to_hp()
207        .modify(|_, w| w.icg_hp_fosc().bit(en));
208    crate::rom::ets_delay_us(5);
209}
210
211// XTAL32K_CLK
212
213#[cfg(use_xtal32k)]
214fn enable_xtal32k_clk_impl(_clocks: &mut ClockTree, en: bool) {
215    LP_CLKRST::regs().xtal32k().write(|w| unsafe {
216        w.dac_xtal32k().bits(3);
217        w.dres_xtal32k().bits(3);
218        w.dgm_xtal32k().bits(3);
219        w.dbuf_xtal32k().bit(true)
220    });
221
222    PMU::regs()
223        .hp_sleep_lp_ck_power()
224        .modify(|_, w| w.hp_sleep_xpd_xtal32k().bit(en));
225
226    // Enable for digital part
227    // TODO: Should the digital clock gate be a different clock node?
228    LP_CLKRST::regs()
229        .clk_to_hp()
230        .modify(|_, w| w.icg_hp_xtal32k().bit(en));
231}
232
233// OSC_SLOW_CLK
234
235fn enable_osc_slow_clk_impl(_clocks: &mut ClockTree, _en: bool) {
236    // TODO:
237    // gpio_ll_input_enable(&GPIO, SOC_EXT_OSC_SLOW_GPIO_NUM);
238    // REG_SET_BIT(LP_AON_GPIO_HOLD0_REG, BIT(SOC_EXT_OSC_SLOW_GPIO_NUM));
239    todo!();
240
241    // No need to configure anything else for OSC_SLOW_CLK
242}
243
244// RC_SLOW_CLK
245
246fn enable_rc_slow_clk_impl(_clocks: &mut ClockTree, en: bool) {
247    if en {
248        // SCK_DCAP value controls tuning of 136k clock. The higher the value of DCAP, the lower the
249        // frequency. There is no separate enable bit, just make sure the calibration value is set.
250        const RTC_CNTL_SCK_DCAP_DEFAULT: u8 = 128;
251        crate::soc::regi2c::I2C_DIG_REG_SCK_DCAP.write_reg(RTC_CNTL_SCK_DCAP_DEFAULT);
252    }
253
254    PMU::regs()
255        .hp_sleep_lp_ck_power()
256        .modify(|_, w| w.hp_sleep_xpd_rc32k().bit(en));
257
258    // Enable for digital part
259    LP_CLKRST::regs()
260        .clk_to_hp()
261        .modify(|_, w| w.icg_hp_osc32k().bit(en));
262}
263
264// HP_ROOT_CLK
265
266fn enable_hp_root_clk_impl(_clocks: &mut ClockTree, _en: bool) {
267    // Nothing to do, managed by hardware.
268}
269
270fn configure_hp_root_clk_impl(
271    _clocks: &mut ClockTree,
272    _old_config: Option<HpRootClkConfig>,
273    _new_config: HpRootClkConfig,
274) {
275    // Nothing to do, managed by hardware.
276}
277
278// CPU_CLK
279
280fn configure_cpu_clk_impl(
281    _clocks: &mut ClockTree,
282    _old_config: Option<CpuClkConfig>,
283    _new_config: CpuClkConfig,
284) {
285    // Nothing to do, automatically managed by hardware.
286}
287
288// AHB_CLK
289
290fn configure_ahb_clk_impl(
291    _clocks: &mut ClockTree,
292    _old_config: Option<AhbClkConfig>,
293    _new_config: AhbClkConfig,
294) {
295    // Nothing to do, automatically managed by hardware.
296}
297
298// MSPI_FAST_CLK
299
300fn enable_mspi_fast_clk_impl(_clocks: &mut ClockTree, _en: bool) {
301    // Nothing to do.
302}
303
304fn configure_mspi_fast_clk_impl(
305    _clocks: &mut ClockTree,
306    _old_config: Option<MspiFastClkConfig>,
307    _new_config: MspiFastClkConfig,
308) {
309    // Nothing to do, automatically managed by hardware.
310}
311
312// SOC_ROOT_CLK
313
314fn enable_soc_root_clk_impl(_clocks: &mut ClockTree, _en: bool) {
315    // Nothing to do.
316}
317
318fn configure_soc_root_clk_impl(
319    _clocks: &mut ClockTree,
320    _old_config: Option<SocRootClkConfig>,
321    new_config: SocRootClkConfig,
322) {
323    PCR::regs().sysclk_conf().modify(|_, w| unsafe {
324        w.soc_clk_sel().bits(match new_config {
325            SocRootClkConfig::Xtal => 0,
326            SocRootClkConfig::Pll => 1,
327            SocRootClkConfig::RcFast => 2,
328        })
329    });
330}
331
332// CPU_HS_DIV
333
334fn enable_cpu_hs_div_impl(_clocks: &mut ClockTree, _en: bool) {
335    // Nothing to do.
336}
337
338fn configure_cpu_hs_div_impl(
339    _clocks: &mut ClockTree,
340    _old_config: Option<CpuHsDivConfig>,
341    new_config: CpuHsDivConfig,
342) {
343    PCR::regs()
344        .cpu_freq_conf()
345        .modify(|_, w| unsafe { w.cpu_hs_div_num().bits(new_config.divisor() as u8) });
346}
347
348// CPU_LS_DIV
349
350fn enable_cpu_ls_div_impl(_clocks: &mut ClockTree, _en: bool) {
351    // Nothing to do.
352}
353
354fn configure_cpu_ls_div_impl(
355    _clocks: &mut ClockTree,
356    _old_config: Option<CpuLsDivConfig>,
357    new_config: CpuLsDivConfig,
358) {
359    PCR::regs()
360        .cpu_freq_conf()
361        .modify(|_, w| unsafe { w.cpu_ls_div_num().bits(new_config.divisor() as u8) });
362}
363
364// AHB_HS_DIV
365
366fn enable_ahb_hs_div_impl(_clocks: &mut ClockTree, _en: bool) {
367    // Nothing to do.
368}
369
370fn configure_ahb_hs_div_impl(
371    _clocks: &mut ClockTree,
372    _old_config: Option<AhbHsDivConfig>,
373    new_config: AhbHsDivConfig,
374) {
375    PCR::regs()
376        .ahb_freq_conf()
377        .modify(|_, w| unsafe { w.ahb_hs_div_num().bits(new_config.divisor() as u8) });
378}
379
380// AHB_LS_DIV
381
382fn enable_ahb_ls_div_impl(_clocks: &mut ClockTree, _en: bool) {
383    // Nothing to do.
384}
385
386fn configure_ahb_ls_div_impl(
387    _clocks: &mut ClockTree,
388    _old_config: Option<AhbLsDivConfig>,
389    new_config: AhbLsDivConfig,
390) {
391    PCR::regs()
392        .ahb_freq_conf()
393        .modify(|_, w| unsafe { w.ahb_ls_div_num().bits(new_config.divisor() as u8) });
394}
395
396// APB_CLK
397
398fn enable_apb_clk_impl(_clocks: &mut ClockTree, _en: bool) {
399    // Nothing to do.
400}
401
402fn configure_apb_clk_impl(
403    _clocks: &mut ClockTree,
404    _old_config: Option<ApbClkConfig>,
405    new_config: ApbClkConfig,
406) {
407    PCR::regs()
408        .apb_freq_conf()
409        .modify(|_, w| unsafe { w.apb_div_num().bits(new_config.divisor() as u8) });
410}
411
412// MSPI_FAST_HS_CLK
413
414fn enable_mspi_fast_hs_clk_impl(_clocks: &mut ClockTree, _en: bool) {
415    // Nothing to do, automatically managed by hardware.
416}
417
418fn configure_mspi_fast_hs_clk_impl(
419    _clocks: &mut ClockTree,
420    _old_config: Option<MspiFastHsClkConfig>,
421    new_config: MspiFastHsClkConfig,
422) {
423    PCR::regs()
424        .mspi_clk_conf()
425        .modify(|_, w| unsafe { w.mspi_fast_hs_div_num().bits(new_config.divisor() as u8) });
426}
427
428// MSPI_FAST_LS_CLK
429
430fn enable_mspi_fast_ls_clk_impl(_clocks: &mut ClockTree, _en: bool) {
431    // Nothing to do, automatically managed by hardware.
432}
433
434fn configure_mspi_fast_ls_clk_impl(
435    _clocks: &mut ClockTree,
436    _old_config: Option<MspiFastLsClkConfig>,
437    new_config: MspiFastLsClkConfig,
438) {
439    PCR::regs()
440        .mspi_clk_conf()
441        .modify(|_, w| unsafe { w.mspi_fast_ls_div_num().bits(new_config.divisor() as u8) });
442}
443
444// PLL_F48M
445
446fn enable_pll_f48m_impl(_clocks: &mut ClockTree, _en: bool) {
447    // Nothing to do.
448}
449
450// PLL_F80M
451
452fn enable_pll_f80m_impl(_clocks: &mut ClockTree, _en: bool) {
453    // Nothing to do.
454}
455
456// PLL_F160M
457
458fn enable_pll_f160m_impl(_clocks: &mut ClockTree, _en: bool) {
459    // Nothing to do.
460}
461
462// PLL_F240M
463
464fn enable_pll_f240m_impl(_clocks: &mut ClockTree, _en: bool) {
465    // Nothing to do.
466}
467
468fn configure_iomux_function_clock_impl(
469    _clocks: &mut ClockTree,
470    _old_config: Option<IomuxFunctionClockConfig>,
471    new_config: IomuxFunctionClockConfig,
472) {
473    PCR::regs().iomux_clk_conf().modify(|_, w| unsafe {
474        w.iomux_func_clk_sel().bits(match new_config {
475            IomuxFunctionClockConfig::PllF80m => 1,
476            IomuxFunctionClockConfig::RcFastClk => 2,
477            IomuxFunctionClockConfig::XtalClk => 3,
478        });
479        w.iomux_func_clk_en().set_bit()
480    });
481}
482
483// LEDC_SCLK
484
485fn enable_ledc_sclk_impl(_clocks: &mut ClockTree, en: bool) {
486    PCR::regs()
487        .ledc_sclk_conf()
488        .modify(|_, w| w.ledc_sclk_en().bit(en));
489}
490
491fn configure_ledc_sclk_impl(
492    _clocks: &mut ClockTree,
493    _old_config: Option<LedcSclkConfig>,
494    new_config: LedcSclkConfig,
495) {
496    PCR::regs().ledc_sclk_conf().modify(|_, w| unsafe {
497        w.ledc_sclk_sel().bits(match new_config {
498            LedcSclkConfig::PllF80m => 1,
499            LedcSclkConfig::RcFastClk => 2,
500            LedcSclkConfig::XtalClk => 3,
501        })
502    });
503}
504
505// XTAL_D2_CLK
506
507fn enable_xtal_d2_clk_impl(_clocks: &mut ClockTree, _en: bool) {
508    // Nothing to do, the divider is always on.
509}
510
511// LP_FAST_CLK
512
513fn enable_lp_fast_clk_impl(_clocks: &mut ClockTree, _en: bool) {
514    // Nothing to do.
515}
516
517fn configure_lp_fast_clk_impl(
518    _clocks: &mut ClockTree,
519    _old_config: Option<LpFastClkConfig>,
520    new_config: LpFastClkConfig,
521) {
522    LP_CLKRST::regs().lp_clk_conf().modify(|_, w| {
523        w.fast_clk_sel().bit(match new_config {
524            LpFastClkConfig::RcFastClk => false,
525            LpFastClkConfig::XtalD2Clk => true,
526        })
527    });
528}
529
530// LP_SLOW_CLK
531
532fn enable_lp_slow_clk_impl(_clocks: &mut ClockTree, _en: bool) {
533    // Nothing to do.
534}
535
536fn configure_lp_slow_clk_impl(
537    _clocks: &mut ClockTree,
538    _old_config: Option<LpSlowClkConfig>,
539    new_config: LpSlowClkConfig,
540) {
541    LP_CLKRST::regs().lp_clk_conf().modify(|_, w| unsafe {
542        w.slow_clk_sel().bits(match new_config {
543            #[cfg(use_xtal32k)]
544            LpSlowClkConfig::Xtal32k => 1,
545            LpSlowClkConfig::RcSlow => 0,
546            LpSlowClkConfig::OscSlow => 2,
547        })
548    });
549}
550
551// TIMG_CALIBRATION_CLOCK
552
553fn enable_timg_calibration_clock_impl(_clocks: &mut ClockTree, _en: bool) {
554    // Nothing to do, calibration clocks can only be selected. They are gated by the CALI_START
555    // bit, which is managed by the calibration process.
556}
557
558fn configure_timg_calibration_clock_impl(
559    _clocks: &mut ClockTree,
560    _old_config: Option<TimgCalibrationClockConfig>,
561    new_config: TimgCalibrationClockConfig,
562) {
563    TIMG0::regs().rtccalicfg().modify(|_, w| unsafe {
564        w.rtc_cali_clk_sel().bits(match new_config {
565            TimgCalibrationClockConfig::RcSlowClk => 0,
566            TimgCalibrationClockConfig::RcFastDivClk => 1,
567            #[cfg(use_xtal32k)]
568            TimgCalibrationClockConfig::Xtal32kClk => 2,
569        })
570    });
571}
572
573impl McpwmInstance {
574    // MCPWM_FUNCTION_CLOCK
575
576    fn enable_function_clock_impl(self, _clocks: &mut ClockTree, en: bool) {
577        PCR::regs()
578            .pwm_clk_conf()
579            .modify(|_, w| w.pwm_clkm_en().bit(en));
580    }
581
582    fn configure_function_clock_impl(
583        self,
584        _clocks: &mut ClockTree,
585        _old_config: Option<McpwmFunctionClockConfig>,
586        new_config: McpwmFunctionClockConfig,
587    ) {
588        PCR::regs().pwm_clk_conf().modify(|_, w| unsafe {
589            w.pwm_clkm_sel().bits(match new_config {
590                McpwmFunctionClockConfig::PllF160m => 1,
591                McpwmFunctionClockConfig::XtalClk => 2,
592                McpwmFunctionClockConfig::RcFastClk => 3,
593            })
594        });
595    }
596}
597
598impl ParlIoInstance {
599    // PARL_IO_RX_CLOCK
600
601    fn enable_rx_clock_impl(self, _clocks: &mut ClockTree, en: bool) {
602        PCR::regs()
603            .parl_clk_rx_conf()
604            .modify(|_, w| w.parl_clk_rx_en().bit(en));
605    }
606
607    fn configure_rx_clock_impl(
608        self,
609        _clocks: &mut ClockTree,
610        _old_config: Option<ParlIoRxClockConfig>,
611        new_config: ParlIoRxClockConfig,
612    ) {
613        PCR::regs().parl_clk_rx_conf().modify(|_, w| unsafe {
614            w.parl_clk_rx_sel().bits(match new_config {
615                ParlIoRxClockConfig::XtalClk => 0,
616                ParlIoRxClockConfig::RcFastClk => 2,
617                ParlIoRxClockConfig::PllF240m => 1,
618            })
619        });
620    }
621
622    // PARL_IO_TX_CLOCK
623
624    fn enable_tx_clock_impl(self, _clocks: &mut ClockTree, en: bool) {
625        PCR::regs()
626            .parl_clk_tx_conf()
627            .modify(|_, w| w.parl_clk_tx_en().bit(en));
628    }
629
630    fn configure_tx_clock_impl(
631        self,
632        _clocks: &mut ClockTree,
633        _old_config: Option<ParlIoTxClockConfig>,
634        new_config: ParlIoTxClockConfig,
635    ) {
636        PCR::regs().parl_clk_tx_conf().modify(|_, w| unsafe {
637            w.parl_clk_tx_sel().bits(match new_config {
638                ParlIoTxClockConfig::XtalClk => 0,
639                ParlIoTxClockConfig::RcFastClk => 2,
640                ParlIoTxClockConfig::PllF240m => 1,
641            })
642        });
643    }
644}
645
646impl SdmInstance {
647    // SDM_FUNCTION_CLOCK
648
649    fn enable_function_clock_impl(self, _clocks: &mut ClockTree, en: bool) {
650        crate::peripherals::GPIO_SD::regs()
651            .sigmadelta_misc()
652            .modify(|_, w| w.function_clk_en().bit(en));
653    }
654}
655impl RmtInstance {
656    // RMT_SCLK
657
658    fn enable_sclk_impl(self, _clocks: &mut ClockTree, en: bool) {
659        PCR::regs()
660            .rmt_sclk_conf()
661            .modify(|_, w| w.sclk_en().bit(en));
662    }
663
664    fn configure_sclk_impl(
665        self,
666        _clocks: &mut ClockTree,
667        _old_config: Option<RmtSclkConfig>,
668        new_config: RmtSclkConfig,
669    ) {
670        PCR::regs().rmt_sclk_conf().modify(|_, w| unsafe {
671            w.sclk_sel().bits(match new_config {
672                RmtSclkConfig::PllF80m => 1,
673                RmtSclkConfig::RcFastClk => 2,
674                RmtSclkConfig::XtalClk => 3,
675            })
676        });
677    }
678}
679
680impl TimgInstance {
681    // TIMG_FUNCTION_CLOCK
682
683    fn enable_function_clock_impl(self, _clocks: &mut ClockTree, en: bool) {
684        let timg = match self {
685            TimgInstance::Timg0 => 0,
686            TimgInstance::Timg1 => 1,
687        };
688        PCR::regs()
689            .timergroup(timg)
690            .timer_clk_conf()
691            .modify(|_, w| w.timer_clk_en().bit(en));
692    }
693
694    fn configure_function_clock_impl(
695        self,
696        _clocks: &mut ClockTree,
697        _old_config: Option<TimgFunctionClockConfig>,
698        new_config: TimgFunctionClockConfig,
699    ) {
700        let timg = match self {
701            TimgInstance::Timg0 => 0,
702            TimgInstance::Timg1 => 1,
703        };
704        PCR::regs()
705            .timergroup(timg)
706            .timer_clk_conf()
707            .modify(|_, w| unsafe {
708                // TODO: add variants to PAC
709                w.timer_clk_sel().bits(match new_config {
710                    TimgFunctionClockConfig::XtalClk => 0,
711                    TimgFunctionClockConfig::RcFastClk => 2,
712                    TimgFunctionClockConfig::PllF80m => 1,
713                })
714            });
715    }
716
717    // TIMG_WDT_CLOCK
718
719    fn enable_wdt_clock_impl(self, _clocks: &mut ClockTree, en: bool) {
720        let timg = match self {
721            TimgInstance::Timg0 => 0,
722            TimgInstance::Timg1 => 1,
723        };
724        PCR::regs()
725            .timergroup(timg)
726            .wdt_clk_conf()
727            .modify(|_, w| w.wdt_clk_en().bit(en));
728    }
729
730    fn configure_wdt_clock_impl(
731        self,
732        _clocks: &mut ClockTree,
733        _old_config: Option<TimgWdtClockConfig>,
734        new_config: TimgWdtClockConfig,
735    ) {
736        let timg = match self {
737            TimgInstance::Timg0 => 0,
738            TimgInstance::Timg1 => 1,
739        };
740        PCR::regs()
741            .timergroup(timg)
742            .wdt_clk_conf()
743            .modify(|_, w| unsafe {
744                w.wdt_clk_sel().bits(match new_config {
745                    TimgWdtClockConfig::XtalClk => 0,
746                    TimgWdtClockConfig::PllF80m => 1,
747                    TimgWdtClockConfig::RcFastClk => 2,
748                })
749            });
750    }
751}