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, UART0, UART1},
21    soc::regi2c,
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        lp_fast_clk: Some(LpFastClkConfig::RcFastClk),
57        lp_slow_clk: Some(LpSlowClkConfig::RcSlow),
58        timg_calibration_clock: None,
59    };
60    const PRESET_160: ClockConfig = ClockConfig {
61        xtal_clk: None,
62        soc_root_clk: Some(SocRootClkConfig::Pll),
63        cpu_hs_div: Some(CpuHsDivConfig::new(CpuHsDivDivisor::_0)),
64        cpu_ls_div: None, // Unused when root clock is PLL
65        ahb_hs_div: Some(AhbHsDivConfig::new(AhbHsDivDivisor::_3)),
66        ahb_ls_div: None, // Unused when root clock is PLL
67        // Configures 80MHz MSPI clock
68        mspi_fast_hs_clk: Some(MspiFastHsClkConfig::new(MspiFastHsClkDivisor::_5)),
69        mspi_fast_ls_clk: None, // Unused when root clock is PLL
70        apb_clk: Some(ApbClkConfig::new(ApbClkDivisor::_0)),
71        ledc_sclk: Some(LedcSclkConfig::PllF80m),
72        lp_fast_clk: Some(LpFastClkConfig::RcFastClk),
73        lp_slow_clk: Some(LpSlowClkConfig::RcSlow),
74        timg_calibration_clock: None,
75    };
76}
77
78impl From<CpuClock> for ClockConfig {
79    fn from(value: CpuClock) -> ClockConfig {
80        match value {
81            CpuClock::_80MHz => CpuClock::PRESET_80,
82            CpuClock::_160MHz => CpuClock::PRESET_160,
83        }
84    }
85}
86
87impl Default for ClockConfig {
88    fn default() -> Self {
89        Self::from(CpuClock::default())
90    }
91}
92
93impl ClockConfig {
94    pub(crate) fn try_get_preset(self) -> Option<CpuClock> {
95        match self {
96            v if v == CpuClock::PRESET_80 => Some(CpuClock::_80MHz),
97            v if v == CpuClock::PRESET_160 => Some(CpuClock::_160MHz),
98            _ => None,
99        }
100    }
101
102    pub(crate) fn configure(mut self) {
103        if self.xtal_clk.is_none() {
104            self.xtal_clk = Some(XtalClkConfig::_40);
105        }
106
107        // On ESP32C6, MSPI source clock's default HS divider leads to 120MHz, which is unusable
108        // before calibration. Therefore, before switching SOC_ROOT_CLK to HS, we need to set
109        // MSPI source clock HS divider to make it run at 80MHz after the switch.
110        // PLL = 480MHz, so divider is 6.
111        ClockTree::with(|clocks| {
112            configure_mspi_fast_hs_clk(clocks, MspiFastHsClkConfig::new(MspiFastHsClkDivisor::_5))
113        });
114
115        self.apply();
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
213fn enable_xtal32k_clk_impl(_clocks: &mut ClockTree, en: bool) {
214    LP_CLKRST::regs().xtal32k().write(|w| unsafe {
215        w.dac_xtal32k().bits(3);
216        w.dres_xtal32k().bits(3);
217        w.dgm_xtal32k().bits(3);
218        w.dbuf_xtal32k().bit(true)
219    });
220
221    PMU::regs()
222        .hp_sleep_lp_ck_power()
223        .modify(|_, w| w.hp_sleep_xpd_xtal32k().bit(en));
224
225    // Enable for digital part
226    // TODO: Should the digital clock gate be a different clock node?
227    LP_CLKRST::regs()
228        .clk_to_hp()
229        .modify(|_, w| w.icg_hp_xtal32k().bit(en));
230}
231
232// OSC_SLOW_CLK
233
234fn enable_osc_slow_clk_impl(_clocks: &mut ClockTree, _en: bool) {
235    // TODO:
236    // gpio_ll_input_enable(&GPIO, SOC_EXT_OSC_SLOW_GPIO_NUM);
237    // REG_SET_BIT(LP_AON_GPIO_HOLD0_REG, BIT(SOC_EXT_OSC_SLOW_GPIO_NUM));
238    todo!();
239
240    // No need to configure anything else for OSC_SLOW_CLK
241}
242
243// RC_SLOW_CLK
244
245fn enable_rc_slow_clk_impl(_clocks: &mut ClockTree, en: bool) {
246    if en {
247        // SCK_DCAP value controls tuning of 136k clock. The higher the value of DCAP, the lower the
248        // frequency. There is no separate enable bit, just make sure the calibration value is set.
249        const RTC_CNTL_SCK_DCAP_DEFAULT: u8 = 128;
250        crate::soc::regi2c::I2C_DIG_REG_SCK_DCAP.write_reg(RTC_CNTL_SCK_DCAP_DEFAULT);
251    }
252
253    PMU::regs()
254        .hp_sleep_lp_ck_power()
255        .modify(|_, w| w.hp_sleep_xpd_rc32k().bit(en));
256
257    // Enable for digital part
258    LP_CLKRST::regs()
259        .clk_to_hp()
260        .modify(|_, w| w.icg_hp_osc32k().bit(en));
261}
262
263// HP_ROOT_CLK
264
265fn enable_hp_root_clk_impl(_clocks: &mut ClockTree, _en: bool) {
266    // Nothing to do, managed by hardware.
267}
268
269fn configure_hp_root_clk_impl(
270    _clocks: &mut ClockTree,
271    _old_config: Option<HpRootClkConfig>,
272    _new_config: HpRootClkConfig,
273) {
274    // Nothing to do, managed by hardware.
275}
276
277// CPU_CLK
278
279fn configure_cpu_clk_impl(
280    _clocks: &mut ClockTree,
281    _old_config: Option<CpuClkConfig>,
282    _new_config: CpuClkConfig,
283) {
284    // Nothing to do, automatically managed by hardware.
285}
286
287// AHB_CLK
288
289fn configure_ahb_clk_impl(
290    _clocks: &mut ClockTree,
291    _old_config: Option<AhbClkConfig>,
292    _new_config: AhbClkConfig,
293) {
294    // Nothing to do, automatically managed by hardware.
295}
296
297// MSPI_FAST_CLK
298
299fn enable_mspi_fast_clk_impl(_clocks: &mut ClockTree, _en: bool) {
300    // Nothing to do.
301}
302
303fn configure_mspi_fast_clk_impl(
304    _clocks: &mut ClockTree,
305    _old_config: Option<MspiFastClkConfig>,
306    _new_config: MspiFastClkConfig,
307) {
308    // Nothing to do, automatically managed by hardware.
309}
310
311// SOC_ROOT_CLK
312
313fn enable_soc_root_clk_impl(_clocks: &mut ClockTree, _en: bool) {
314    // Nothing to do.
315}
316
317fn configure_soc_root_clk_impl(
318    _clocks: &mut ClockTree,
319    _old_config: Option<SocRootClkConfig>,
320    new_config: SocRootClkConfig,
321) {
322    PCR::regs().sysclk_conf().modify(|_, w| unsafe {
323        w.soc_clk_sel().bits(match new_config {
324            SocRootClkConfig::Xtal => 0,
325            SocRootClkConfig::Pll => 1,
326            SocRootClkConfig::RcFast => 2,
327        })
328    });
329}
330
331// CPU_HS_DIV
332
333fn enable_cpu_hs_div_impl(_clocks: &mut ClockTree, _en: bool) {
334    // Nothing to do.
335}
336
337fn configure_cpu_hs_div_impl(
338    _clocks: &mut ClockTree,
339    _old_config: Option<CpuHsDivConfig>,
340    new_config: CpuHsDivConfig,
341) {
342    PCR::regs()
343        .cpu_freq_conf()
344        .modify(|_, w| unsafe { w.cpu_hs_div_num().bits(new_config.divisor() as u8) });
345}
346
347// CPU_LS_DIV
348
349fn enable_cpu_ls_div_impl(_clocks: &mut ClockTree, _en: bool) {
350    // Nothing to do.
351}
352
353fn configure_cpu_ls_div_impl(
354    _clocks: &mut ClockTree,
355    _old_config: Option<CpuLsDivConfig>,
356    new_config: CpuLsDivConfig,
357) {
358    PCR::regs()
359        .cpu_freq_conf()
360        .modify(|_, w| unsafe { w.cpu_ls_div_num().bits(new_config.divisor() as u8) });
361}
362
363// AHB_HS_DIV
364
365fn enable_ahb_hs_div_impl(_clocks: &mut ClockTree, _en: bool) {
366    // Nothing to do.
367}
368
369fn configure_ahb_hs_div_impl(
370    _clocks: &mut ClockTree,
371    _old_config: Option<AhbHsDivConfig>,
372    new_config: AhbHsDivConfig,
373) {
374    PCR::regs()
375        .ahb_freq_conf()
376        .modify(|_, w| unsafe { w.ahb_hs_div_num().bits(new_config.divisor() as u8) });
377}
378
379// AHB_LS_DIV
380
381fn enable_ahb_ls_div_impl(_clocks: &mut ClockTree, _en: bool) {
382    // Nothing to do.
383}
384
385fn configure_ahb_ls_div_impl(
386    _clocks: &mut ClockTree,
387    _old_config: Option<AhbLsDivConfig>,
388    new_config: AhbLsDivConfig,
389) {
390    PCR::regs()
391        .ahb_freq_conf()
392        .modify(|_, w| unsafe { w.ahb_ls_div_num().bits(new_config.divisor() as u8) });
393}
394
395// APB_CLK
396
397fn enable_apb_clk_impl(_clocks: &mut ClockTree, _en: bool) {
398    // Nothing to do.
399}
400
401fn configure_apb_clk_impl(
402    _clocks: &mut ClockTree,
403    _old_config: Option<ApbClkConfig>,
404    new_config: ApbClkConfig,
405) {
406    PCR::regs()
407        .apb_freq_conf()
408        .modify(|_, w| unsafe { w.apb_div_num().bits(new_config.divisor() as u8) });
409}
410
411// MSPI_FAST_HS_CLK
412
413fn enable_mspi_fast_hs_clk_impl(_clocks: &mut ClockTree, _en: bool) {
414    // Nothing to do, automatically managed by hardware.
415}
416
417fn configure_mspi_fast_hs_clk_impl(
418    _clocks: &mut ClockTree,
419    _old_config: Option<MspiFastHsClkConfig>,
420    new_config: MspiFastHsClkConfig,
421) {
422    PCR::regs()
423        .mspi_clk_conf()
424        .modify(|_, w| unsafe { w.mspi_fast_hs_div_num().bits(new_config.divisor() as u8) });
425}
426
427// MSPI_FAST_LS_CLK
428
429fn enable_mspi_fast_ls_clk_impl(_clocks: &mut ClockTree, _en: bool) {
430    // Nothing to do, automatically managed by hardware.
431}
432
433fn configure_mspi_fast_ls_clk_impl(
434    _clocks: &mut ClockTree,
435    _old_config: Option<MspiFastLsClkConfig>,
436    new_config: MspiFastLsClkConfig,
437) {
438    PCR::regs()
439        .mspi_clk_conf()
440        .modify(|_, w| unsafe { w.mspi_fast_ls_div_num().bits(new_config.divisor() as u8) });
441}
442
443// PLL_F48M
444
445fn enable_pll_f48m_impl(_clocks: &mut ClockTree, _en: bool) {
446    // Nothing to do.
447}
448
449// PLL_F80M
450
451fn enable_pll_f80m_impl(_clocks: &mut ClockTree, _en: bool) {
452    // Nothing to do.
453}
454
455// PLL_F160M
456
457fn enable_pll_f160m_impl(_clocks: &mut ClockTree, _en: bool) {
458    // Nothing to do.
459}
460
461// PLL_F240M
462
463fn enable_pll_f240m_impl(_clocks: &mut ClockTree, _en: bool) {
464    // Nothing to do.
465}
466
467// LEDC_SCLK
468
469fn enable_ledc_sclk_impl(_clocks: &mut ClockTree, en: bool) {
470    PCR::regs()
471        .ledc_sclk_conf()
472        .modify(|_, w| w.ledc_sclk_en().bit(en));
473}
474
475fn configure_ledc_sclk_impl(
476    _clocks: &mut ClockTree,
477    _old_config: Option<LedcSclkConfig>,
478    new_config: LedcSclkConfig,
479) {
480    PCR::regs().ledc_sclk_conf().modify(|_, w| unsafe {
481        w.ledc_sclk_sel().bits(match new_config {
482            LedcSclkConfig::PllF80m => 1,
483            LedcSclkConfig::RcFastClk => 2,
484            LedcSclkConfig::XtalClk => 3,
485        })
486    });
487}
488
489// XTAL_D2_CLK
490
491fn enable_xtal_d2_clk_impl(_clocks: &mut ClockTree, _en: bool) {
492    // Nothing to do, the divider is always on.
493}
494
495// LP_FAST_CLK
496
497fn enable_lp_fast_clk_impl(_clocks: &mut ClockTree, _en: bool) {
498    // Nothing to do.
499}
500
501fn configure_lp_fast_clk_impl(
502    _clocks: &mut ClockTree,
503    _old_config: Option<LpFastClkConfig>,
504    new_config: LpFastClkConfig,
505) {
506    LP_CLKRST::regs().lp_clk_conf().modify(|_, w| {
507        w.fast_clk_sel().bit(match new_config {
508            LpFastClkConfig::RcFastClk => false,
509            LpFastClkConfig::XtalD2Clk => true,
510        })
511    });
512}
513
514// LP_SLOW_CLK
515
516fn enable_lp_slow_clk_impl(_clocks: &mut ClockTree, _en: bool) {
517    // Nothing to do.
518}
519
520fn configure_lp_slow_clk_impl(
521    _clocks: &mut ClockTree,
522    _old_config: Option<LpSlowClkConfig>,
523    new_config: LpSlowClkConfig,
524) {
525    LP_CLKRST::regs().lp_clk_conf().modify(|_, w| unsafe {
526        w.slow_clk_sel().bits(match new_config {
527            LpSlowClkConfig::Xtal32k => 1,
528            LpSlowClkConfig::RcSlow => 0,
529            LpSlowClkConfig::OscSlow => 2,
530        })
531    });
532}
533
534// TIMG_CALIBRATION_CLOCK
535
536fn enable_timg_calibration_clock_impl(_clocks: &mut ClockTree, _en: bool) {
537    // Nothing to do, calibration clocks can only be selected. They are gated by the CALI_START
538    // bit, which is managed by the calibration process.
539}
540
541fn configure_timg_calibration_clock_impl(
542    _clocks: &mut ClockTree,
543    _old_config: Option<TimgCalibrationClockConfig>,
544    new_config: TimgCalibrationClockConfig,
545) {
546    TIMG0::regs().rtccalicfg().modify(|_, w| unsafe {
547        w.rtc_cali_clk_sel().bits(match new_config {
548            TimgCalibrationClockConfig::RcSlowClk => 0,
549            TimgCalibrationClockConfig::RcFastDivClk => 1,
550            TimgCalibrationClockConfig::Xtal32kClk => 2,
551        })
552    });
553}
554
555impl McpwmInstance {
556    // MCPWM_FUNCTION_CLOCK
557
558    fn enable_function_clock_impl(self, _clocks: &mut ClockTree, en: bool) {
559        PCR::regs()
560            .pwm_clk_conf()
561            .modify(|_, w| w.pwm_clkm_en().bit(en));
562    }
563
564    fn configure_function_clock_impl(
565        self,
566        _clocks: &mut ClockTree,
567        _old_config: Option<McpwmFunctionClockConfig>,
568        new_config: McpwmFunctionClockConfig,
569    ) {
570        PCR::regs().pwm_clk_conf().modify(|_, w| unsafe {
571            w.pwm_clkm_sel().bits(match new_config {
572                McpwmFunctionClockConfig::PllF160m => 1,
573                McpwmFunctionClockConfig::XtalClk => 2,
574                McpwmFunctionClockConfig::RcFastClk => 3,
575            })
576        });
577    }
578}
579
580impl ParlIoInstance {
581    // PARL_IO_RX_CLOCK
582
583    fn enable_rx_clock_impl(self, _clocks: &mut ClockTree, en: bool) {
584        PCR::regs()
585            .parl_clk_rx_conf()
586            .modify(|_, w| w.parl_clk_rx_en().bit(en));
587    }
588
589    fn configure_rx_clock_impl(
590        self,
591        _clocks: &mut ClockTree,
592        _old_config: Option<ParlIoRxClockConfig>,
593        new_config: ParlIoRxClockConfig,
594    ) {
595        PCR::regs().parl_clk_rx_conf().modify(|_, w| unsafe {
596            w.parl_clk_rx_sel().bits(match new_config {
597                ParlIoRxClockConfig::XtalClk => 0,
598                ParlIoRxClockConfig::RcFastClk => 2,
599                ParlIoRxClockConfig::PllF240m => 1,
600            })
601        });
602    }
603
604    // PARL_IO_TX_CLOCK
605
606    fn enable_tx_clock_impl(self, _clocks: &mut ClockTree, en: bool) {
607        PCR::regs()
608            .parl_clk_tx_conf()
609            .modify(|_, w| w.parl_clk_tx_en().bit(en));
610    }
611
612    fn configure_tx_clock_impl(
613        self,
614        _clocks: &mut ClockTree,
615        _old_config: Option<ParlIoTxClockConfig>,
616        new_config: ParlIoTxClockConfig,
617    ) {
618        PCR::regs().parl_clk_tx_conf().modify(|_, w| unsafe {
619            w.parl_clk_tx_sel().bits(match new_config {
620                ParlIoTxClockConfig::XtalClk => 0,
621                ParlIoTxClockConfig::RcFastClk => 2,
622                ParlIoTxClockConfig::PllF240m => 1,
623            })
624        });
625    }
626}
627
628impl RmtInstance {
629    // RMT_SCLK
630
631    fn enable_sclk_impl(self, _clocks: &mut ClockTree, en: bool) {
632        PCR::regs()
633            .rmt_sclk_conf()
634            .modify(|_, w| w.sclk_en().bit(en));
635    }
636
637    fn configure_sclk_impl(
638        self,
639        _clocks: &mut ClockTree,
640        _old_config: Option<RmtSclkConfig>,
641        new_config: RmtSclkConfig,
642    ) {
643        PCR::regs().rmt_sclk_conf().modify(|_, w| unsafe {
644            w.sclk_sel().bits(match new_config {
645                RmtSclkConfig::PllF80m => 1,
646                RmtSclkConfig::RcFastClk => 2,
647                RmtSclkConfig::XtalClk => 3,
648            })
649        });
650    }
651}
652
653impl TimgInstance {
654    // TIMG_FUNCTION_CLOCK
655
656    fn enable_function_clock_impl(self, _clocks: &mut ClockTree, en: bool) {
657        let timg = match self {
658            TimgInstance::Timg0 => 0,
659            TimgInstance::Timg1 => 1,
660        };
661        PCR::regs()
662            .timergroup(timg)
663            .timer_clk_conf()
664            .modify(|_, w| w.timer_clk_en().bit(en));
665    }
666
667    fn configure_function_clock_impl(
668        self,
669        _clocks: &mut ClockTree,
670        _old_config: Option<TimgFunctionClockConfig>,
671        new_config: TimgFunctionClockConfig,
672    ) {
673        let timg = match self {
674            TimgInstance::Timg0 => 0,
675            TimgInstance::Timg1 => 1,
676        };
677        PCR::regs()
678            .timergroup(timg)
679            .timer_clk_conf()
680            .modify(|_, w| unsafe {
681                // TODO: add variants to PAC
682                w.timer_clk_sel().bits(match new_config {
683                    TimgFunctionClockConfig::XtalClk => 0,
684                    TimgFunctionClockConfig::RcFastClk => 2,
685                    TimgFunctionClockConfig::PllF80m => 1,
686                })
687            });
688    }
689
690    // TIMG_WDT_CLOCK
691
692    fn enable_wdt_clock_impl(self, _clocks: &mut ClockTree, en: bool) {
693        let timg = match self {
694            TimgInstance::Timg0 => 0,
695            TimgInstance::Timg1 => 1,
696        };
697        PCR::regs()
698            .timergroup(timg)
699            .wdt_clk_conf()
700            .modify(|_, w| w.wdt_clk_en().bit(en));
701    }
702
703    fn configure_wdt_clock_impl(
704        self,
705        _clocks: &mut ClockTree,
706        _old_config: Option<TimgWdtClockConfig>,
707        new_config: TimgWdtClockConfig,
708    ) {
709        let timg = match self {
710            TimgInstance::Timg0 => 0,
711            TimgInstance::Timg1 => 1,
712        };
713        PCR::regs()
714            .timergroup(timg)
715            .wdt_clk_conf()
716            .modify(|_, w| unsafe {
717                w.wdt_clk_sel().bits(match new_config {
718                    TimgWdtClockConfig::XtalClk => 0,
719                    TimgWdtClockConfig::PllF80m => 1,
720                    TimgWdtClockConfig::RcFastClk => 2,
721                })
722            });
723    }
724}
725
726impl UartInstance {
727    // UART_FUNCTION_CLOCK
728
729    fn enable_function_clock_impl(self, _clocks: &mut ClockTree, en: bool) {
730        let uart = match self {
731            UartInstance::Uart0 => 0,
732            UartInstance::Uart1 => 1,
733        };
734        PCR::regs()
735            .uart(uart)
736            .clk_conf()
737            .modify(|_, w| w.sclk_en().bit(en));
738    }
739
740    fn configure_function_clock_impl(
741        self,
742        _clocks: &mut ClockTree,
743        _old_config: Option<UartFunctionClockConfig>,
744        new_config: UartFunctionClockConfig,
745    ) {
746        let uart = match self {
747            UartInstance::Uart0 => 0,
748            UartInstance::Uart1 => 1,
749        };
750        PCR::regs().uart(uart).clk_conf().modify(|_, w| unsafe {
751            w.sclk_sel().bits(match new_config.sclk {
752                UartFunctionClockSclk::PllF80m => 1,
753                UartFunctionClockSclk::RcFast => 2,
754                UartFunctionClockSclk::Xtal => 3,
755            });
756            w.sclk_div_a().bits(0);
757            w.sclk_div_b().bits(0);
758            w.sclk_div_num().bits(new_config.div_num as _);
759            w
760        });
761    }
762
763    // UART_BAUD_RATE_GENERATOR
764
765    fn enable_baud_rate_generator_impl(self, _clocks: &mut ClockTree, _en: bool) {
766        // Nothing to do.
767    }
768
769    fn configure_baud_rate_generator_impl(
770        self,
771        _clocks: &mut ClockTree,
772        _old_config: Option<UartBaudRateGeneratorConfig>,
773        new_config: UartBaudRateGeneratorConfig,
774    ) {
775        let regs = match self {
776            UartInstance::Uart0 => UART0::regs(),
777            UartInstance::Uart1 => UART1::regs(),
778        };
779        regs.clkdiv().write(|w| unsafe {
780            w.clkdiv().bits(new_config.integral as _);
781            w.frag().bits(new_config.fractional as _)
782        });
783    }
784}