atsamd_hal/peripherals/clock/d5x/v2/
xosc32k.rs

1//! # External, 32 kHz crystal oscillator controller
2//!
3//! ## Overview
4//!
5//! The `xosc32k` module provides access to the 32 kHz external crystal
6//! oscillator controller (XOSC32K) within the `OSC32KCTRL` peripheral.
7//!
8//! The peripheral can operate in two [`Mode`]s. It can accept an external
9//! clock, or it can interface with an crystal oscillator. In both cases, the
10//! clock must be 32,768 Hz.
11//!
12//! When used with an external clock, only one GPIO [`Pin`] is required, but
13//! when used with a crystal oscillator, two GPIO `Pin`s are required. The
14//! [`XIn32`] `Pin` is used in both `Mode`s, while the [`XOut32`] `Pin` is only
15//! used in [`CrystalMode`].
16//!
17//! ## Clock tree structure
18//!
19//! The `XOSC32K` clock is unlike most other clocks, because it has two separate
20//! outputs, one at 32 kHz and another divided down to 1 kHz. Moreover, none,
21//! either or both of these outputs can be enabled at any given time.
22//!
23//! We can see, then, that the `XOSC32K` peripheral forms its own, miniature
24//! clock tree. There is a 1:N producer clock that must be enabled first; and
25//! there are two possible consumer clocks that can be independently and
26//! optionally enabled. In fact, this structure is illustrated by the `XOSC32K`
27//! register, which has three different enable bits: `ENABLE`, `EN32K` and
28//! `EN1K`.
29//!
30//! To represent this structure in the type system, we divide the `XOSC32K`
31//! peripheral into these three clocks. Users start by enabling the
32//! [`Xosc32kBase`] clock, which corresponds to setting the `XOSC32K` register
33//! `ENABLE` bit. The call to [`Xosc32kBase::enable`] returns a 1:N [`Enabled`]
34//! clock [`Source`], which can be consumed by both the [`Xosc32k`] and
35//! [`Xosc1k`] clocks. Enabling either of these two clocks will [`Increment`]
36//! the [`EnabledXosc32kBase`] counter, preventing it from being disabled.
37//! Note that `Xosc32k` and `Xosc1k` are themselves 1:N clocks as well.
38//!
39//! ## Clock failure detection and write lock
40//!
41//! Like the [`Xosc`] clocks, the XOSC32K peripheral also has clock failure
42//! detection. However, unlike the `XOSCCTRL` registers, the `XOSC32K` register
43//! has a dedicated write lock bit that will freeze its configuration until the
44//! next power-on reset.
45//!
46//! While `Xosc` clock failure detection is configured directly in the
47//! `XOSCCTRL` register, the XOSC32K peripheral has a separate, dedicated
48//! clock failure detection register (`Cfdctrl`). This difference likely exists
49//! to provide control of clock failure detection *after* write lock has been
50//! enabled.
51//!
52//! In this module, write lock is implemented by simply dropping the
53//! [`Xosc32kBase`] clock, which prevents any further access to the `XOSC32K`
54//! register. Thus, to allow control of clock failure detection in the presence
55//! of write lock, we provide a dedicated [`Xosc32kCfd`] interface, which has
56//! exclusive control over the `Cfdctrl` register.
57//!
58//! ## Example
59//!
60//! Creating and configuring the XOSC32K clocks proceeds according to the
61//! principles outlined in the [`clock` module documentation]. It is best shown
62//! with an example.
63//!
64//! Let's start by using [`clock_system_at_reset`] to access the HAL clocking
65//! structs. We'll also need access to the GPIO [`Pins`].
66//!
67//! ```no_run
68//! use atsamd_hal::{
69//!     clock::v2::{
70//!         clock_system_at_reset,
71//!         osculp32k::OscUlp32k,
72//!         xosc32k::{
73//!             ControlGainMode, SafeClockDiv, StartUpDelay, Xosc1k, Xosc32k, Xosc32kBase,
74//!             Xosc32kCfd,
75//!         },
76//!     },
77//!     gpio::Pins,
78//!     pac::Peripherals,
79//! };
80//! let mut pac = Peripherals::take().unwrap();
81//! let pins = Pins::new(pac.port);
82//! let (buses, clocks, tokens) = clock_system_at_reset(
83//!     pac.oscctrl,
84//!     pac.osc32kctrl,
85//!     pac.gclk,
86//!     pac.mclk,
87//!     &mut pac.nvmctrl,
88//! );
89//! ```
90//!
91//! Next, we create the [`Xosc32kBase`] clock from a 32 kHz oscillator using its
92//! corresponding [`Xosc32kBaseToken`] and the [`XIn32`] and [`XOut32`] `Pin`s.
93//! We then set the delay before the clock is unmasked by providing a desired
94//! [`StartUpDelay`]. Finally, we select a [`ControlGainMode`] for the crystal
95//! before enabling it.
96//!
97//! ```no_run
98//! # use atsamd_hal::{
99//! #     clock::v2::{
100//! #         clock_system_at_reset,
101//! #         osculp32k::OscUlp32k,
102//! #         xosc32k::{
103//! #             ControlGainMode, SafeClockDiv, StartUpDelay, Xosc1k, Xosc32k, Xosc32kBase,
104//! #             Xosc32kCfd,
105//! #         },
106//! #     },
107//! #     gpio::Pins,
108//! #     pac::Peripherals,
109//! # };
110//! # let mut pac = Peripherals::take().unwrap();
111//! # let pins = Pins::new(pac.port);
112//! # let (buses, clocks, tokens) = clock_system_at_reset(
113//! #     pac.oscctrl,
114//! #     pac.osc32kctrl,
115//! #     pac.gclk,
116//! #     pac.mclk,
117//! #     &mut pac.nvmctrl,
118//! # );
119//! let xosc32k_base = Xosc32kBase::from_crystal(tokens.xosc32k.base, pins.pa00, pins.pa01)
120//!     .start_up_delay(StartUpDelay::Delay1s)
121//!     .control_gain_mode(ControlGainMode::HighSpeed)
122//!     .enable();
123//! ```
124//!
125//! At this point, we opt to wait until the `Xosc32kBase` oscillator `is_ready`
126//! and stable.
127//!
128//! ```no_run
129//! # use atsamd_hal::{
130//! #     clock::v2::{
131//! #         clock_system_at_reset,
132//! #         osculp32k::OscUlp32k,
133//! #         xosc32k::{
134//! #             ControlGainMode, SafeClockDiv, StartUpDelay, Xosc1k, Xosc32k, Xosc32kBase,
135//! #             Xosc32kCfd,
136//! #         },
137//! #     },
138//! #     gpio::Pins,
139//! #     pac::Peripherals,
140//! # };
141//! # let mut pac = Peripherals::take().unwrap();
142//! # let pins = Pins::new(pac.port);
143//! # let (buses, clocks, tokens) = clock_system_at_reset(
144//! #     pac.oscctrl,
145//! #     pac.osc32kctrl,
146//! #     pac.gclk,
147//! #     pac.mclk,
148//! #     &mut pac.nvmctrl,
149//! # );
150//! # let xosc32k_base = Xosc32kBase::from_crystal(tokens.xosc32k.base, pins.pa00, pins.pa01)
151//! #     .start_up_delay(StartUpDelay::Delay1s)
152//! #     .control_gain_mode(ControlGainMode::HighSpeed)
153//! #     .enable();
154//! while !xosc32k_base.is_ready() {}
155//! ```
156//!
157//! With the [`EnabledXosc32kBase`] clock in hand, we can enable the [`Xosc1k`]
158//! and [`Xosc32k`], each of which [`Increment`]s the [`Enabled`] counter.
159//! Once we are satisfied with the configuration, we can call `write_lock` to
160//! lock the XOSC32K configuration at the hardware level. Doing so also consumes
161//! the `EnabledXosc32kBase` clock, which eliminates any ability to change the
162//! configuration at the API level.
163//!
164//! ```no_run
165//! # use atsamd_hal::{
166//! #     clock::v2::{
167//! #         clock_system_at_reset,
168//! #         osculp32k::OscUlp32k,
169//! #         xosc32k::{
170//! #             ControlGainMode, SafeClockDiv, StartUpDelay, Xosc1k, Xosc32k, Xosc32kBase,
171//! #             Xosc32kCfd,
172//! #         },
173//! #     },
174//! #     gpio::Pins,
175//! #     pac::Peripherals,
176//! # };
177//! # let mut pac = Peripherals::take().unwrap();
178//! # let pins = Pins::new(pac.port);
179//! # let (buses, clocks, tokens) = clock_system_at_reset(
180//! #     pac.oscctrl,
181//! #     pac.osc32kctrl,
182//! #     pac.gclk,
183//! #     pac.mclk,
184//! #     &mut pac.nvmctrl,
185//! # );
186//! # let xosc32k_base = Xosc32kBase::from_crystal(tokens.xosc32k.base, pins.pa00, pins.pa01)
187//! #     .start_up_delay(StartUpDelay::Delay1s)
188//! #     .control_gain_mode(ControlGainMode::HighSpeed)
189//! #     .enable();
190//! # while !xosc32k_base.is_ready() {}
191//! let (xosc1k, xosc32k_base) = Xosc1k::enable(tokens.xosc32k.xosc1k, xosc32k_base);
192//! let (xosc32k, xosc32k_base) = Xosc32k::enable(tokens.xosc32k.xosc32k, xosc32k_base);
193//! xosc32k_base.write_lock();
194//! ```
195//!
196//! However, while we have locked the XOSC32K configuration, we still want to
197//! enable clock failure detection, which will continuously monitor the clock
198//! and switch to a safe, backup clock if necessary.
199//!
200//! To do so, we must first enable the backup clock, which, for the XOSC32K, is
201//! the [`OscUlp32k`]. The OSCULP32K peripheral has a nearly identical structure
202//! to the XOSC32K; we create an [`EnabledOscUlp32k`] from the
203//! [`EnabledOscUlp32kBase`] clock and the corresponding [`OscUlp32kToken`].
204//!
205//! Upon creation of the [`Xosc32kCfd`] struct, we register it as a consumer of
206//! the `EnabledOscUlp32k`, which will `Increment` its `Counter` as well. When
207//! creating the safe clock, the `OscUlp32k` can be optionally divided by two,
208//! which is selected with [`SafeClockDiv`].
209//!
210//! ```no_run
211//! # use atsamd_hal::{
212//! #     clock::v2::{
213//! #         clock_system_at_reset,
214//! #         osculp32k::OscUlp32k,
215//! #         xosc32k::{
216//! #             ControlGainMode, SafeClockDiv, StartUpDelay, Xosc1k, Xosc32k, Xosc32kBase,
217//! #             Xosc32kCfd,
218//! #         },
219//! #     },
220//! #     gpio::Pins,
221//! #     pac::Peripherals,
222//! # };
223//! # let mut pac = Peripherals::take().unwrap();
224//! # let pins = Pins::new(pac.port);
225//! # let (buses, clocks, tokens) = clock_system_at_reset(
226//! #     pac.oscctrl,
227//! #     pac.osc32kctrl,
228//! #     pac.gclk,
229//! #     pac.mclk,
230//! #     &mut pac.nvmctrl,
231//! # );
232//! # let xosc32k_base = Xosc32kBase::from_crystal(tokens.xosc32k.base, pins.pa00, pins.pa01)
233//! #     .start_up_delay(StartUpDelay::Delay1s)
234//! #     .control_gain_mode(ControlGainMode::HighSpeed)
235//! #     .enable();
236//! # while !xosc32k_base.is_ready() {}
237//! # let (xosc1k, xosc32k_base) = Xosc1k::enable(tokens.xosc32k.xosc1k, xosc32k_base);
238//! # let (xosc32k, xosc32k_base) = Xosc32k::enable(tokens.xosc32k.xosc32k, xosc32k_base);
239//! # xosc32k_base.write_lock();
240//! let (osculp32k, osculp32k_base) =
241//!     OscUlp32k::enable(tokens.osculp32k.osculp32k, clocks.osculp32k_base);
242//! let (mut cfd, osculp32k) =
243//!     Xosc32kCfd::enable(tokens.xosc32k.cfd, osculp32k, SafeClockDiv::Div1);
244//! ```
245//!
246//! Finally, with the clock failure detection interface in hand, we can do
247//! things like check if the XOSC32K [`has_failed`] or if it [`is_switched`] to
248//! the safe clock. If we are able to recover from a clock failure, we can even
249//! [`switch_back`] to the crystal oscillator.
250//!
251//! ```no_run
252//! # use atsamd_hal::{
253//! #     clock::v2::{
254//! #         clock_system_at_reset,
255//! #         osculp32k::OscUlp32k,
256//! #         xosc32k::{
257//! #             ControlGainMode, SafeClockDiv, StartUpDelay, Xosc1k, Xosc32k, Xosc32kBase,
258//! #             Xosc32kCfd,
259//! #         },
260//! #     },
261//! #     gpio::Pins,
262//! #     pac::Peripherals,
263//! # };
264//! # let mut pac = Peripherals::take().unwrap();
265//! # let pins = Pins::new(pac.port);
266//! # let (buses, clocks, tokens) = clock_system_at_reset(
267//! #     pac.oscctrl,
268//! #     pac.osc32kctrl,
269//! #     pac.gclk,
270//! #     pac.mclk,
271//! #     &mut pac.nvmctrl,
272//! # );
273//! # let xosc32k_base = Xosc32kBase::from_crystal(tokens.xosc32k.base, pins.pa00, pins.pa01)
274//! #     .start_up_delay(StartUpDelay::Delay1s)
275//! #     .control_gain_mode(ControlGainMode::HighSpeed)
276//! #     .enable();
277//! # while !xosc32k_base.is_ready() {}
278//! # let (xosc1k, xosc32k_base) = Xosc1k::enable(tokens.xosc32k.xosc1k, xosc32k_base);
279//! # let (xosc32k, xosc32k_base) = Xosc32k::enable(tokens.xosc32k.xosc32k, xosc32k_base);
280//! # xosc32k_base.write_lock();
281//! # let (osculp32k, osculp32k_base) =
282//! #     OscUlp32k::enable(tokens.osculp32k.osculp32k, clocks.osculp32k_base);
283//! # let (mut cfd, osculp32k) =
284//! #     Xosc32kCfd::enable(tokens.xosc32k.cfd, osculp32k, SafeClockDiv::Div1);
285//! if cfd.has_failed() && cfd.is_switched() {
286//!     cfd.switch_back();
287//! }
288//! ```
289//!
290//! The complete example is provided below.
291//!
292//! ```no_run
293//! use atsamd_hal::{
294//!     clock::v2::{
295//!         clock_system_at_reset,
296//!         osculp32k::OscUlp32k,
297//!         xosc32k::{
298//!             ControlGainMode, SafeClockDiv, StartUpDelay, Xosc1k, Xosc32k, Xosc32kBase,
299//!             Xosc32kCfd,
300//!         },
301//!     },
302//!     gpio::Pins,
303//!     pac::Peripherals,
304//! };
305//! let mut pac = Peripherals::take().unwrap();
306//! let pins = Pins::new(pac.port);
307//! let (buses, clocks, tokens) = clock_system_at_reset(
308//!     pac.oscctrl,
309//!     pac.osc32kctrl,
310//!     pac.gclk,
311//!     pac.mclk,
312//!     &mut pac.nvmctrl,
313//! );
314//! let xosc32k_base = Xosc32kBase::from_crystal(tokens.xosc32k.base, pins.pa00, pins.pa01)
315//!     .start_up_delay(StartUpDelay::Delay1s)
316//!     .control_gain_mode(ControlGainMode::HighSpeed)
317//!     .enable();
318//! while !xosc32k_base.is_ready() {}
319//! let (xosc1k, xosc32k_base) = Xosc1k::enable(tokens.xosc32k.xosc1k, xosc32k_base);
320//! let (xosc32k, xosc32k_base) = Xosc32k::enable(tokens.xosc32k.xosc32k, xosc32k_base);
321//! xosc32k_base.write_lock();
322//! let (osculp32k, osculp32k_base) =
323//!     OscUlp32k::enable(tokens.osculp32k.osculp32k, clocks.osculp32k_base);
324//! let (mut cfd, osculp32k) =
325//!     Xosc32kCfd::enable(tokens.xosc32k.cfd, osculp32k, SafeClockDiv::Div1);
326//! if cfd.has_failed() && cfd.is_switched() {
327//!     cfd.switch_back();
328//! }
329//! ```
330//!
331//! [`clock` module documentation]: super
332//! [`Pins`]: crate::gpio::Pins
333//! [`clock_system_at_reset`]: super::clock_system_at_reset
334//! [`Xosc`]: super::xosc::Xosc
335//! [`OscUlp32k`]: super::osculp32k::OscUlp32k
336//! [`EnabledOscUlp32k`]: super::osculp32k::EnabledOscUlp32k
337//! [`OscUlp32kToken`]: super::osculp32k::OscUlp32kToken
338//! [`EnabledOscUlp32kBase`]: super::osculp32k::EnabledOscUlp32kBase
339//! [`OscUlp32k`]: super::osculp32k::OscUlp32k
340//! [`has_failed`]: Xosc32kCfd::has_failed
341//! [`is_switched`]: Xosc32kCfd::is_switched
342//! [`switch_back`]: Xosc32kCfd::switch_back
343
344use fugit::RateExtU32;
345use typenum::U0;
346
347use crate::pac::osc32kctrl::xosc32k::{Cgmselect, Startupselect};
348use crate::pac::osc32kctrl::{self, status, Cfdctrl};
349
350use crate::gpio::{FloatingDisabled, Pin, PA00, PA01};
351use crate::time::Hertz;
352use crate::typelevel::{Decrement, Increment, PrivateDecrement, PrivateIncrement, Sealed};
353
354use super::osculp32k::OscUlp32kId;
355use super::{Enabled, Source};
356
357//==============================================================================
358// Tokens
359//==============================================================================
360
361/// Singleton token that can be exchanged for [`Xosc32kBase`]
362///
363/// As explained in the [`clock` module documentation](super), instances of
364/// various `Token` types can be exchanged for actual clock types. They
365/// typically represent clocks that are disabled at power-on reset.
366///
367/// The [`Xosc32kBase`] clock is disabled at power-on reset. To use it, you must
368/// first exchange the token for an actual clock with
369/// [`Xosc32kBase::from_clock`] or [`Xosc32kBase::from_crystal`].
370pub struct Xosc32kBaseToken(());
371
372/// Singleton token that can be exchanged for [`Xosc1k`]
373///
374/// As explained in the [`clock` module documentation](super), instances of
375/// various `Token` types can be exchanged for actual clock types. They
376/// typically represent clocks that are disabled at power-on reset.
377///
378/// The [`Xosc1k`] clock is disabled at power-on reset. To use it, you must
379/// first exchange the token for an actual clock with [`Xosc1k::enable`].
380pub struct Xosc1kToken(());
381
382/// Singleton token that can be exchanged for [`Xosc32k`]
383///
384/// As explained in the [`clock` module documentation](super), instances of
385/// various `Token` types can be exchanged for actual clock types. They
386/// typically represent clocks that are disabled at power-on reset.
387///
388/// The [`Xosc32k`] clock is disabled at power-on reset. To use it, you must
389/// first exchange the token for an actual clock with [`Xosc32k::enable`].
390pub struct Xosc32kToken(());
391
392/// Singleton token that can be exchanged for [`Xosc32kCfd`]
393///
394/// As explained in the [module-level documentation](self), clock failure
395/// detection can be used even after the `XOSC32K` register has been write
396/// locked. For that reason, users control clock failure detection through the
397/// dedicated [`Xosc32kCfd`] type.
398///
399/// Clock failure detection is disabled at power-on reset. To use it, you must
400/// first enable it by exchanging the token with [`Xosc32kCfd::enable`].
401pub struct Xosc32kCfdToken(());
402
403/// Set of tokens representing the disabled XOSC32K clocks power-on reset
404pub struct Xosc32kTokens {
405    pub base: Xosc32kBaseToken,
406    pub xosc1k: Xosc1kToken,
407    pub xosc32k: Xosc32kToken,
408    pub cfd: Xosc32kCfdToken,
409}
410
411impl Xosc32kTokens {
412    /// Create the set of tokens
413    ///
414    /// # Safety
415    ///
416    /// There must never be more than one instance of these tokens at any given
417    /// time. See the notes on `Token` types and memory safety in the root of
418    /// the `clock` module for more details.
419    pub(super) unsafe fn new() -> Self {
420        Self {
421            base: Xosc32kBaseToken(()),
422            xosc1k: Xosc1kToken(()),
423            xosc32k: Xosc32kToken(()),
424            cfd: Xosc32kCfdToken(()),
425        }
426    }
427}
428
429impl Xosc32kBaseToken {
430    #[inline]
431    fn status(&self) -> status::R {
432        // Safety: We are only reading from the `STATUS` register, so there is
433        // no risk of memory corruption.
434        unsafe { (*crate::pac::Osc32kctrl::PTR).status().read() }
435    }
436
437    /// Check whether the XOSC32K is stable and ready
438    #[inline]
439    fn is_ready(&self) -> bool {
440        self.status().xosc32krdy().bit()
441    }
442
443    #[inline]
444    fn xosc32k(&self) -> &osc32kctrl::Xosc32k {
445        // Safety: The `Xosc32kBaseToken` has exclusive access to the `XOSC32K`
446        // register. See the notes on `Token` types and memory safety in the
447        // root of the `clock` module for more details.
448        unsafe { (*crate::pac::Osc32kctrl::PTR).xosc32k() }
449    }
450
451    /// Reset the XOSC32K register
452    #[inline]
453    fn reset(&mut self) {
454        self.xosc32k().reset();
455    }
456
457    /// Set most of the fields in the XOSC32K register
458    #[inline]
459    fn set_xosc32k(&mut self, settings: Settings) {
460        let xtalen = settings.mode == DynMode::CrystalMode;
461        self.xosc32k().modify(|_, w| {
462            w.cgm().variant(settings.cgm.into());
463            w.startup().variant(settings.start_up.into());
464            w.ondemand().bit(settings.on_demand);
465            w.runstdby().bit(settings.run_standby);
466            w.xtalen().bit(xtalen)
467        });
468    }
469
470    /// Disable the XOSC32K
471    #[inline]
472    fn enable(&mut self) {
473        self.xosc32k().modify(|_, w| w.enable().set_bit());
474    }
475
476    /// Disable the XOSC32K
477    #[inline]
478    fn disable(&mut self) {
479        self.xosc32k().modify(|_, w| w.enable().clear_bit());
480    }
481
482    /// Enable the 1 kHz output
483    #[inline]
484    fn enable_1k(&mut self) {
485        self.xosc32k().modify(|_, w| w.en1k().set_bit());
486    }
487
488    /// Disable the 1 kHz output
489    #[inline]
490    fn disable_1k(&mut self) {
491        self.xosc32k().modify(|_, w| w.en1k().clear_bit());
492    }
493
494    /// Enable the 32 kHz output
495    #[inline]
496    fn enable_32k(&mut self) {
497        self.xosc32k().modify(|_, w| w.en32k().set_bit());
498    }
499
500    /// Disable the 32 kHz output
501    #[inline]
502    fn disable_32k(&mut self) {
503        self.xosc32k().modify(|_, w| w.en32k().clear_bit());
504    }
505
506    /// Enable the write lock
507    #[inline]
508    fn write_lock(&mut self) {
509        self.xosc32k().modify(|_, w| w.wrtlock().set_bit());
510    }
511}
512
513impl Xosc32kCfdToken {
514    #[inline]
515    fn status(&self) -> status::R {
516        // Safety: We are only reading from the `STATUS` register, so there is
517        // no risk of memory corruption.
518        unsafe { (*crate::pac::Osc32kctrl::PTR).status().read() }
519    }
520
521    /// Check whether the XOSC32K has triggered failure detection
522    #[inline]
523    fn has_failed(&self) -> bool {
524        self.status().xosc32kfail().bit()
525    }
526
527    /// Check whether the XOSC32K has been switched to the safe clock
528    #[inline]
529    fn is_switched(&self) -> bool {
530        self.status().xosc32ksw().bit()
531    }
532
533    #[inline]
534    fn cfdctrl(&self) -> &Cfdctrl {
535        // Safety: The `Xosc32kCfdToken` has exclusive access to the `Cfdctrl`
536        // register. See the notes on `Token` types and memory safety in the
537        // root of the `clock` module for more details.
538        unsafe { (*crate::pac::Osc32kctrl::PTR).cfdctrl() }
539    }
540
541    /// Enable clock failure detection and set the safe clock divider
542    #[inline]
543    fn enable(&mut self, div: SafeClockDiv) {
544        self.cfdctrl().modify(|_, w| {
545            w.cfdpresc().bit(div.into());
546            w.cfden().set_bit()
547        });
548    }
549
550    /// Disable clock failure detection
551    #[inline]
552    fn disable(&mut self) {
553        self.cfdctrl().modify(|_, w| w.cfden().clear_bit());
554    }
555
556    /// Switch from the safe clock back to the XOSC32K clock/oscillator
557    ///
558    /// This bit is cleared by the hardware after successfully switching back
559    #[inline]
560    fn switch_back(&mut self) {
561        self.cfdctrl().modify(|_, w| w.swback().set_bit());
562    }
563}
564
565//==============================================================================
566// Settings
567//==============================================================================
568
569// Collection of XOSC32K register fields
570//
571// All of these fields are set in a single write to XOSC32K during the call to
572// [`Xosc32kBase::enable`]. The remaining fields are only modified after it has
573// been enabled.
574#[derive(Clone, Copy)]
575struct Settings {
576    start_up: StartUpDelay,
577    cgm: ControlGainMode,
578    on_demand: bool,
579    run_standby: bool,
580    mode: DynMode,
581}
582
583//==============================================================================
584// XIn32 & XOut32
585//==============================================================================
586
587/// Type alias for the XOSC32K input [`Pin`]
588pub type XIn32 = Pin<PA00, FloatingDisabled>;
589
590/// Type alias for the XOSC32K output [`Pin`]
591pub type XOut32 = Pin<PA01, FloatingDisabled>;
592
593//==============================================================================
594// SafeClockDiv
595//==============================================================================
596
597/// Division factor for the safe clock prescaler
598///
599/// If an XOSC32K clock failure is detected, the hardware will switch to a safe
600/// clock derived from the [`OscUlp32k`]. This enum sets the divider between it
601/// and the safe clock frequency. The divider can be 1 or 2.
602///
603///[`OscUlp32k`]: super::osculp32k::OscUlp32k
604#[repr(u8)]
605#[derive(Clone, Copy, Default, PartialEq, Eq)]
606pub enum SafeClockDiv {
607    #[default]
608    Div1,
609    Div2,
610}
611
612impl From<SafeClockDiv> for bool {
613    fn from(div: SafeClockDiv) -> Self {
614        match div {
615            SafeClockDiv::Div1 => false,
616            SafeClockDiv::Div2 => true,
617        }
618    }
619}
620
621//==============================================================================
622// StartUpDelay
623//==============================================================================
624
625/// Start up delay before continuous monitoring takes effect
626///
627/// After a hard reset or waking from sleep, the XOSC32K output will remained
628/// masked for the start up period, to ensure an unstable clock is not
629/// propagated into the digital logic.
630///
631/// The start up delay is counted using the [`OscUlp32k`] clock.
632///
633/// [`OscUlp32k`]: super::osculp32k::OscUlp32k
634#[repr(u8)]
635#[derive(Clone, Copy, Default, PartialEq, Eq)]
636pub enum StartUpDelay {
637    #[default]
638    Delay63ms,
639    Delay125ms,
640    Delay500ms,
641    Delay1s,
642    Delay2s,
643    Delay4s,
644    Delay8s,
645}
646
647impl From<StartUpDelay> for Startupselect {
648    fn from(delay: StartUpDelay) -> Self {
649        match delay {
650            StartUpDelay::Delay63ms => Startupselect::Cycle2048,
651            StartUpDelay::Delay125ms => Startupselect::Cycle4096,
652            StartUpDelay::Delay500ms => Startupselect::Cycle16384,
653            StartUpDelay::Delay1s => Startupselect::Cycle32768,
654            StartUpDelay::Delay2s => Startupselect::Cycle65536,
655            StartUpDelay::Delay4s => Startupselect::Cycle131072,
656            StartUpDelay::Delay8s => Startupselect::Cycle262144,
657        }
658    }
659}
660
661//==============================================================================
662// ControlGainMode
663//==============================================================================
664
665/// Gain mode for the XOSC32K control loop
666///
667/// The XOSC32K crystal oscillator control loop has a configurable gain to allow
668/// users to trade power for speed and stability.
669#[derive(Copy, Clone, Default, PartialEq, Eq)]
670pub enum ControlGainMode {
671    #[default]
672    Standard,
673    HighSpeed,
674}
675
676impl From<ControlGainMode> for Cgmselect {
677    fn from(cgm: ControlGainMode) -> Self {
678        match cgm {
679            ControlGainMode::Standard => Cgmselect::Xt,
680            ControlGainMode::HighSpeed => Cgmselect::Hs,
681        }
682    }
683}
684
685//==============================================================================
686// DynMode
687//==============================================================================
688
689/// Value-level enum identifying one of two possible XOSC32K operating modes
690///
691/// The XOSC32K clock can be sourced from either an external clock or crystal
692/// oscillator. The variants of this enum identify one of these two possible
693/// operating modes.
694///
695/// `DynMode` is the value-level equivalent of [`Mode`].
696#[derive(Clone, Copy, Default, PartialEq, Eq)]
697pub enum DynMode {
698    #[default]
699    ClockMode,
700    CrystalMode,
701}
702
703//==============================================================================
704// Mode
705//==============================================================================
706
707/// Type-level enum for the XOSC32K operation mode
708///
709/// The XOSC32K clock can be sourced from either an external clock or a crystal
710/// oscillator. This type-level `enum` provides two type-level variants,
711/// [`ClockMode`] and [`CrystalMode`], representing these operating modes.
712///
713/// `Mode` is the type-level equivalent of [`DynMode`]. See the documentation on
714/// [type-level programming] and specifically [type-level enums] for more
715/// details.
716///
717/// [type-level programming]: crate::typelevel
718/// [type-level enums]: crate::typelevel#type-level-enums
719pub trait Mode: Sealed {
720    const DYN: DynMode;
721    #[doc(hidden)]
722    type Pins;
723}
724
725/// Type-level variant of the XOSC32K operating [`Mode`]
726///
727/// In this `Mode`, the XOSC32K clock will be sourced from an external clock.
728///
729/// See the documentation on [type-level programming] and specifically
730/// [type-level enums] for more details.
731///
732/// [type-level programming]: crate::typelevel
733/// [type-level enums]: crate::typelevel#type-level-enums
734pub enum ClockMode {}
735impl Sealed for ClockMode {}
736impl Mode for ClockMode {
737    const DYN: DynMode = DynMode::ClockMode;
738    type Pins = XIn32;
739}
740
741/// Type-level variant of the XOSC32K operating [`Mode`]
742///
743/// In this `Mode`, the XOSC32K clock will be sourced from a crystal oscillator.
744///
745/// See the documentation on [type-level programming] and specifically
746/// [type-level enums] for more details.
747///
748/// [type-level programming]: crate::typelevel
749/// [type-level enums]: crate::typelevel#type-level-enums
750pub enum CrystalMode {}
751impl Sealed for CrystalMode {}
752impl Mode for CrystalMode {
753    const DYN: DynMode = DynMode::CrystalMode;
754    type Pins = (XIn32, XOut32);
755}
756
757//==============================================================================
758// Xosc32kBase
759//==============================================================================
760
761/// XOSC32K base clock, which feeds the [`Xosc1k`] and [`Xosc32k`] clocks
762///
763/// The XOSC32K peripheral has two possible clock outputs, one at 32 kHz and
764/// another at 1 kHz. This structure is represented in the type system as a set
765/// of three clocks forming a small clock tree. The [`Xosc32kBase`] clock
766/// represents the configurable base oscillator that feeds the optional
767/// [`Xosc1k`] and [`Xosc32k`] output clocks. See the
768/// [module-level documentation](super) for details and examples.
769pub struct Xosc32kBase<M: Mode> {
770    token: Xosc32kBaseToken,
771    pins: M::Pins,
772    settings: Settings,
773}
774
775/// The [`Enabled`] [`Xosc32kBase`] clock
776///
777/// As described in the [`clock` module documentation](super), the [`Enabled`]
778/// wrapper implements compile-time clock tree safety by tracking the number of
779/// clocks consuming the [`Xosc32kBase`] clock and restricts access to the
780/// underlying type to prevent misuse.
781///
782/// As with [`Enabled`], the default value for `N` is `U0`; if left unspecified,
783/// the counter is assumed to be zero.
784pub type EnabledXosc32kBase<M, N = U0> = Enabled<Xosc32kBase<M>, N>;
785
786impl Xosc32kBase<ClockMode> {
787    /// Create the [`Xosc32kBase`] clock from an external clock, taking
788    /// ownership of the [`XIn32`] [`Pin`]
789    ///
790    /// Creating an [`Xosc32kBase`] clock does not modify any of the hardware
791    /// registers. It only creates a struct to track the configuration. The
792    /// configuration data is stored until the user calls [`enable`]. At that
793    /// point, all of the registers are written according to the initialization
794    /// procedures specified in the datasheet, and an [`EnabledXosc32kBase`]
795    /// clock is returned. The `Xosc32kBase` clock is not active or useful until
796    /// that point.
797    ///
798    /// [`enable`]: Xosc32kBase::enable
799    #[inline]
800    pub fn from_clock(token: Xosc32kBaseToken, xin32: impl Into<XIn32>) -> Self {
801        let pins = xin32.into();
802        Self::new(token, pins)
803    }
804
805    /// Consume the [`Xosc32kBase`] and release the [`Xosc32kBaseToken`] and
806    /// [`XIn32`] [`Pin`]
807    #[inline]
808    pub fn free(self) -> (Xosc32kBaseToken, XIn32) {
809        (self.token, self.pins)
810    }
811}
812
813impl Xosc32kBase<CrystalMode> {
814    /// Create the [`Xosc32kBase`] clock from an external crystal oscillator,
815    /// taking ownership of the [`XIn32`] and [`XOut32`] [`Pin`]s.
816    ///
817    /// Creating an [`Xosc32kBase`] clock does not modify any of the hardware
818    /// registers. It only creates a struct to track the configuration. The
819    /// configuration data is stored until the user calls [`enable`]. At that
820    /// point, all of the registers are written according to the initialization
821    /// procedures specified in the datasheet, and an [`EnabledXosc32kBase`]
822    /// clock is returned. The `Xosc32kBase` is not active or useful until that
823    /// point.
824    ///
825    /// [`enable`]: Xosc32kBase::enable
826    #[inline]
827    pub fn from_crystal(
828        token: Xosc32kBaseToken,
829        xin32: impl Into<XIn32>,
830        xout32: impl Into<XOut32>,
831    ) -> Self {
832        let pins = (xin32.into(), xout32.into());
833        Self::new(token, pins)
834    }
835
836    /// Consume the [`Xosc32kBase`] and release the [`Xosc32kBaseToken`],
837    /// [`XIn32`] and [`XOut32`] [`Pin`]s
838    #[inline]
839    pub fn free(self) -> (Xosc32kBaseToken, XIn32, XOut32) {
840        let (xin32, xout32) = self.pins;
841        (self.token, xin32, xout32)
842    }
843
844    /// Set the crystal oscillator [`ControlGainMode`]
845    #[inline]
846    pub fn control_gain_mode(mut self, cgm: ControlGainMode) -> Self {
847        self.settings.cgm = cgm;
848        self
849    }
850}
851
852impl<M: Mode> Xosc32kBase<M> {
853    #[inline]
854    fn new(token: Xosc32kBaseToken, pins: M::Pins) -> Self {
855        let settings = Settings {
856            start_up: StartUpDelay::Delay63ms,
857            cgm: ControlGainMode::Standard,
858            on_demand: true,
859            run_standby: false,
860            mode: M::DYN,
861        };
862        Self {
863            token,
864            pins,
865            settings,
866        }
867    }
868
869    /// Set the start up delay before the [`Xosc32kBase`] clock is unmasked and
870    /// continuously monitored
871    ///
872    /// During the start up period, the [`Xosc32kBase`] clock is masked to
873    /// prevent clock instability from propagating to the digital logic. During
874    /// this time, clock failure detection is disabled.
875    #[inline]
876    pub fn start_up_delay(mut self, delay: StartUpDelay) -> Self {
877        self.settings.start_up = delay;
878        self
879    }
880
881    /// Control the XOSC32K on-demand behavior
882    ///
883    /// When the on-demand is enabled, the XOSC32K clocks will only run in Idle
884    /// or Standby sleep modes if it is requested by a peripheral. Otherwise,
885    /// its behavior is dependent on the run-standby setting.
886    #[inline]
887    pub fn on_demand(mut self, on_demand: bool) -> Self {
888        self.settings.on_demand = on_demand;
889        self
890    }
891
892    /// Control the XOSC32K behavior in Standby sleep mode
893    ///
894    /// When `RUNSTDBY` is disabled, the XOSC32K clocks will never run in
895    /// Standby sleep mode unless `ONDEMAND` is enabled and a clock is requested
896    /// by a peripheral.
897    ///
898    /// When `RUNSTDBY` is enabled, the `Xosc` will run in Standby sleep mode,
899    /// but it can still be disabled if `ONDEMAND` is enabled and a clock is not
900    /// requested.
901    #[inline]
902    pub fn run_standby(mut self, run_standby: bool) -> Self {
903        self.settings.run_standby = run_standby;
904        self
905    }
906
907    /// Freeze the XOSC32K configuration until power-on reset
908    ///
909    /// This function sets the write-lock bit, which freezes the XOSC32K
910    /// configuration at the hardware level until power-on reset. At the API
911    /// level, it also consumes and drops the [`Xosc32kBase`], which prevents
912    /// any further modifications.
913    ///
914    /// **NOTE:** Because the `Xosc32kBase` is not yet enabled, calling this
915    /// method will lock both the [`Xosc1k`] and [`Xosc32k`] in their disabled
916    /// state.
917    #[inline]
918    pub fn write_lock(mut self) {
919        self.token.write_lock();
920    }
921
922    /// Enable the [`Xosc32kBase`] clock, so that it can be used as a clock
923    /// [`Source`] for the [`Xosc1k`] and [`Xosc32k`] clocks
924    ///
925    /// As mentioned when creating a new `Xosc32kBase`, no hardware registers
926    /// are actually modified until this call. Rather, the desired configuration
927    /// is stored internally, and the `Xosc32kBase` is initialized and
928    /// configured here according to the datasheet.
929    ///
930    /// The returned value is an [`EnabledXosc32kBase`] that can be used as a
931    /// clock [`Source`] for the [`Xosc1k`] and [`Xosc32k`] clocks.
932    #[inline]
933    pub fn enable(mut self) -> EnabledXosc32kBase<M> {
934        self.token.reset();
935        self.token.set_xosc32k(self.settings);
936        self.token.enable();
937        Enabled::new(self)
938    }
939}
940
941impl<M: Mode> EnabledXosc32kBase<M> {
942    /// Disable the [`Xosc32kBase`] clock
943    ///
944    /// This method is only implemented for `N = U0`, which means the clock can
945    /// only be disabled when no other clocks consume this [`Xosc32kBase`]
946    /// clock.
947    #[inline]
948    pub fn disable(mut self) -> Xosc32kBase<M> {
949        self.0.token.disable();
950        self.0
951    }
952}
953
954impl<M: Mode, N> EnabledXosc32kBase<M, N> {
955    /// Check whether the XOSC32K is stable and ready to be used as a clock
956    /// [`Source`]
957    #[inline]
958    pub fn is_ready(&self) -> bool {
959        self.0.token.is_ready()
960    }
961
962    /// Freeze the XOSC32K configuration until power-on reset
963    ///
964    /// This function sets the write-lock bit, which freezes the XOSC32K
965    /// configuration at the hardware level until power-on reset. At the API
966    /// level, it also consumes and drops the [`Xosc32kBase`] clock, which
967    /// prevents any further modifications.
968    #[inline]
969    pub fn write_lock(mut self) {
970        self.0.token.write_lock();
971    }
972}
973
974//==============================================================================
975// Xosc32kCfd
976//==============================================================================
977
978/// Clock failure detection interface for the XOSC32K peripheral
979///
980/// The XOSC32K peripheral provides a hardware method to continuously monitor
981/// the clock to verify it is still running. In the event of a failure, the
982/// output will be switched to a "safe clock" derived from the [`OscUlp32k`].
983/// The XOSC32K peripheral provides a prescaler to optionally divide the
984/// `OscUlp32k` by two.
985///
986/// Note that clock failure is triggered when four safe clock periods pass
987/// without seeing a rising & falling edge pair on the XOSC32K clock. Once
988/// failure is detected, the corresponding bit in the `STATUS` register will
989/// go high and an interrupt will be triggered.
990///
991/// If the external clock can be fixed, the XOSC32K clock can be switched back
992/// using [`Xosc32kCfd::switch_back`].
993///
994/// Because the safe clock makes use of the `OscUlp32k`, the `Xosc32kCfd` must
995/// register as a consumer of the [`EnabledOscUlp32k`] and [`Increment`] its
996/// counter.
997///
998/// [`OscUlp32k`]: super::osculp32k::OscUlp32k
999/// [`EnabledOscUlp32k`]: super::osculp32k::EnabledOscUlp32k
1000pub struct Xosc32kCfd {
1001    token: Xosc32kCfdToken,
1002}
1003
1004impl Xosc32kCfd {
1005    /// Enable continuous monitoring of the XOSC32K for clock failure
1006    ///
1007    /// Because the safe clock makes use of the [`OscUlp32k`], the `Xosc32kCfd`
1008    /// must register as a consumer of the [`EnabledOscUlp32k`] and
1009    /// [`Increment`] its counter.
1010    ///
1011    /// [`OscUlp32k`]: super::osculp32k::OscUlp32k
1012    /// [`EnabledOscUlp32k`]: super::osculp32k::EnabledOscUlp32k
1013    #[inline]
1014    pub fn enable<S>(
1015        mut token: Xosc32kCfdToken,
1016        osc_ulp_32k: S,
1017        div: SafeClockDiv,
1018    ) -> (Xosc32kCfd, S::Inc)
1019    where
1020        S: Source<Id = OscUlp32kId> + Increment,
1021    {
1022        token.enable(div);
1023        (Self { token }, osc_ulp_32k.inc())
1024    }
1025
1026    /// Check whether the XOSC32K has triggered clock failure detection
1027    ///
1028    /// Failure is triggered when four safe clock periods pass without seeing a
1029    /// rising & falling edge pair on the XOSC32K clock.
1030    #[inline]
1031    pub fn has_failed(&self) -> bool {
1032        self.token.has_failed()
1033    }
1034
1035    /// Check whether the XOSC32K has been switched to the safe clock
1036    ///
1037    /// Returns `true` if the XOSC32K has been switched to the safe clock.
1038    #[inline]
1039    pub fn is_switched(&self) -> bool {
1040        self.token.is_switched()
1041    }
1042
1043    /// Attempt to switch from the safe clock back to the external clock
1044    ///
1045    /// This function will set the switch back bit (`SWBACK`) in the `Cfdctrl`
1046    /// register. Once the hardware has successfully switched back, this bit
1047    /// will be automatically cleared.
1048    ///
1049    /// Users can check whether switching back was successful by checking the
1050    /// `STATUS` register with [`Xosc32kCfd::is_switched`].
1051    #[inline]
1052    pub fn switch_back(&mut self) {
1053        self.token.switch_back()
1054    }
1055
1056    /// Disable continuous monitoring of the XOSC32K for clock failure
1057    ///
1058    /// Once failure monitoring is disabled, the [`OscUlp32k`] is no longer used
1059    /// as the safe clock, so the [`EnabledOscUlp32k`] counter can be
1060    /// [`Decrement`]ed.
1061    ///
1062    /// [`OscUlp32k`]: super::osculp32k::OscUlp32k
1063    /// [`EnabledOscUlp32k`]: super::osculp32k::EnabledOscUlp32k
1064    #[inline]
1065    pub fn disable<S>(mut self, osc_ulp_32k: S) -> (Xosc32kCfdToken, S::Dec)
1066    where
1067        S: Source<Id = OscUlp32kId> + Decrement,
1068    {
1069        self.token.disable();
1070        (self.token, osc_ulp_32k.dec())
1071    }
1072}
1073
1074//==============================================================================
1075// Ids
1076//==============================================================================
1077
1078/// Type representing the identity of the [`Xosc1k`] clock
1079///
1080/// See the discussion on [`Id` types](super#id-types) for more information.
1081pub enum Xosc1kId {}
1082
1083impl Sealed for Xosc1kId {}
1084
1085/// Type representing the identity of the [`Xosc32k`] clock
1086///
1087/// See the discussion on [`Id` types](super#id-types) for more information.
1088pub enum Xosc32kId {}
1089
1090impl Sealed for Xosc32kId {}
1091
1092//==============================================================================
1093// Xosc1k
1094//==============================================================================
1095
1096/// Clock representing the 1 kHz output of the [`Xosc32kBase`] clock
1097///
1098/// The XOSC32K peripheral has two possible clock outputs, one at 32 kHz and
1099/// another at 1 kHz. This structure is represented in the type system as a set
1100/// of three clocks forming a small clock tree. The [`Xosc1k`] clock is derived
1101/// from the [`Xosc32kBase`] clock. See the [module-level documentation](super)
1102/// for details and examples.
1103pub struct Xosc1k {
1104    token: Xosc1kToken,
1105}
1106
1107/// The [`Enabled`] [`Xosc1k`] clock
1108///
1109/// As described in the [`clock` module documentation](super), the [`Enabled`]
1110/// wrapper implements compile-time clock tree safety by tracking the number of
1111/// clocks consuming the [`Xosc1k`] clock and restricts access to the underlying
1112/// type to prevent misuse.
1113///
1114/// As with [`Enabled`], the default value for `N` is `U0`; if left unspecified,
1115/// the counter is assumed to be zero.
1116pub type EnabledXosc1k<N = U0> = Enabled<Xosc1k, N>;
1117
1118impl Xosc1k {
1119    /// Enable 1 kHz output from the [`Xosc32kBase`] clock
1120    ///
1121    /// This will [`Increment`] the [`EnabledXosc32kBase`] counter.
1122    #[inline]
1123    pub fn enable<M, N>(
1124        token: Xosc1kToken,
1125        mut base: EnabledXosc32kBase<M, N>,
1126    ) -> (EnabledXosc1k, EnabledXosc32kBase<M, N::Inc>)
1127    where
1128        M: Mode,
1129        N: Increment,
1130    {
1131        base.0.token.enable_1k();
1132        (Enabled::new(Self { token }), base.inc())
1133    }
1134}
1135
1136impl EnabledXosc1k {
1137    /// Disable 1 kHz output from the [`Xosc32kBase`] clock
1138    ///
1139    /// This will [`Decrement`] the [`EnabledXosc32kBase`] counter.
1140    #[inline]
1141    pub fn disable<M, N>(
1142        self,
1143        mut base: EnabledXosc32kBase<M, N>,
1144    ) -> (Xosc1kToken, EnabledXosc32kBase<M, N::Dec>)
1145    where
1146        M: Mode,
1147        N: Decrement,
1148    {
1149        base.0.token.disable_1k();
1150        (self.0.token, base.dec())
1151    }
1152}
1153
1154impl<N> Source for EnabledXosc1k<N> {
1155    type Id = Xosc1kId;
1156
1157    #[inline]
1158    fn freq(&self) -> Hertz {
1159        1024.Hz()
1160    }
1161}
1162
1163//==============================================================================
1164// Xosc32k
1165//==============================================================================
1166
1167/// Clock representing the 32 kHz output of the [`Xosc32kBase`] clock
1168///
1169/// The XOSC32K peripheral has two possible clock outputs, one at 32 kHz and
1170/// another at 1 kHz. This structure is represented in the type system as a set
1171/// of three clocks forming a small clock tree. The [`Xosc32k`] clock is derived
1172/// from the [`Xosc32kBase`] clock. See the [module-level documentation](super)
1173/// for details and examples.
1174pub struct Xosc32k {
1175    token: Xosc32kToken,
1176}
1177
1178/// The [`Enabled`] [`Xosc32k`] clock
1179///
1180/// As described in the [`clock` module documentation](super), the [`Enabled`]
1181/// wrapper implements compile-time clock tree safety by tracking the number of
1182/// clocks consuming the [`Xosc32k`] clock and restricts access to the
1183/// underlying type to prevent misuse.
1184///
1185/// As with [`Enabled`], the default value for `N` is `U0`; if left unspecified,
1186/// the counter is assumed to be zero.
1187pub type EnabledXosc32k<N = U0> = Enabled<Xosc32k, N>;
1188
1189impl Xosc32k {
1190    /// Enable 32 kHz output from the [`Xosc32kBase`] clock
1191    ///
1192    /// This will [`Increment`] the [`EnabledXosc32kBase`] counter.
1193    #[inline]
1194    pub fn enable<M, N>(
1195        token: Xosc32kToken,
1196        mut base: EnabledXosc32kBase<M, N>,
1197    ) -> (EnabledXosc32k, EnabledXosc32kBase<M, N::Inc>)
1198    where
1199        M: Mode,
1200        N: Increment,
1201    {
1202        base.0.token.enable_32k();
1203        (Enabled::new(Self { token }), base.inc())
1204    }
1205}
1206
1207impl EnabledXosc32k {
1208    /// Disable 1 kHz output from the [`Xosc32kBase`] clock
1209    ///
1210    /// This will [`Decrement`] the [`EnabledXosc32kBase`] counter.
1211    #[inline]
1212    pub fn disable<M, N>(
1213        self,
1214        mut base: EnabledXosc32kBase<M, N>,
1215    ) -> (Xosc32kToken, EnabledXosc32kBase<M, N::Dec>)
1216    where
1217        M: Mode,
1218        N: Decrement,
1219    {
1220        base.0.token.disable_32k();
1221        (self.0.token, base.dec())
1222    }
1223}
1224
1225impl<N> Source for EnabledXosc32k<N> {
1226    type Id = Xosc32kId;
1227
1228    #[inline]
1229    fn freq(&self) -> Hertz {
1230        32_768.Hz()
1231    }
1232}