1#![allow(clippy::from_over_into)]
8
9use atsamd_hal_macros::{hal_cfg, hal_macro_helper};
10
11use fugit::RateExtU32;
12
13use crate::pac::gclk::clkctrl::Genselect::*;
14use crate::pac::gclk::clkctrl::Idselect::*;
15use crate::pac::gclk::genctrl::Srcselect::*;
16use crate::pac::{self, Gclk, Nvmctrl, Pm, Sysctrl};
17use crate::time::Hertz;
18
19pub type ClockId = pac::gclk::clkctrl::Idselect;
20pub type ClockGenId = pac::gclk::clkctrl::Genselect;
21pub type ClockSource = pac::gclk::genctrl::Srcselect;
22
23#[derive(Clone, Copy)]
30pub struct GClock {
31    gclk: ClockGenId,
32    freq: Hertz,
33}
34
35impl Into<Hertz> for GClock {
36    fn into(self) -> Hertz {
37        self.freq
38    }
39}
40
41struct State {
42    gclk: Gclk,
43}
44
45impl State {
46    fn reset_gclk(&mut self) {
47        self.gclk.ctrl().write(|w| w.swrst().set_bit());
48        while self.gclk.ctrl().read().swrst().bit_is_set()
49            || self.gclk.status().read().syncbusy().bit_is_set()
50        {}
51    }
52
53    fn wait_for_sync(&mut self) {
54        while self.gclk.status().read().syncbusy().bit_is_set() {}
55    }
56
57    fn set_gclk_divider_and_source(
58        &mut self,
59        gclk: ClockGenId,
60        divider: u16,
61        src: ClockSource,
62        improve_duty_cycle: bool,
63    ) {
64        let mut divisor_invalid = false;
67        if gclk == Gclk1 {
68            if divider as u32 >= 2_u32.pow(16) {
69                divisor_invalid = true;
70            }
71        } else if gclk == Gclk2 {
72            if divider >= 2_u16.pow(5) {
73                divisor_invalid = true;
74            }
75        } else if divider >= 2_u16.pow(8) {
76            divisor_invalid = true;
77        }
78        if divisor_invalid {
79            panic!("invalid divisor {} for Gclk {}", divider, gclk as u8);
80        }
81
82        self.gclk.gendiv().write(|w| unsafe {
83            w.id().bits(u8::from(gclk));
84            w.div().bits(divider)
85        });
86        self.wait_for_sync();
87
88        self.gclk.genctrl().write(|w| unsafe {
89            w.id().bits(u8::from(gclk));
90            w.src().bits(u8::from(src));
91            w.divsel().clear_bit();
93            w.idc().bit(improve_duty_cycle);
94            w.genen().set_bit();
95            w.oe().set_bit()
96        });
97        self.wait_for_sync();
98    }
99
100    fn enable_clock_generator(&mut self, clock: ClockId, generator: ClockGenId) {
101        self.gclk.clkctrl().write(|w| unsafe {
102            w.id().bits(u8::from(clock));
103            w.r#gen().bits(u8::from(generator));
104            w.clken().set_bit()
105        });
106        self.wait_for_sync();
107    }
108
109    fn configure_standby(&mut self, gclk: ClockGenId, enable: bool) {
110        unsafe {
114            let genctrl_ptr_u8: *mut u8 = self.gclk.genctrl().as_ptr() as *mut u8;
115            *genctrl_ptr_u8 = u8::from(gclk);
116        }
117        self.wait_for_sync();
118
119        self.gclk.genctrl().modify(|_, w| w.runstdby().bit(enable));
121        self.wait_for_sync();
122    }
123}
124
125pub struct GenericClockController {
133    state: State,
134    gclks: [Hertz; 8],
135    used_clocks: u64,
136}
137
138impl GenericClockController {
139    pub fn with_internal_32kosc(
142        gclk: Gclk,
143        pm: &mut Pm,
144        sysctrl: &mut Sysctrl,
145        nvmctrl: &mut Nvmctrl,
146    ) -> Self {
147        Self::new_48mhz_from_32khz(gclk, pm, sysctrl, nvmctrl, false)
148    }
149
150    pub fn with_external_32kosc(
153        gclk: Gclk,
154        pm: &mut Pm,
155        sysctrl: &mut Sysctrl,
156        nvmctrl: &mut Nvmctrl,
157    ) -> Self {
158        Self::new_48mhz_from_32khz(gclk, pm, sysctrl, nvmctrl, true)
159    }
160
161    #[hal_macro_helper]
162    fn new_48mhz_from_32khz(
163        gclk: Gclk,
164        pm: &mut Pm,
165        sysctrl: &mut Sysctrl,
166        nvmctrl: &mut Nvmctrl,
167        use_external_crystal: bool,
168    ) -> Self {
169        let mut state = State { gclk };
170
171        set_flash_to_half_auto_wait_state(nvmctrl);
172        #[hal_cfg("clock-d21")]
173        set_flash_manual_write(nvmctrl);
174        enable_gclk_apb(pm);
175        if use_external_crystal {
176            enable_external_32kosc(sysctrl);
177        } else {
178            enable_internal_32kosc(sysctrl);
179        }
180
181        state.reset_gclk();
182
183        if use_external_crystal {
185            state.set_gclk_divider_and_source(Gclk1, 1, Xosc32k, false);
186        } else {
187            state.set_gclk_divider_and_source(Gclk1, 1, Osc32k, false);
188        }
189
190        state.enable_clock_generator(Dfll48, Gclk1);
192        configure_and_enable_dfll48m(sysctrl, use_external_crystal);
194        state.set_gclk_divider_and_source(Gclk0, 1, Dfll48m, true);
196        sysctrl.osc8m().modify(|_, w| {
200            w.presc()._0();
201            w.ondemand().clear_bit()
202        });
203        pm.cpusel().write(|w| w.cpudiv().div1());
204        pm.apbasel().write(|w| w.apbadiv().div1());
205        pm.apbbsel().write(|w| w.apbbdiv().div1());
206        pm.apbcsel().write(|w| w.apbcdiv().div1());
207
208        Self {
209            state,
210            gclks: [
211                OSC48M_FREQ,
212                OSC32K_FREQ,
213                0.Hz(),
214                0.Hz(),
215                0.Hz(),
216                0.Hz(),
217                0.Hz(),
218                0.Hz(),
219            ],
220            used_clocks: 1u64 << u8::from(ClockId::Dfll48),
221        }
222    }
223
224    #[hal_macro_helper]
227    pub fn with_internal_8mhz(
228        gclk: Gclk,
229        pm: &mut Pm,
230        sysctrl: &mut Sysctrl,
231        nvmctrl: &mut Nvmctrl,
232    ) -> Self {
233        let mut state = State { gclk };
234
235        #[hal_cfg("clock-d21")]
237        set_flash_manual_write(nvmctrl);
238
239        #[hal_cfg("clock-d11")]
241        let _ = nvmctrl;
242
243        enable_gclk_apb(pm);
244
245        state.reset_gclk();
246
247        state.set_gclk_divider_and_source(Gclk0, 1, Osc8m, false);
249
250        sysctrl.osc8m().modify(|_, w| {
252            w.presc()._0();
253            w.ondemand().clear_bit()
254        });
255        pm.cpusel().write(|w| w.cpudiv().div1());
256        pm.apbasel().write(|w| w.apbadiv().div1());
257        pm.apbbsel().write(|w| w.apbbdiv().div1());
258        pm.apbcsel().write(|w| w.apbcdiv().div1());
259
260        Self {
261            state,
262            gclks: [
263                OSC8M_FREQ,
264                0.Hz(),
265                0.Hz(),
266                0.Hz(),
267                0.Hz(),
268                0.Hz(),
269                0.Hz(),
270                0.Hz(),
271            ],
272            used_clocks: 0,
273        }
274    }
275
276    pub fn gclk0(&mut self) -> GClock {
278        GClock {
279            gclk: Gclk0,
280            freq: self.gclks[0],
281        }
282    }
283
284    pub fn gclk1(&mut self) -> GClock {
286        GClock {
287            gclk: Gclk1,
288            freq: self.gclks[1],
289        }
290    }
291
292    pub fn get_gclk(&mut self, gclk: ClockGenId) -> Option<GClock> {
296        let idx = u8::from(gclk) as usize;
297        if self.gclks[idx].to_Hz() == 0 {
298            None
299        } else {
300            Some(GClock {
301                gclk,
302                freq: self.gclks[idx],
303            })
304        }
305    }
306
307    pub fn configure_gclk_divider_and_source(
317        &mut self,
318        gclk: ClockGenId,
319        divider: u16,
320        src: ClockSource,
321        improve_duty_cycle: bool,
322    ) -> Option<GClock> {
323        let idx = u8::from(gclk) as usize;
324        if self.gclks[idx].to_Hz() != 0 {
325            return None;
326        }
327        self.state
328            .set_gclk_divider_and_source(gclk, divider, src, improve_duty_cycle);
329        let freq: Hertz = match src {
330            Xosc32k | Osc32k | Osculp32k => OSC32K_FREQ,
331            Gclkgen1 => self.gclks[1],
332            Osc8m => OSC8M_FREQ,
333            Dfll48m => OSC48M_FREQ,
334            Dpll96m => 96.MHz(),
335            Gclkin | Xosc => unimplemented!(),
336        };
337        self.gclks[idx] = freq / divider as u32;
338        Some(GClock { gclk, freq })
339    }
340
341    pub fn configure_standby(&mut self, gclk: ClockGenId, enable: bool) {
343        self.state.configure_standby(gclk, enable)
344    }
345}
346
347macro_rules! clock_generator {
348    ($(($id:ident, $Type:ident, $clock:ident),)+) => {
349
350$(
351#[derive(Debug)]
360pub struct $Type {
361    freq: Hertz,
362}
363
364impl $Type {
365    pub fn freq(&self) -> Hertz {
367        self.freq
368    }
369}
370impl Into<Hertz> for $Type {
371    fn into(self) -> Hertz {
372        self.freq
373    }
374}
375)+
376
377impl GenericClockController {
378    $(
379    pub fn $id(&mut self, generator: &GClock) -> Option<$Type> {
393        let bits: u64 = 1<<u8::from(ClockId::$clock) as u64;
394        if (self.used_clocks & bits) != 0 {
395            return None;
396        }
397        self.used_clocks |= bits;
398
399        self.state.enable_clock_generator(ClockId::$clock, generator.gclk);
400        let freq = self.gclks[u8::from(generator.gclk) as usize];
401        Some($Type{freq})
402    }
403    )+
404}
405    }
406}
407
408#[hal_cfg("clock-d11")]
410clock_generator!(
411    (tcc0, Tcc0Clock, Tcc0),
412    (tc1_tc2, Tc1Tc2Clock, Tc1Tc2),
413    (sercom0_core, Sercom0CoreClock, Sercom0Core),
414    (sercom1_core, Sercom1CoreClock, Sercom1Core),
415    (sercom2_core, Sercom2CoreClock, Sercom2Core),
416    (rtc, RtcClock, Rtc),
417    (adc, AdcClock, Adc),
418    (wdt, WdtClock, Wdt),
419    (eic, EicClock, Eic),
420    (usb, UsbClock, Usb),
421    (evsys0, Evsys0Clock, Evsys0),
422    (evsys1, Evsys1Clock, Evsys1),
423    (evsys2, Evsys2Clock, Evsys2),
424    (evsys3, Evsys3Clock, Evsys3),
425    (evsys4, Evsys4Clock, Evsys4),
426    (evsys5, Evsys5Clock, Evsys5),
427    (ac_ana, AcAnaClock, AcAna),
428    (ac_dig, AcDigClock, AcDig),
429    (dac, DacClock, Dac),
430);
431#[hal_cfg("clock-d21")]
433clock_generator!(
434    (tcc0_tcc1, Tcc0Tcc1Clock, Tcc0Tcc1),
435    (tcc2_tc3, Tcc2Tc3Clock, Tcc2Tc3),
436    (tc4_tc5, Tc4Tc5Clock, Tc4Tc5),
437    (tc6_tc7, Tc6Tc7Clock, Tc6Tc7),
438    (sercom0_core, Sercom0CoreClock, Sercom0Core),
439    (sercom1_core, Sercom1CoreClock, Sercom1Core),
440    (sercom2_core, Sercom2CoreClock, Sercom2Core),
441    (sercom3_core, Sercom3CoreClock, Sercom3Core),
442    (sercom4_core, Sercom4CoreClock, Sercom4Core),
443    (sercom5_core, Sercom5CoreClock, Sercom5Core),
444    (usb, UsbClock, Usb),
445    (rtc, RtcClock, Rtc),
446    (adc, AdcClock, Adc),
447    (wdt, WdtClock, Wdt),
448    (eic, EicClock, Eic),
449    (evsys0, Evsys0Clock, Evsys0),
450    (evsys1, Evsys1Clock, Evsys1),
451    (evsys2, Evsys2Clock, Evsys2),
452    (evsys3, Evsys3Clock, Evsys3),
453    (evsys4, Evsys4Clock, Evsys4),
454    (evsys5, Evsys5Clock, Evsys5),
455    (evsys6, Evsys6Clock, Evsys6),
456    (evsys7, Evsys7Clock, Evsys7),
457    (evsys8, Evsys8Clock, Evsys8),
458    (evsys9, Evsys9Clock, Evsys9),
459    (evsys10, Evsys10Clock, Evsys10),
460    (evsys11, Evsys11Clock, Evsys11),
461    (ac_ana, AcAnaClock, AcAna),
462    (ac_dig, AcDigClock, AcDig),
463    (dac, DacClock, Dac),
464    (i2s0, I2S0Clock, I2s0),
465    (i2s1, I2S1Clock, I2s1),
466);
467
468pub const OSC48M_FREQ: Hertz = Hertz::Hz(48_000_000);
470pub const OSC8M_FREQ: Hertz = Hertz::Hz(8_000_000);
472pub const OSC32K_FREQ: Hertz = Hertz::Hz(32_768);
474
475fn set_flash_to_half_auto_wait_state(nvmctrl: &mut Nvmctrl) {
476    nvmctrl.ctrlb().modify(|_, w| w.rws().half());
477}
478
479#[hal_cfg("clock-d21")]
481fn set_flash_manual_write(nvmctrl: &mut Nvmctrl) {
482    nvmctrl.ctrlb().modify(|_, w| w.manw().set_bit());
483}
484
485fn enable_gclk_apb(pm: &mut Pm) {
486    pm.apbamask().modify(|_, w| w.gclk_().set_bit());
487}
488
489pub fn enable_internal_32kosc(sysctrl: &mut Sysctrl) {
491    let calibration = super::calibration::osc32k_cal();
492    sysctrl.osc32k().write(|w| {
493        unsafe {
494            w.ondemand().clear_bit();
495            w.calib().bits(calibration);
496            w.startup().bits(6);
498        }
499        w.en32k().set_bit();
500        w.enable().set_bit();
501        w.runstdby().set_bit()
502    });
503    while sysctrl.pclksr().read().osc32krdy().bit_is_clear() {
504        }
506}
507
508pub fn enable_external_32kosc(sysctrl: &mut Sysctrl) {
510    sysctrl.xosc32k().modify(|_, w| {
511        unsafe {
512            w.startup().bits(6);
514        }
515        w.ondemand().clear_bit();
516        w.en32k().set_bit();
518        w.xtalen().set_bit();
520        w.runstdby().set_bit()
521    });
522    sysctrl.xosc32k().modify(|_, w| w.enable().set_bit());
523    while sysctrl.pclksr().read().xosc32krdy().bit_is_clear() {
524        }
526}
527
528fn wait_for_dfllrdy(sysctrl: &mut Sysctrl) {
529    while sysctrl.pclksr().read().dfllrdy().bit_is_clear() {}
530}
531
532#[hal_macro_helper]
534fn configure_and_enable_dfll48m(sysctrl: &mut Sysctrl, use_external_crystal: bool) {
535    sysctrl.dfllctrl().write(|w| w.ondemand().clear_bit());
540    wait_for_dfllrdy(sysctrl);
541
542    if use_external_crystal {
543        sysctrl.dfllmul().write(|w| unsafe {
544            w.cstep().bits(31);
545            w.fstep().bits(511);
546            w.mul().bits(((48_000_000u32 + 32768 / 2) / 32768) as u16)
548        });
549
550        sysctrl.dfllctrl().write(|w| {
552            w.ondemand().clear_bit();
554
555            w.mode().set_bit();
557
558            w.waitlock().set_bit();
559
560            w.qldis().set_bit()
562        });
563    } else {
564        let coarse = super::calibration::dfll48m_coarse_cal();
566        let fine = 0x1ff;
567
568        sysctrl.dfllval().write(|w| unsafe {
569            w.coarse().bits(coarse);
570            w.fine().bits(fine)
571        });
572
573        sysctrl.dfllmul().write(|w| unsafe {
574            w.cstep().bits(coarse / 4);
575            w.fstep().bits(10);
576            w.mul().bits((48_000_000u32 / 1000) as u16)
578        });
579
580        sysctrl.dfllctrl().write(|w| {
582            w.ondemand().clear_bit();
584
585            w.mode().set_bit();
587
588            w.ccdis().set_bit();
590
591            w.usbcrm().set_bit();
593
594            w.bplckc().set_bit()
596        });
597    }
598
599    wait_for_dfllrdy(sysctrl);
600
601    sysctrl.dfllctrl().modify(|_, w| w.enable().set_bit());
603
604    #[hal_cfg("clock-d21")]
605    if use_external_crystal {
606        while sysctrl.pclksr().read().dflllckc().bit_is_clear()
608            || sysctrl.pclksr().read().dflllckf().bit_is_clear()
609        {}
610    }
611
612    wait_for_dfllrdy(sysctrl);
613}