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, MODEM_LPCON, 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    // enable i2c mst clk by temporarily forcing on
156    let old_clk_conf = MODEM_LPCON::regs().clk_conf().read();
157    MODEM_LPCON::regs().clk_conf().write(|w| {
158        unsafe { w.bits(old_clk_conf.bits()) };
159        w.clk_i2c_mst_en().set_bit()
160    });
161
162    MODEM_LPCON::regs()
163        .i2c_mst_clk_conf()
164        .modify(|_, w| w.clk_i2c_mst_sel_160m().set_bit());
165
166    // BBPLL CALIBRATION START
167    I2C_ANA_MST::regs().ana_conf0().modify(|_, w| {
168        w.bbpll_stop_force_high().clear_bit();
169        w.bbpll_stop_force_low().set_bit()
170    });
171
172    const DIV_REF: u8 = 0; // Do not divide reference clock
173    const DCHGP: u8 = 5;
174    const DCUR: u8 = 3;
175
176    const I2C_BBPLL_OC_DCHGP_LSB: u32 = 4;
177    const I2C_BBPLL_OC_DHREF_SEL_LSB: u32 = 4;
178    const I2C_BBPLL_OC_DLREF_SEL_LSB: u32 = 6;
179
180    const I2C_BBPLL_LREF: u8 = (DCHGP << I2C_BBPLL_OC_DCHGP_LSB) | DIV_REF;
181    const I2C_BBPLL_DCUR: u8 =
182        (1 << I2C_BBPLL_OC_DLREF_SEL_LSB) | (3 << I2C_BBPLL_OC_DHREF_SEL_LSB) | DCUR;
183
184    regi2c::I2C_BBPLL_OC_REF.write_reg(I2C_BBPLL_LREF);
185    regi2c::I2C_BBPLL_OC_DIV_REG.write_reg(8); // multiply 40MHz XTAL by 8+4
186    regi2c::I2C_BBPLL_OC_DR1.write_field(0);
187    regi2c::I2C_BBPLL_OC_DR3.write_field(0);
188    regi2c::I2C_BBPLL_REG6.write_reg(I2C_BBPLL_DCUR);
189    regi2c::I2C_BBPLL_OC_VCO_DBIAS.write_field(2);
190
191    // WAIT CALIBRATION DONE
192    while I2C_ANA_MST::regs()
193        .ana_conf0()
194        .read()
195        .cal_done()
196        .bit_is_clear()
197    {}
198
199    // workaround bbpll calibration might stop early
200    crate::rom::ets_delay_us(10);
201
202    // BBPLL CALIBRATION STOP
203    I2C_ANA_MST::regs().ana_conf0().modify(|_, w| {
204        w.bbpll_stop_force_high().set_bit();
205        w.bbpll_stop_force_low().clear_bit()
206    });
207
208    MODEM_LPCON::regs()
209        .clk_conf()
210        .write(|w| unsafe { w.bits(old_clk_conf.bits()) });
211}
212
213// RC_FAST_CLK
214
215fn enable_rc_fast_clk_impl(_clocks: &mut ClockTree, en: bool) {
216    PMU::regs()
217        .hp_sleep_lp_ck_power()
218        .modify(|_, w| w.hp_sleep_xpd_fosc_clk().bit(en));
219    // TODO: Should the digital clock gate be a different clock node?
220    LP_CLKRST::regs()
221        .clk_to_hp()
222        .modify(|_, w| w.icg_hp_fosc().bit(en));
223    crate::rom::ets_delay_us(5);
224}
225
226// XTAL32K_CLK
227
228fn enable_xtal32k_clk_impl(_clocks: &mut ClockTree, en: bool) {
229    LP_CLKRST::regs().xtal32k().write(|w| unsafe {
230        w.dac_xtal32k().bits(3);
231        w.dres_xtal32k().bits(3);
232        w.dgm_xtal32k().bits(3);
233        w.dbuf_xtal32k().bit(true)
234    });
235
236    PMU::regs()
237        .hp_sleep_lp_ck_power()
238        .modify(|_, w| w.hp_sleep_xpd_xtal32k().bit(en));
239
240    // Enable for digital part
241    // TODO: Should the digital clock gate be a different clock node?
242    LP_CLKRST::regs()
243        .clk_to_hp()
244        .modify(|_, w| w.icg_hp_xtal32k().bit(en));
245}
246
247// OSC_SLOW_CLK
248
249fn enable_osc_slow_clk_impl(_clocks: &mut ClockTree, _en: bool) {
250    // TODO:
251    // gpio_ll_input_enable(&GPIO, SOC_EXT_OSC_SLOW_GPIO_NUM);
252    // REG_SET_BIT(LP_AON_GPIO_HOLD0_REG, BIT(SOC_EXT_OSC_SLOW_GPIO_NUM));
253    todo!();
254
255    // No need to configure anything else for OSC_SLOW_CLK
256}
257
258// RC_SLOW_CLK
259
260fn enable_rc_slow_clk_impl(_clocks: &mut ClockTree, en: bool) {
261    if en {
262        // SCK_DCAP value controls tuning of 136k clock. The higher the value of DCAP, the lower the
263        // frequency. There is no separate enable bit, just make sure the calibration value is set.
264        const RTC_CNTL_SCK_DCAP_DEFAULT: u8 = 128;
265        crate::soc::regi2c::I2C_DIG_REG_SCK_DCAP.write_reg(RTC_CNTL_SCK_DCAP_DEFAULT);
266    }
267
268    PMU::regs()
269        .hp_sleep_lp_ck_power()
270        .modify(|_, w| w.hp_sleep_xpd_rc32k().bit(en));
271
272    // Enable for digital part
273    LP_CLKRST::regs()
274        .clk_to_hp()
275        .modify(|_, w| w.icg_hp_osc32k().bit(en));
276}
277
278// HP_ROOT_CLK
279
280fn enable_hp_root_clk_impl(_clocks: &mut ClockTree, _en: bool) {
281    // Nothing to do, managed by hardware.
282}
283
284fn configure_hp_root_clk_impl(
285    _clocks: &mut ClockTree,
286    _old_config: Option<HpRootClkConfig>,
287    _new_config: HpRootClkConfig,
288) {
289    // Nothing to do, managed by hardware.
290}
291
292// CPU_CLK
293
294fn configure_cpu_clk_impl(
295    _clocks: &mut ClockTree,
296    _old_config: Option<CpuClkConfig>,
297    _new_config: CpuClkConfig,
298) {
299    // Nothing to do, automatically managed by hardware.
300}
301
302// AHB_CLK
303
304fn configure_ahb_clk_impl(
305    _clocks: &mut ClockTree,
306    _old_config: Option<AhbClkConfig>,
307    _new_config: AhbClkConfig,
308) {
309    // Nothing to do, automatically managed by hardware.
310}
311
312// MSPI_FAST_CLK
313
314fn enable_mspi_fast_clk_impl(_clocks: &mut ClockTree, _en: bool) {
315    // Nothing to do.
316}
317
318fn configure_mspi_fast_clk_impl(
319    _clocks: &mut ClockTree,
320    _old_config: Option<MspiFastClkConfig>,
321    _new_config: MspiFastClkConfig,
322) {
323    // Nothing to do, automatically managed by hardware.
324}
325
326// SOC_ROOT_CLK
327
328fn enable_soc_root_clk_impl(_clocks: &mut ClockTree, _en: bool) {
329    // Nothing to do.
330}
331
332fn configure_soc_root_clk_impl(
333    _clocks: &mut ClockTree,
334    _old_config: Option<SocRootClkConfig>,
335    new_config: SocRootClkConfig,
336) {
337    PCR::regs().sysclk_conf().modify(|_, w| unsafe {
338        w.soc_clk_sel().bits(match new_config {
339            SocRootClkConfig::Xtal => 0,
340            SocRootClkConfig::Pll => 1,
341            SocRootClkConfig::RcFast => 2,
342        })
343    });
344}
345
346// CPU_HS_DIV
347
348fn enable_cpu_hs_div_impl(_clocks: &mut ClockTree, _en: bool) {
349    // Nothing to do.
350}
351
352fn configure_cpu_hs_div_impl(
353    _clocks: &mut ClockTree,
354    _old_config: Option<CpuHsDivConfig>,
355    new_config: CpuHsDivConfig,
356) {
357    PCR::regs()
358        .cpu_freq_conf()
359        .modify(|_, w| unsafe { w.cpu_hs_div_num().bits(new_config.divisor() as u8) });
360}
361
362// CPU_LS_DIV
363
364fn enable_cpu_ls_div_impl(_clocks: &mut ClockTree, _en: bool) {
365    // Nothing to do.
366}
367
368fn configure_cpu_ls_div_impl(
369    _clocks: &mut ClockTree,
370    _old_config: Option<CpuLsDivConfig>,
371    new_config: CpuLsDivConfig,
372) {
373    PCR::regs()
374        .cpu_freq_conf()
375        .modify(|_, w| unsafe { w.cpu_ls_div_num().bits(new_config.divisor() as u8) });
376}
377
378// AHB_HS_DIV
379
380fn enable_ahb_hs_div_impl(_clocks: &mut ClockTree, _en: bool) {
381    // Nothing to do.
382}
383
384fn configure_ahb_hs_div_impl(
385    _clocks: &mut ClockTree,
386    _old_config: Option<AhbHsDivConfig>,
387    new_config: AhbHsDivConfig,
388) {
389    PCR::regs()
390        .ahb_freq_conf()
391        .modify(|_, w| unsafe { w.ahb_hs_div_num().bits(new_config.divisor() as u8) });
392}
393
394// AHB_LS_DIV
395
396fn enable_ahb_ls_div_impl(_clocks: &mut ClockTree, _en: bool) {
397    // Nothing to do.
398}
399
400fn configure_ahb_ls_div_impl(
401    _clocks: &mut ClockTree,
402    _old_config: Option<AhbLsDivConfig>,
403    new_config: AhbLsDivConfig,
404) {
405    PCR::regs()
406        .ahb_freq_conf()
407        .modify(|_, w| unsafe { w.ahb_ls_div_num().bits(new_config.divisor() as u8) });
408}
409
410// APB_CLK
411
412fn enable_apb_clk_impl(_clocks: &mut ClockTree, _en: bool) {
413    // Nothing to do.
414}
415
416fn configure_apb_clk_impl(
417    _clocks: &mut ClockTree,
418    _old_config: Option<ApbClkConfig>,
419    new_config: ApbClkConfig,
420) {
421    PCR::regs()
422        .apb_freq_conf()
423        .modify(|_, w| unsafe { w.apb_div_num().bits(new_config.divisor() as u8) });
424}
425
426// MSPI_FAST_HS_CLK
427
428fn enable_mspi_fast_hs_clk_impl(_clocks: &mut ClockTree, _en: bool) {
429    // Nothing to do, automatically managed by hardware.
430}
431
432fn configure_mspi_fast_hs_clk_impl(
433    _clocks: &mut ClockTree,
434    _old_config: Option<MspiFastHsClkConfig>,
435    new_config: MspiFastHsClkConfig,
436) {
437    PCR::regs()
438        .mspi_clk_conf()
439        .modify(|_, w| unsafe { w.mspi_fast_hs_div_num().bits(new_config.divisor() as u8) });
440}
441
442// MSPI_FAST_LS_CLK
443
444fn enable_mspi_fast_ls_clk_impl(_clocks: &mut ClockTree, _en: bool) {
445    // Nothing to do, automatically managed by hardware.
446}
447
448fn configure_mspi_fast_ls_clk_impl(
449    _clocks: &mut ClockTree,
450    _old_config: Option<MspiFastLsClkConfig>,
451    new_config: MspiFastLsClkConfig,
452) {
453    PCR::regs()
454        .mspi_clk_conf()
455        .modify(|_, w| unsafe { w.mspi_fast_ls_div_num().bits(new_config.divisor() as u8) });
456}
457
458// PLL_F48M
459
460fn enable_pll_f48m_impl(_clocks: &mut ClockTree, _en: bool) {
461    // Nothing to do.
462}
463
464// PLL_F80M
465
466fn enable_pll_f80m_impl(_clocks: &mut ClockTree, _en: bool) {
467    // Nothing to do.
468}
469
470// PLL_F160M
471
472fn enable_pll_f160m_impl(_clocks: &mut ClockTree, _en: bool) {
473    // Nothing to do.
474}
475
476// PLL_F240M
477
478fn enable_pll_f240m_impl(_clocks: &mut ClockTree, _en: bool) {
479    // Nothing to do.
480}
481
482// LEDC_SCLK
483
484fn enable_ledc_sclk_impl(_clocks: &mut ClockTree, en: bool) {
485    PCR::regs()
486        .ledc_sclk_conf()
487        .modify(|_, w| w.ledc_sclk_en().bit(en));
488}
489
490fn configure_ledc_sclk_impl(
491    _clocks: &mut ClockTree,
492    _old_config: Option<LedcSclkConfig>,
493    new_config: LedcSclkConfig,
494) {
495    PCR::regs().ledc_sclk_conf().modify(|_, w| unsafe {
496        w.ledc_sclk_sel().bits(match new_config {
497            LedcSclkConfig::PllF80m => 1,
498            LedcSclkConfig::RcFastClk => 2,
499            LedcSclkConfig::XtalClk => 3,
500        })
501    });
502}
503
504// XTAL_D2_CLK
505
506fn enable_xtal_d2_clk_impl(_clocks: &mut ClockTree, _en: bool) {
507    // Nothing to do, the divider is always on.
508}
509
510// LP_FAST_CLK
511
512fn enable_lp_fast_clk_impl(_clocks: &mut ClockTree, _en: bool) {
513    // Nothing to do.
514}
515
516fn configure_lp_fast_clk_impl(
517    _clocks: &mut ClockTree,
518    _old_config: Option<LpFastClkConfig>,
519    new_config: LpFastClkConfig,
520) {
521    LP_CLKRST::regs().lp_clk_conf().modify(|_, w| {
522        w.fast_clk_sel().bit(match new_config {
523            LpFastClkConfig::RcFastClk => false,
524            LpFastClkConfig::XtalD2Clk => true,
525        })
526    });
527}
528
529// LP_SLOW_CLK
530
531fn enable_lp_slow_clk_impl(_clocks: &mut ClockTree, _en: bool) {
532    // Nothing to do.
533}
534
535fn configure_lp_slow_clk_impl(
536    _clocks: &mut ClockTree,
537    _old_config: Option<LpSlowClkConfig>,
538    new_config: LpSlowClkConfig,
539) {
540    LP_CLKRST::regs().lp_clk_conf().modify(|_, w| unsafe {
541        w.slow_clk_sel().bits(match new_config {
542            LpSlowClkConfig::Xtal32k => 1,
543            LpSlowClkConfig::RcSlow => 0,
544            LpSlowClkConfig::OscSlow => 2,
545        })
546    });
547}
548
549// TIMG_CALIBRATION_CLOCK
550
551fn enable_timg_calibration_clock_impl(_clocks: &mut ClockTree, _en: bool) {
552    // Nothing to do, calibration clocks can only be selected. They are gated by the CALI_START
553    // bit, which is managed by the calibration process.
554}
555
556fn configure_timg_calibration_clock_impl(
557    _clocks: &mut ClockTree,
558    _old_config: Option<TimgCalibrationClockConfig>,
559    new_config: TimgCalibrationClockConfig,
560) {
561    TIMG0::regs().rtccalicfg().modify(|_, w| unsafe {
562        w.rtc_cali_clk_sel().bits(match new_config {
563            TimgCalibrationClockConfig::RcSlowClk => 0,
564            TimgCalibrationClockConfig::RcFastDivClk => 1,
565            TimgCalibrationClockConfig::Xtal32kClk => 2,
566        })
567    });
568}
569
570impl McpwmInstance {
571    // MCPWM_FUNCTION_CLOCK
572
573    fn enable_function_clock_impl(self, _clocks: &mut ClockTree, en: bool) {
574        PCR::regs()
575            .pwm_clk_conf()
576            .modify(|_, w| w.pwm_clkm_en().bit(en));
577    }
578
579    fn configure_function_clock_impl(
580        self,
581        _clocks: &mut ClockTree,
582        _old_config: Option<McpwmFunctionClockConfig>,
583        new_config: McpwmFunctionClockConfig,
584    ) {
585        PCR::regs().pwm_clk_conf().modify(|_, w| unsafe {
586            w.pwm_clkm_sel().bits(match new_config {
587                McpwmFunctionClockConfig::PllF160m => 1,
588                McpwmFunctionClockConfig::XtalClk => 2,
589                McpwmFunctionClockConfig::RcFastClk => 3,
590            })
591        });
592    }
593}
594
595impl ParlIoInstance {
596    // PARL_IO_RX_CLOCK
597
598    fn enable_rx_clock_impl(self, _clocks: &mut ClockTree, en: bool) {
599        PCR::regs()
600            .parl_clk_rx_conf()
601            .modify(|_, w| w.parl_clk_rx_en().bit(en));
602    }
603
604    fn configure_rx_clock_impl(
605        self,
606        _clocks: &mut ClockTree,
607        _old_config: Option<ParlIoRxClockConfig>,
608        new_config: ParlIoRxClockConfig,
609    ) {
610        PCR::regs().parl_clk_rx_conf().modify(|_, w| unsafe {
611            w.parl_clk_rx_sel().bits(match new_config {
612                ParlIoRxClockConfig::XtalClk => 0,
613                ParlIoRxClockConfig::RcFastClk => 2,
614                ParlIoRxClockConfig::PllF240m => 1,
615            })
616        });
617    }
618
619    // PARL_IO_TX_CLOCK
620
621    fn enable_tx_clock_impl(self, _clocks: &mut ClockTree, en: bool) {
622        PCR::regs()
623            .parl_clk_tx_conf()
624            .modify(|_, w| w.parl_clk_tx_en().bit(en));
625    }
626
627    fn configure_tx_clock_impl(
628        self,
629        _clocks: &mut ClockTree,
630        _old_config: Option<ParlIoTxClockConfig>,
631        new_config: ParlIoTxClockConfig,
632    ) {
633        PCR::regs().parl_clk_tx_conf().modify(|_, w| unsafe {
634            w.parl_clk_tx_sel().bits(match new_config {
635                ParlIoTxClockConfig::XtalClk => 0,
636                ParlIoTxClockConfig::RcFastClk => 2,
637                ParlIoTxClockConfig::PllF240m => 1,
638            })
639        });
640    }
641}
642
643impl RmtInstance {
644    // RMT_SCLK
645
646    fn enable_sclk_impl(self, _clocks: &mut ClockTree, en: bool) {
647        PCR::regs()
648            .rmt_sclk_conf()
649            .modify(|_, w| w.sclk_en().bit(en));
650    }
651
652    fn configure_sclk_impl(
653        self,
654        _clocks: &mut ClockTree,
655        _old_config: Option<RmtSclkConfig>,
656        new_config: RmtSclkConfig,
657    ) {
658        PCR::regs().rmt_sclk_conf().modify(|_, w| unsafe {
659            w.sclk_sel().bits(match new_config {
660                RmtSclkConfig::PllF80m => 1,
661                RmtSclkConfig::RcFastClk => 2,
662                RmtSclkConfig::XtalClk => 3,
663            })
664        });
665    }
666}
667
668impl TimgInstance {
669    // TIMG_FUNCTION_CLOCK
670
671    fn enable_function_clock_impl(self, _clocks: &mut ClockTree, en: bool) {
672        let timg = match self {
673            TimgInstance::Timg0 => 0,
674            TimgInstance::Timg1 => 1,
675        };
676        PCR::regs()
677            .timergroup(timg)
678            .timer_clk_conf()
679            .modify(|_, w| w.timer_clk_en().bit(en));
680    }
681
682    fn configure_function_clock_impl(
683        self,
684        _clocks: &mut ClockTree,
685        _old_config: Option<TimgFunctionClockConfig>,
686        new_config: TimgFunctionClockConfig,
687    ) {
688        let timg = match self {
689            TimgInstance::Timg0 => 0,
690            TimgInstance::Timg1 => 1,
691        };
692        PCR::regs()
693            .timergroup(timg)
694            .timer_clk_conf()
695            .modify(|_, w| unsafe {
696                // TODO: add variants to PAC
697                w.timer_clk_sel().bits(match new_config {
698                    TimgFunctionClockConfig::XtalClk => 0,
699                    TimgFunctionClockConfig::RcFastClk => 2,
700                    TimgFunctionClockConfig::PllF80m => 1,
701                })
702            });
703    }
704
705    // TIMG_WDT_CLOCK
706
707    fn enable_wdt_clock_impl(self, _clocks: &mut ClockTree, en: bool) {
708        let timg = match self {
709            TimgInstance::Timg0 => 0,
710            TimgInstance::Timg1 => 1,
711        };
712        PCR::regs()
713            .timergroup(timg)
714            .wdt_clk_conf()
715            .modify(|_, w| w.wdt_clk_en().bit(en));
716    }
717
718    fn configure_wdt_clock_impl(
719        self,
720        _clocks: &mut ClockTree,
721        _old_config: Option<TimgWdtClockConfig>,
722        new_config: TimgWdtClockConfig,
723    ) {
724        let timg = match self {
725            TimgInstance::Timg0 => 0,
726            TimgInstance::Timg1 => 1,
727        };
728        PCR::regs()
729            .timergroup(timg)
730            .wdt_clk_conf()
731            .modify(|_, w| unsafe {
732                w.wdt_clk_sel().bits(match new_config {
733                    TimgWdtClockConfig::XtalClk => 0,
734                    TimgWdtClockConfig::PllF80m => 1,
735                    TimgWdtClockConfig::RcFastClk => 2,
736                })
737            });
738    }
739}
740
741impl UartInstance {
742    // UART_FUNCTION_CLOCK
743
744    fn enable_function_clock_impl(self, _clocks: &mut ClockTree, en: bool) {
745        let uart = match self {
746            UartInstance::Uart0 => 0,
747            UartInstance::Uart1 => 1,
748        };
749        PCR::regs()
750            .uart(uart)
751            .clk_conf()
752            .modify(|_, w| w.sclk_en().bit(en));
753    }
754
755    fn configure_function_clock_impl(
756        self,
757        _clocks: &mut ClockTree,
758        _old_config: Option<UartFunctionClockConfig>,
759        new_config: UartFunctionClockConfig,
760    ) {
761        let uart = match self {
762            UartInstance::Uart0 => 0,
763            UartInstance::Uart1 => 1,
764        };
765        PCR::regs().uart(uart).clk_conf().modify(|_, w| unsafe {
766            w.sclk_sel().bits(match new_config.sclk {
767                UartFunctionClockSclk::PllF80m => 1,
768                UartFunctionClockSclk::RcFast => 2,
769                UartFunctionClockSclk::Xtal => 3,
770            });
771            w.sclk_div_a().bits(0);
772            w.sclk_div_b().bits(0);
773            w.sclk_div_num().bits(new_config.div_num as _);
774            w
775        });
776    }
777
778    // UART_BAUD_RATE_GENERATOR
779
780    fn enable_baud_rate_generator_impl(self, _clocks: &mut ClockTree, _en: bool) {
781        // Nothing to do.
782    }
783
784    fn configure_baud_rate_generator_impl(
785        self,
786        _clocks: &mut ClockTree,
787        _old_config: Option<UartBaudRateGeneratorConfig>,
788        new_config: UartBaudRateGeneratorConfig,
789    ) {
790        let regs = match self {
791            UartInstance::Uart0 => UART0::regs(),
792            UartInstance::Uart1 => UART1::regs(),
793        };
794        regs.clkdiv().write(|w| unsafe {
795            w.clkdiv().bits(new_config.integral as _);
796            w.frag().bits(new_config.fractional as _)
797        });
798    }
799}