Skip to main content

esp_hal/soc/esp32c5/
clocks.rs

1//! Clock tree definitions and implementations for ESP32-C5.
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 (32K OSC_SLOW, 130k RC_SLOW and 20M RC_FAST) are not calibrated here,
9//!   this system can only give a rough estimate of their frequency. They can be calibrated
10//!   separately using a known crystal frequency.
11//! - Some of the SOC capabilities are not implemented: I2S external pad clock source, external 32k
12//!   oscillator, others.
13#![allow(dead_code, reason = "Some of this is bound to be unused")]
14#![allow(missing_docs, reason = "Experimental")]
15
16// TODO: This is a temporary place for this, should probably be moved into clocks_ll.
17
18use crate::{
19    peripherals::{I2C_ANA_MST, LP_CLKRST, PCR, PMU, UART0, UART1},
20    soc::regi2c,
21};
22
23define_clock_tree_types!();
24
25/// Clock configuration options.
26#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
27#[cfg_attr(feature = "defmt", derive(defmt::Format))]
28#[allow(
29    clippy::enum_variant_names,
30    reason = "MHz suffix indicates physical unit."
31)]
32#[non_exhaustive]
33pub enum CpuClock {
34    /// 80 MHz CPU clock
35    #[default]
36    _80MHz  = 80,
37
38    /// 160 MHz CPU clock
39    _160MHz = 160,
40
41    /// 240 MHz CPU clock
42    _240MHz = 240,
43}
44
45impl CpuClock {
46    const PRESET_80: ClockConfig = ClockConfig {
47        xtal_clk: None,
48        hp_root_clk: Some(HpRootClkConfig::PllF160m),
49        cpu_clk: Some(CpuClkConfig::new(1)),
50        ahb_clk: Some(AhbClkConfig::new(3)), // 40MHz - cannot exceed XTAL_CLK
51        apb_clk: Some(ApbClkConfig::new(0)),
52        lp_fast_clk: Some(LpFastClkConfig::RcFast),
53        lp_slow_clk: Some(LpSlowClkConfig::RcSlow),
54        crypto_clk: Some(CryptoClkConfig::PllF480m),
55        timg_calibration_clock: None,
56    };
57    const PRESET_160: ClockConfig = ClockConfig {
58        xtal_clk: None,
59        hp_root_clk: Some(HpRootClkConfig::PllF160m),
60        cpu_clk: Some(CpuClkConfig::new(0)),
61        ahb_clk: Some(AhbClkConfig::new(3)), // 40MHz - cannot exceed XTAL_CLK
62        apb_clk: Some(ApbClkConfig::new(0)),
63        lp_fast_clk: Some(LpFastClkConfig::RcFast),
64        lp_slow_clk: Some(LpSlowClkConfig::RcSlow),
65        crypto_clk: Some(CryptoClkConfig::PllF480m),
66        timg_calibration_clock: None,
67    };
68    const PRESET_240: ClockConfig = ClockConfig {
69        xtal_clk: None,
70        hp_root_clk: Some(HpRootClkConfig::PllF240m),
71        cpu_clk: Some(CpuClkConfig::new(0)),
72        ahb_clk: Some(AhbClkConfig::new(5)), // 40MHz - cannot exceed XTAL_CLK
73        apb_clk: Some(ApbClkConfig::new(0)),
74        lp_fast_clk: Some(LpFastClkConfig::RcFast),
75        lp_slow_clk: Some(LpSlowClkConfig::RcSlow),
76        crypto_clk: Some(CryptoClkConfig::PllF480m),
77        timg_calibration_clock: None,
78    };
79}
80
81impl From<CpuClock> for ClockConfig {
82    fn from(value: CpuClock) -> ClockConfig {
83        match value {
84            CpuClock::_80MHz => CpuClock::PRESET_80,
85            CpuClock::_160MHz => CpuClock::PRESET_160,
86            CpuClock::_240MHz => CpuClock::PRESET_240,
87        }
88    }
89}
90
91impl Default for ClockConfig {
92    fn default() -> Self {
93        Self::from(CpuClock::default())
94    }
95}
96
97impl ClockConfig {
98    pub(crate) fn try_get_preset(self) -> Option<CpuClock> {
99        match self {
100            v if v == CpuClock::PRESET_80 => Some(CpuClock::_80MHz),
101            v if v == CpuClock::PRESET_160 => Some(CpuClock::_160MHz),
102            v if v == CpuClock::PRESET_240 => Some(CpuClock::_240MHz),
103            _ => None,
104        }
105    }
106
107    pub(crate) fn configure(mut self) {
108        // FIXME: we ignore user XTAL configuration, but we shouldn't offer it in the first place.
109        // PCR_CLK_XTAL_FREQ updates its value based on EFUSE_XTAL_48M_SEL.
110        self.xtal_clk = if PCR::regs().sysclk_conf().read().clk_xtal_freq().bits() == 40 {
111            Some(XtalClkConfig::_40)
112        } else {
113            Some(XtalClkConfig::_48)
114        };
115
116        self.apply();
117    }
118}
119
120// XTAL_CLK
121
122fn configure_xtal_clk_impl(
123    _clocks: &mut ClockTree,
124    _old_config: Option<XtalClkConfig>,
125    _config: XtalClkConfig,
126) {
127    // Nothing to do here.
128}
129
130// PLL_CLK
131
132fn enable_pll_clk_impl(clocks: &mut ClockTree, en: bool) {
133    if en {
134        PMU::regs().imm_hp_ck_power().write(|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            .write(|w| w.tie_high_global_bbpll_icg().set_bit());
142    } else {
143        PMU::regs()
144            .imm_hp_ck_power()
145            .write(|w| w.tie_low_global_bbpll_icg().set_bit());
146        PMU::regs().imm_hp_ck_power().write(|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    // Digital part - nothing to do here, PLL always runs at 480MHz
156
157    // Analog part
158
159    // BBPLL CALIBRATION START
160    I2C_ANA_MST::regs().ana_conf0().modify(|_, w| {
161        w.bbpll_stop_force_high().clear_bit();
162        w.bbpll_stop_force_low().set_bit()
163    });
164
165    let div7_0: u8;
166    let dr1: u8;
167    let dr3: u8;
168    match unwrap!(clocks.xtal_clk()) {
169        XtalClkConfig::_40 => {
170            div7_0 = 12;
171            dr1 = 0;
172            dr3 = 0;
173        }
174        XtalClkConfig::_48 => {
175            div7_0 = 10;
176            dr1 = 1;
177            dr3 = 1;
178        }
179    }
180
181    const DIV_REF: u8 = 1; // Do not divide reference clock
182    const DCHGP: u8 = 5;
183    const DBIAS: u8 = 3;
184    const HREF: u8 = 3;
185    const LREF: u8 = 1;
186
187    const I2C_BBPLL_OC_DCHGP_LSB: u32 = 4;
188    const I2C_BBPLL_OC_DHREF_SEL_LSB: u32 = 4;
189    const I2C_BBPLL_OC_DLREF_SEL_LSB: u32 = 6;
190
191    const I2C_BBPLL_LREF: u8 = (DCHGP << I2C_BBPLL_OC_DCHGP_LSB) | DIV_REF;
192
193    regi2c::I2C_BBPLL_OC_REF.write_reg(I2C_BBPLL_LREF);
194    regi2c::I2C_BBPLL_OC_DIV_REG.write_reg(div7_0);
195    regi2c::I2C_BBPLL_OC_DR1.write_field(dr1);
196    regi2c::I2C_BBPLL_OC_DR3.write_field(dr3);
197    regi2c::I2C_BBPLL_OC_DLREF_SEL.write_field(LREF);
198    regi2c::I2C_BBPLL_OC_DHREF_SEL.write_field(HREF);
199    regi2c::I2C_BBPLL_OC_VCO_DBIAS.write_field(DBIAS);
200
201    // WAIT CALIBRATION DONE
202    while I2C_ANA_MST::regs()
203        .ana_conf0()
204        .read()
205        .cal_done()
206        .bit_is_clear()
207    {}
208    crate::rom::ets_delay_us(10);
209
210    // BBPLL CALIBRATION STOP
211    I2C_ANA_MST::regs().ana_conf0().modify(|_, w| {
212        w.bbpll_stop_force_high().set_bit();
213        w.bbpll_stop_force_low().clear_bit()
214    });
215}
216
217// RC_FAST_CLK
218
219fn enable_rc_fast_clk_impl(_clocks: &mut ClockTree, en: bool) {
220    LP_CLKRST::regs()
221        .clk_to_hp()
222        .modify(|_, w| w.icg_hp_fosc().bit(en));
223}
224
225// XTAL32K_CLK
226
227fn enable_xtal32k_clk_impl(_clocks: &mut ClockTree, en: bool) {
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    LP_CLKRST::regs()
237        .clk_to_hp()
238        .modify(|_, w| w.icg_hp_osc32k().bit(en));
239}
240
241// RC_SLOW_CLK
242
243fn enable_rc_slow_clk_impl(_clocks: &mut ClockTree, en: bool) {
244    LP_CLKRST::regs()
245        .clk_to_hp()
246        .modify(|_, w| w.icg_hp_sosc().bit(en));
247}
248
249// PLL_F12M
250
251fn enable_pll_f12m_impl(_clocks: &mut ClockTree, en: bool) {
252    PCR::regs()
253        .pll_div_clk_en()
254        .modify(|_, w| w.pll_12m_clk_en().bit(en));
255}
256
257// PLL_F20M
258
259fn enable_pll_f20m_impl(_clocks: &mut ClockTree, en: bool) {
260    PCR::regs()
261        .pll_div_clk_en()
262        .modify(|_, w| w.pll_20m_clk_en().bit(en));
263}
264
265// PLL_F40M
266
267fn enable_pll_f40m_impl(_clocks: &mut ClockTree, en: bool) {
268    PCR::regs()
269        .pll_div_clk_en()
270        .modify(|_, w| w.pll_40m_clk_en().bit(en));
271}
272
273// PLL_F48M
274
275fn enable_pll_f48m_impl(_clocks: &mut ClockTree, en: bool) {
276    PCR::regs()
277        .pll_div_clk_en()
278        .modify(|_, w| w.pll_48m_clk_en().bit(en));
279}
280
281// PLL_F60M
282
283fn enable_pll_f60m_impl(_clocks: &mut ClockTree, en: bool) {
284    PCR::regs()
285        .pll_div_clk_en()
286        .modify(|_, w| w.pll_60m_clk_en().bit(en));
287}
288
289// PLL_F80M
290
291fn enable_pll_f80m_impl(_clocks: &mut ClockTree, en: bool) {
292    PCR::regs()
293        .pll_div_clk_en()
294        .modify(|_, w| w.pll_80m_clk_en().bit(en));
295}
296
297// PLL_F120M
298
299fn enable_pll_f120m_impl(_clocks: &mut ClockTree, en: bool) {
300    PCR::regs()
301        .pll_div_clk_en()
302        .modify(|_, w| w.pll_120m_clk_en().bit(en));
303}
304
305// PLL_F160M
306
307fn enable_pll_f160m_impl(_clocks: &mut ClockTree, en: bool) {
308    PCR::regs()
309        .pll_div_clk_en()
310        .modify(|_, w| w.pll_160m_clk_en().bit(en));
311}
312
313// PLL_F240M
314
315fn enable_pll_f240m_impl(_clocks: &mut ClockTree, en: bool) {
316    PCR::regs()
317        .pll_div_clk_en()
318        .modify(|_, w| w.pll_240m_clk_en().bit(en));
319}
320
321// HP_ROOT_CLK
322
323fn enable_hp_root_clk_impl(_clocks: &mut ClockTree, _en: bool) {
324    // Nothing to do here.
325}
326
327fn configure_hp_root_clk_impl(
328    _clocks: &mut ClockTree,
329    _old_config: Option<HpRootClkConfig>,
330    new_config: HpRootClkConfig,
331) {
332    // TODO: Limit AHB to ensure it's running at <= XTAL_CLK && CPU_CLK must be an integer multiple
333    // of AHB
334    PCR::regs().sysclk_conf().modify(|_, w| unsafe {
335        w.soc_clk_sel().bits(match new_config {
336            HpRootClkConfig::Xtal => 0,
337            HpRootClkConfig::RcFast => 1,
338            HpRootClkConfig::PllF160m => 2,
339            HpRootClkConfig::PllF240m => 3,
340        })
341    });
342}
343
344// CPU_CLK
345
346fn enable_cpu_clk_impl(_clocks: &mut ClockTree, _en: bool) {
347    // Nothing to do here.
348}
349
350fn configure_cpu_clk_impl(
351    _clocks: &mut ClockTree,
352    _old_config: Option<CpuClkConfig>,
353    new_config: CpuClkConfig,
354) {
355    PCR::regs()
356        .cpu_freq_conf()
357        .modify(|_, w| unsafe { w.cpu_div_num().bits(new_config.divisor() as u8) });
358
359    PCR::regs()
360        .bus_clk_update()
361        .write(|w| w.bus_clock_update().set_bit());
362}
363
364// AHB_CLK
365
366fn enable_ahb_clk_impl(_clocks: &mut ClockTree, _en: bool) {
367    // Nothing to do here.
368}
369
370fn configure_ahb_clk_impl(
371    _clocks: &mut ClockTree,
372    _old_config: Option<AhbClkConfig>,
373    new_config: AhbClkConfig,
374) {
375    PCR::regs()
376        .ahb_freq_conf()
377        .modify(|_, w| unsafe { w.ahb_div_num().bits(new_config.divisor() as u8) });
378
379    PCR::regs()
380        .bus_clk_update()
381        .write(|w| w.bus_clock_update().set_bit());
382}
383
384// APB_CLK
385
386fn enable_apb_clk_impl(_clocks: &mut ClockTree, _en: bool) {
387    // Nothing to do here.
388}
389
390fn configure_apb_clk_impl(
391    _clocks: &mut ClockTree,
392    _old_config: Option<ApbClkConfig>,
393    new_config: ApbClkConfig,
394) {
395    PCR::regs()
396        .apb_freq_conf()
397        .modify(|_, w| unsafe { w.apb_div_num().bits(new_config.divisor() as u8) });
398}
399
400// XTAL_D2_CLK
401
402fn enable_xtal_d2_clk_impl(_clocks: &mut ClockTree, _en: bool) {
403    // Nothing to do here.
404}
405
406// LP_FAST_CLK
407
408fn enable_lp_fast_clk_impl(_clocks: &mut ClockTree, _en: bool) {
409    // Nothing to do here.
410}
411
412fn configure_lp_fast_clk_impl(
413    _clocks: &mut ClockTree,
414    _old_config: Option<LpFastClkConfig>,
415    new_config: LpFastClkConfig,
416) {
417    LP_CLKRST::regs().lp_clk_conf().modify(|_, w| unsafe {
418        w.fast_clk_sel().bits(match new_config {
419            LpFastClkConfig::RcFast => 0,
420            LpFastClkConfig::XtalD2 => 1,
421            LpFastClkConfig::Xtal => 2,
422        })
423    });
424}
425
426// LP_SLOW_CLK
427
428fn enable_lp_slow_clk_impl(_clocks: &mut ClockTree, _en: bool) {
429    // Nothing to do here.
430}
431
432fn configure_lp_slow_clk_impl(
433    _clocks: &mut ClockTree,
434    _old_config: Option<LpSlowClkConfig>,
435    new_config: LpSlowClkConfig,
436) {
437    LP_CLKRST::regs().lp_clk_conf().modify(|_, w| unsafe {
438        w.slow_clk_sel().bits(match new_config {
439            LpSlowClkConfig::RcSlow => 0,
440            LpSlowClkConfig::Xtal32k => 1,
441            // LpSlowClkConfig::Ext32k => 2,
442            LpSlowClkConfig::OscSlow => 3,
443        })
444    });
445}
446
447// CRYPTO_CLK
448
449fn enable_crypto_clk_impl(_clocks: &mut ClockTree, _en: bool) {
450    // Nothing to do here.
451}
452
453fn configure_crypto_clk_impl(
454    _clocks: &mut ClockTree,
455    _old_config: Option<CryptoClkConfig>,
456    new_config: CryptoClkConfig,
457) {
458    PCR::regs().sec_conf().modify(|_, w| unsafe {
459        w.sec_clk_sel().bits(match new_config {
460            CryptoClkConfig::Xtal => 0,
461            CryptoClkConfig::Fosc => 1,
462            CryptoClkConfig::PllF480m => 2,
463        })
464    });
465}
466
467// TIMG_CALIBRATION_CLOCK
468
469fn enable_timg_calibration_clock_impl(_clocks: &mut ClockTree, _en: bool) {
470    // Nothing to do here.
471}
472
473fn configure_timg_calibration_clock_impl(
474    _clocks: &mut ClockTree,
475    _old_config: Option<TimgCalibrationClockConfig>,
476    new_config: TimgCalibrationClockConfig,
477) {
478    PCR::regs().ctrl_32k_conf().modify(|_, w| unsafe {
479        w._32k_sel().bits(match new_config {
480            TimgCalibrationClockConfig::OscSlowClk => 0,
481            TimgCalibrationClockConfig::Xtal32kClk => 1,
482            // TimgCalibrationClockConfig::Ext32kClk => 2,
483            TimgCalibrationClockConfig::RcSlowClk => 3,
484            TimgCalibrationClockConfig::RcFastDivClk => 4,
485        })
486    });
487}
488
489impl ParlIoInstance {
490    // PARL_IO_RX_CLOCK
491
492    fn enable_rx_clock_impl(self, _clocks: &mut ClockTree, en: bool) {
493        PCR::regs()
494            .parl_clk_rx_conf()
495            .modify(|_, w| w.parl_clk_rx_en().bit(en));
496    }
497
498    fn configure_rx_clock_impl(
499        self,
500        _clocks: &mut ClockTree,
501        _old_config: Option<ParlIoRxClockConfig>,
502        new_config: ParlIoRxClockConfig,
503    ) {
504        PCR::regs().parl_clk_rx_conf().modify(|_, w| unsafe {
505            w.parl_clk_rx_sel().bits(match new_config {
506                ParlIoRxClockConfig::XtalClk => 0,
507                ParlIoRxClockConfig::RcFastClk => 1,
508                ParlIoRxClockConfig::PllF240m => 2,
509            })
510        });
511    }
512
513    // PARL_IO_TX_CLOCK
514
515    fn enable_tx_clock_impl(self, _clocks: &mut ClockTree, en: bool) {
516        PCR::regs()
517            .parl_clk_tx_conf()
518            .modify(|_, w| w.parl_clk_tx_en().bit(en));
519    }
520
521    fn configure_tx_clock_impl(
522        self,
523        _clocks: &mut ClockTree,
524        _old_config: Option<ParlIoTxClockConfig>,
525        new_config: ParlIoTxClockConfig,
526    ) {
527        PCR::regs().parl_clk_tx_conf().modify(|_, w| unsafe {
528            w.parl_clk_tx_sel().bits(match new_config {
529                ParlIoTxClockConfig::XtalClk => 0,
530                ParlIoTxClockConfig::RcFastClk => 1,
531                ParlIoTxClockConfig::PllF240m => 2,
532            })
533        });
534    }
535}
536
537impl RmtInstance {
538    // RMT_SCLK
539
540    fn enable_sclk_impl(self, _clocks: &mut ClockTree, en: bool) {
541        PCR::regs().rmt_pd_ctrl().modify(|_, w| {
542            w.rmt_mem_force_pu().bit(en);
543            w.rmt_mem_force_pd().bit(!en)
544        });
545
546        PCR::regs()
547            .rmt_sclk_conf()
548            .modify(|_, w| w.sclk_en().bit(en));
549    }
550
551    fn configure_sclk_impl(
552        self,
553        _clocks: &mut ClockTree,
554        _old_config: Option<RmtSclkConfig>,
555        new_config: RmtSclkConfig,
556    ) {
557        PCR::regs().rmt_sclk_conf().modify(|_, w| unsafe {
558            w.sclk_sel().bits(match new_config {
559                RmtSclkConfig::XtalClk => 0,
560                RmtSclkConfig::RcFastClk => 1,
561                RmtSclkConfig::PllF80m => 2,
562            })
563        });
564    }
565}
566
567impl TimgInstance {
568    // TIMG_FUNCTION_CLOCK
569
570    // TIMG0_FUNCTION_CLOCK
571
572    fn enable_function_clock_impl(self, _clocks: &mut ClockTree, en: bool) {
573        let timg = match self {
574            TimgInstance::Timg0 => 0,
575            TimgInstance::Timg1 => 1,
576        };
577        PCR::regs()
578            .timergroup(timg)
579            .timer_clk_conf()
580            .modify(|_, w| w.timer_clk_en().bit(en));
581    }
582
583    fn configure_function_clock_impl(
584        self,
585        _clocks: &mut ClockTree,
586        _old_config: Option<TimgFunctionClockConfig>,
587        new_config: TimgFunctionClockConfig,
588    ) {
589        // TODO: add variants to PAC
590        let timg = match self {
591            TimgInstance::Timg0 => 0,
592            TimgInstance::Timg1 => 1,
593        };
594        PCR::regs()
595            .timergroup(timg)
596            .timer_clk_conf()
597            .modify(|_, w| unsafe {
598                w.timer_clk_sel().bits(match new_config {
599                    TimgFunctionClockConfig::XtalClk => 0,
600                    TimgFunctionClockConfig::RcFastClk => 1,
601                    TimgFunctionClockConfig::PllF80m => 2,
602                })
603            });
604    }
605
606    // TIMG_WDT_CLOCK
607
608    fn enable_wdt_clock_impl(self, _clocks: &mut ClockTree, en: bool) {
609        let timg = match self {
610            TimgInstance::Timg0 => 0,
611            TimgInstance::Timg1 => 1,
612        };
613        PCR::regs()
614            .timergroup(timg)
615            .wdt_clk_conf()
616            .modify(|_, w| w.wdt_clk_en().bit(en));
617    }
618
619    fn configure_wdt_clock_impl(
620        self,
621        _clocks: &mut ClockTree,
622        _old_config: Option<TimgWdtClockConfig>,
623        new_config: TimgWdtClockConfig,
624    ) {
625        let timg = match self {
626            TimgInstance::Timg0 => 0,
627            TimgInstance::Timg1 => 1,
628        };
629        PCR::regs()
630            .timergroup(timg)
631            .wdt_clk_conf()
632            .modify(|_, w| unsafe {
633                w.wdt_clk_sel().bits(match new_config {
634                    TimgWdtClockConfig::XtalClk => 0,
635                    TimgWdtClockConfig::RcFastClk => 1,
636                    TimgWdtClockConfig::PllF80m => 2,
637                })
638            });
639    }
640}
641
642impl UartInstance {
643    // UART_FUNCTION_CLOCK
644
645    fn enable_function_clock_impl(self, _clocks: &mut ClockTree, en: bool) {
646        let uart = match self {
647            UartInstance::Uart0 => {
648                // Disabling this prevents the device from booting
649                // TODO: https://github.com/esp-rs/esp-hal/issues/4952
650                return;
651            }
652            UartInstance::Uart1 => 1,
653        };
654        PCR::regs()
655            .uart(uart)
656            .clk_conf()
657            .modify(|_, w| w.sclk_en().bit(en));
658    }
659
660    fn configure_function_clock_impl(
661        self,
662        _clocks: &mut ClockTree,
663        _old_config: Option<UartFunctionClockConfig>,
664        new_config: UartFunctionClockConfig,
665    ) {
666        PCR::regs()
667            .uart(match self {
668                UartInstance::Uart0 => 0,
669                UartInstance::Uart1 => 1,
670            })
671            .clk_conf()
672            .modify(|_, w| unsafe {
673                w.sclk_sel().bits(match new_config.sclk {
674                    UartFunctionClockSclk::Xtal => 0,
675                    UartFunctionClockSclk::RcFast => 1,
676                    UartFunctionClockSclk::PllF80m => 2,
677                });
678                w.sclk_div_a().bits(0);
679                w.sclk_div_b().bits(0);
680                w.sclk_div_num().bits(new_config.div_num as _);
681                w
682            });
683    }
684
685    // UART_BAUD_RATE_GENERATOR
686
687    fn enable_baud_rate_generator_impl(self, _clocks: &mut ClockTree, _en: bool) {
688        // Nothing to do.
689    }
690
691    fn configure_baud_rate_generator_impl(
692        self,
693        _clocks: &mut ClockTree,
694        _old_config: Option<UartBaudRateGeneratorConfig>,
695        new_config: UartBaudRateGeneratorConfig,
696    ) {
697        let regs = match self {
698            UartInstance::Uart0 => UART0::regs(),
699            UartInstance::Uart1 => UART1::regs(),
700        };
701        regs.clkdiv().write(|w| unsafe {
702            w.clkdiv().bits(new_config.integral as _);
703            w.frag().bits(new_config.fractional as _)
704        });
705    }
706}