1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
//! # Internal, ultra low power, 32 kHz oscillator
//!
//! ## Overview
//!
//! The `osculp32k` module provides access to the 32 kHz ultra low power
//! internal oscillator (OSCULP32K) within the `OSC32KCTRL` peripheral.
//!
//! The `OSCULP32K` clock is unlike most other clocks. First, it is an internal
//! clock that is always enabled and can't be disabled. And second, it has two
//! separate outputs, one at 32 kHz and another divided down to 1 kHz. Moreover,
//! none, either or both of these outputs can be enabled at any given time.
//!
//! We can see, then, that the `OSCULP32K` peripheral forms its own, miniature
//! clock tree. There is a 1:N producer clock that is always enabled; and there
//! are two possible consumer clocks that can be independently and optionally
//! enabled. In fact, this structure is illustrated by the `OSCULP32K`
//! register, which has no regular `ENABLE` bit and two different enable bits
//! for clock output, `EN32K` and `EN1K`.
//!
//! To represent this structure in the type system, we divide the `OSCULP32K`
//! peripheral into these three clocks. Users get access to the 1:N
//! [`EnabledOscUlp32kBase`] clock [`Source`] at power-on reset, which can be
//! consumed by both the [`OscUlp32k`] and [`OscUlp1k`] clocks. Note that
//! `OscUlp32k` and `OscUlp1k` are themselves 1:N clocks as well.
//!
//! ## Write lock
//!
//! Rhe `OSCULP32K` register has a dedicated write lock bit that will freeze its
//! configuration until the next power-on reset. We implement this by simply
//! dropping the [`OscUlp32kBase`] clock, which prevents any further access to
//! the `OSCULP32K` register.
//!
//! ## Example
//!
//! Creating and configuring the OSCULP32K clocks proceeds according to the
//! principles outlined in the [`clock` module documentation]. It is best shown
//! with an example.
//!
//! Let's start by using [`clock_system_at_reset`] to access the HAL clocking
//! structs.
//!
//! ```no_run
//! use atsamd_hal::{
//!     clock::v2::{
//!         clock_system_at_reset,
//!         osculp32k::{OscUlp1k, OscUlp32k},
//!     },
//!     pac::Peripherals,
//! };
//! let mut pac = Peripherals::take().unwrap();
//! let (buses, clocks, tokens) = clock_system_at_reset(
//!     pac.OSCCTRL,
//!     pac.OSC32KCTRL,
//!     pac.GCLK,
//!     pac.MCLK,
//!     &mut pac.NVMCTRL,
//! );
//! ```
//!
//! Next, we can extract the [`EnabledOscUlp32kBase`] clock from the [`Clocks`]
//! struct and use it to enable the [`OscUlp1k`] and [`OscUlp32k`] clocks.
//!
//! ```no_run
//! # use atsamd_hal::{
//! #     clock::v2::{
//! #         clock_system_at_reset,
//! #         osculp32k::{OscUlp1k, OscUlp32k},
//! #     },
//! #     pac::Peripherals,
//! # };
//! # let mut pac = Peripherals::take().unwrap();
//! # let (buses, clocks, tokens) = clock_system_at_reset(
//! #     pac.OSCCTRL,
//! #     pac.OSC32KCTRL,
//! #     pac.GCLK,
//! #     pac.MCLK,
//! #     &mut pac.NVMCTRL,
//! # );
//! let base = clocks.osculp32k_base;
//! let (osculp1k, base) = OscUlp1k::enable(tokens.osculp32k.osculp1k, base);
//! let (osculp32k, base) = OscUlp32k::enable(tokens.osculp32k.osculp32k, base);
//! ```
//!
//! We can then override the calibration value read from flash at start up.
//!
//! ```no_run
//! # use atsamd_hal::{
//! #     clock::v2::{
//! #         clock_system_at_reset,
//! #         osculp32k::{OscUlp1k, OscUlp32k},
//! #     },
//! #     pac::Peripherals,
//! # };
//! # let mut pac = Peripherals::take().unwrap();
//! # let (buses, clocks, tokens) = clock_system_at_reset(
//! #     pac.OSCCTRL,
//! #     pac.OSC32KCTRL,
//! #     pac.GCLK,
//! #     pac.MCLK,
//! #     &mut pac.NVMCTRL,
//! # );
//! # let base = clocks.osculp32k_base;
//! # let (osculp1k, base) = OscUlp1k::enable(tokens.osculp32k.osculp1k, base);
//! # let (osculp32k, mut base) = OscUlp32k::enable(tokens.osculp32k.osculp32k, base);
//! base.set_calibration(128);
//! ```
//!
//! And finally, we can set the write lock bit to freeze the configuation until
//! the next power-on reset. Doing so also drops the `EnabledOscUlp32kBase`
//! clock.
//!
//! ```no_run
//! # use atsamd_hal::{
//! #     clock::v2::{
//! #         clock_system_at_reset,
//! #         osculp32k::{OscUlp1k, OscUlp32k},
//! #     },
//! #     pac::Peripherals,
//! # };
//! # let mut pac = Peripherals::take().unwrap();
//! # let (buses, clocks, tokens) = clock_system_at_reset(
//! #     pac.OSCCTRL,
//! #     pac.OSC32KCTRL,
//! #     pac.GCLK,
//! #     pac.MCLK,
//! #     &mut pac.NVMCTRL,
//! # );
//! # let base = clocks.osculp32k_base;
//! # let (osculp1k, base) = OscUlp1k::enable(tokens.osculp32k.osculp1k, base);
//! # let (osculp32k, mut base) = OscUlp32k::enable(tokens.osculp32k.osculp32k, base);
//! # base.set_calibration(128);
//! base.write_lock();
//! ```
//!
//! The complete example is shown below.
//!
//! ```no_run
//! use atsamd_hal::{
//!     clock::v2::{
//!         clock_system_at_reset,
//!         osculp32k::{OscUlp1k, OscUlp32k},
//!     },
//!     pac::Peripherals,
//! };
//! let mut pac = Peripherals::take().unwrap();
//! let (buses, clocks, tokens) = clock_system_at_reset(
//!     pac.OSCCTRL,
//!     pac.OSC32KCTRL,
//!     pac.GCLK,
//!     pac.MCLK,
//!     &mut pac.NVMCTRL,
//! );
//! let base = clocks.osculp32k_base;
//! let (osculp1k, base) = OscUlp1k::enable(tokens.osculp32k.osculp1k, base);
//! let (osculp32k, mut base) = OscUlp32k::enable(tokens.osculp32k.osculp32k, base);
//! base.set_calibration(128);
//! base.write_lock();
//! ```
//!
//! [`clock` module documentation]: super
//! [`clock_system_at_reset`]: super::clock_system_at_reset
//! [`Clocks`]: super::Clocks

use typenum::U0;

use crate::pac::osc32kctrl::OSCULP32K;

use crate::time::Hertz;
use crate::typelevel::{Decrement, Increment, PrivateDecrement, PrivateIncrement, Sealed};

use super::{Enabled, Source};

//==============================================================================
// Tokens
//==============================================================================

/// Singleton token for the [`OscUlp32kBase`] clock
//
// There should never be more than one instance of `OscUlp32kBaseToken`, because
// it relies on that fact for memory safety.
//
// Users never see `OscUlp32kBaseToken`, because the OSCULP32K base oscillator
// is always enabled. Internally, however, it is used as a register interface.
// The token is zero-sized, so it can be carried by clock types without
// introducing any memory bloat.
//
// As part of that register interface, the `OscUlp32kBaseToken` can access the
// `OSCULP32K` register. That the token is a singleton guarantees the register
// is written from only one location. This allows the token to be `Sync`, even
// though the PAC `OSC32KCTRL` struct is not.
struct OscUlp32kBaseToken(());

/// Singleton token that can be exchanged for [`OscUlp1k`]
///
/// As explained in the [`clock` module documentation](super), instances of
/// various `Token` types can be exchanged for actual clock types. They
/// typically represent clocks that are disabled at power-on reset.
///
/// The [`OscUlp1k`] clock is disabled at power-on reset. To use it, you must
/// first exchange the token for an actual clock with [`OscUlp1k::enable`].
pub struct OscUlp1kToken(());

/// Singleton token that can be exchanged for [`OscUlp32k`]
///
/// As explained in the [`clock` module documentation](super), instances of
/// various `Token` types can be exchanged for actual clock types. They
/// typically represent clocks that are disabled at power-on reset.
///
/// The [`OscUlp32k`] clock is disabled at power-on reset. To use it, you must
/// first exchange the token for an actual clock with [`OscUlp32k::enable`].
pub struct OscUlp32kToken(());

/// Set of tokens representing the disabled OSCULP32K clocks power-on reset
pub struct OscUlp32kTokens {
    pub osculp1k: OscUlp1kToken,
    pub osculp32k: OscUlp32kToken,
}

impl OscUlp32kTokens {
    /// Create the set of tokens
    ///
    /// # Safety
    ///
    /// There must never be more than one instance of each token at any given
    /// time. See the notes on `Token` types and memory safety in the root of
    /// the `clock` module for more details.
    pub(super) unsafe fn new() -> Self {
        Self {
            osculp1k: OscUlp1kToken(()),
            osculp32k: OscUlp32kToken(()),
        }
    }
}

impl OscUlp32kBaseToken {
    #[inline]
    fn osculp32k(&self) -> &OSCULP32K {
        // Safety: The `OscUlp32kBaseToken` has exclusive access to the
        // `OSCULP32K` register. See the notes on `Token` types and memory
        // safety in the root of the `clock` module for more details.
        unsafe { &(*crate::pac::OSC32KCTRL::PTR).osculp32k }
    }

    /// Set the calibration
    #[inline]
    fn set_calibration(&mut self, calib: u8) {
        // Safety: All bit patterns are valid for this field
        self.osculp32k()
            .modify(|_, w| unsafe { w.calib().bits(calib) });
    }

    /// Enable the 1 kHz output
    #[inline]
    fn enable_1k(&mut self) {
        self.osculp32k().modify(|_, w| w.en1k().set_bit());
    }

    /// Disable the 1 kHz output
    #[inline]
    fn disable_1k(&mut self) {
        self.osculp32k().modify(|_, w| w.en1k().clear_bit());
    }

    /// Enable the 32 kHz output
    #[inline]
    fn enable_32k(&mut self) {
        self.osculp32k().modify(|_, w| w.en32k().set_bit());
    }

    /// Disable the 32 kHz output
    #[inline]
    fn disable_32k(&mut self) {
        self.osculp32k().modify(|_, w| w.en32k().clear_bit());
    }

    /// Enable the write lock
    #[inline]
    fn write_lock(&mut self) {
        self.osculp32k().modify(|_, w| w.wrtlock().set_bit());
    }
}

//==============================================================================
// OscUlpBase
//==============================================================================

/// OSC3ULP2K base clock, which feeds the [`OscUlp1k`] and [`OscUlp32k`] clocks
///
/// The OSCULP32K peripheral has two possible clock outputs, one at 32 kHz and
/// another at 1 kHz. This structure is represented in the type system as a set
/// of three clocks forming a small clock tree. The [`OscUlp32kBase`] clock
/// represents the base oscillator that feeds the optional [`OscUlp1k`] and
/// [`OscUlp32k`] output clocks. See the [module-level documentation](super) for
/// details and examples.
pub struct OscUlp32kBase {
    token: OscUlp32kBaseToken,
}

/// The [`Enabled`] [`OscUlp32kBase`] clock
///
/// As described in the [`clock` module documentation](super), the [`Enabled`]
/// wrapper implements compile-time clock tree safety by tracking the number of
/// clocks consuming the [`OscUlp32kBase`] clock and restricts access to the
/// underlying type to prevent misuse.
///
/// **NOTE:** The `OscUlp32kBase` clock is internal and can never be disabled,
/// so we do not provide a `disable` method.
///
/// As with [`Enabled`], the default value for `N` is `U0`; if left unspecified,
/// the counter is assumed to be zero.
pub type EnabledOscUlp32kBase<N = U0> = Enabled<OscUlp32kBase, N>;

impl OscUlp32kBase {
    /// Create the ultra-low power base oscillator
    ///
    /// # Safety
    ///
    /// Because an `OscUlp32kBase` contains an `OscUlp32kBaseToken`, there must
    /// never be more than one instance of this struct at any given time. See
    /// the notes on `Token` types and memory safety in the root of the `clock`
    /// module for more details.
    #[inline]
    pub(super) unsafe fn new() -> EnabledOscUlp32kBase {
        let token = OscUlp32kBaseToken(());
        Enabled::new(Self { token })
    }
}

impl<N> EnabledOscUlp32kBase<N> {
    /// Override the factory-default calibration value
    #[inline]
    pub fn set_calibration(&mut self, calib: u8) {
        self.0.token.set_calibration(calib);
    }

    /// Freeze the OSCULP32K configuration until power-on reset
    ///
    /// This function sets the write-lock bit, which freezes the OSCULP32K
    /// configuration at the hardware level until power-on reset. At the API
    /// level, it also consumes and drops the [`OscUlp32kBase`] clock, which
    /// prevents any further modifications.
    #[inline]
    pub fn write_lock(mut self) {
        self.0.token.write_lock();
    }
}

//==============================================================================
// Ids
//==============================================================================

/// Type representing the identity of the [`OscUlp1k`] clock
///
/// See the discussion on [`Id` types](super#id-types) for more information.
pub enum OscUlp1kId {}

impl Sealed for OscUlp1kId {}

/// Type representing the identity of the [`OscUlp32k`] clock
///
/// See the discussion on [`Id` types](super#id-types) for more information.
pub enum OscUlp32kId {}

impl Sealed for OscUlp32kId {}

//==============================================================================
// OscUlp1k
//==============================================================================

/// Clock representing the 1 kHz output of the [`OscUlp32kBase`] clock
///
/// The OSCULP32K peripheral has two possible clock outputs, one at 32 kHz and
/// another at 1 kHz. This structure is represented in the type system as a set
/// of three clocks forming a small clock tree. The [`OscUlp1k`] clock is
/// derived from the [`OscUlp32kBase`] clock. See the
/// [module-level documentation](super) for details and examples.
pub struct OscUlp1k {
    token: OscUlp1kToken,
}

/// The [`Enabled`] [`OscUlp1k`] clock
///
/// As described in the [`clock` module documentation](super), the [`Enabled`]
/// wrapper implements compile-time clock tree safety by tracking the number of
/// clocks consuming the [`OscUlp1k`] clock and restricts access to the
/// underlying type to prevent misuse.
///
/// As with [`Enabled`], the default value for `N` is `U0`; if left unspecified,
/// the counter is assumed to be zero.
pub type EnabledOscUlp1k<N = U0> = Enabled<OscUlp1k, N>;

impl OscUlp1k {
    /// Enable 1 kHz output from the [`OscUlp32kBase`] clock
    ///
    /// This will [`Increment`] the [`EnabledOscUlp32kBase`] counter.
    #[inline]
    pub fn enable<N: Increment>(
        token: OscUlp1kToken,
        mut base: EnabledOscUlp32kBase<N>,
    ) -> (EnabledOscUlp1k, EnabledOscUlp32kBase<N::Inc>) {
        base.0.token.enable_1k();
        (Enabled::new(Self { token }), base.inc())
    }
}

impl EnabledOscUlp1k {
    /// Disable 1 kHz output from the [`OscUlp32kBase`] clock
    ///
    /// This will [`Decrement`] the [`EnabledOscUlp32kBase`] counter.
    #[inline]
    pub fn disable<N: Decrement>(
        self,
        mut base: EnabledOscUlp32kBase<N>,
    ) -> (OscUlp1kToken, EnabledOscUlp32kBase<N::Dec>) {
        base.0.token.disable_1k();
        (self.0.token, base.dec())
    }
}

impl<N> Source for EnabledOscUlp1k<N> {
    type Id = OscUlp1kId;

    #[inline]
    fn freq(&self) -> Hertz {
        Hertz(1024)
    }
}

//==============================================================================
// OscUlp32k
//==============================================================================

/// Clock representing the 32 kHz output of the [`OscUlp32kBase`] clock
///
/// The OSCULP32K peripheral has two possible clock outputs, one at 32 kHz and
/// another at 1 kHz. This structure is represented in the type system as a set
/// of three clocks forming a small clock tree. The [`OscUlp32k`] clock is
/// derived from the [`OscUlp32kBase`] clock. See the
/// [module-level documentation](super) for details and examples.
pub struct OscUlp32k {
    token: OscUlp32kToken,
}

/// The [`Enabled`] [`OscUlp32k`] clock
///
/// As described in the [`clock` module documentation](super), the [`Enabled`]
/// wrapper implements compile-time clock tree safety by tracking the number of
/// clocks consuming the [`OscUlp32k`] clock and restricts access to the
/// underlying type to prevent misuse.
///
/// As with [`Enabled`], the default value for `N` is `U0`; if left unspecified,
/// the counter is assumed to be zero.
pub type EnabledOscUlp32k<N = U0> = Enabled<OscUlp32k, N>;

impl OscUlp32k {
    /// Enable 32 kHz output from the [`OscUlp32kBase`] clock
    ///
    /// This will [`Increment`] the [`EnabledOscUlp32kBase`] counter.
    #[inline]
    pub fn enable<N: Increment>(
        token: OscUlp32kToken,
        mut base: EnabledOscUlp32kBase<N>,
    ) -> (EnabledOscUlp32k, EnabledOscUlp32kBase<N::Inc>) {
        base.0.token.enable_32k();
        (Enabled::new(Self { token }), base.inc())
    }
}

impl EnabledOscUlp32k {
    /// Disable 32 kHz output from the [`OscUlp32kBase`] clock
    ///
    /// This will [`Decrement`] the [`EnabledOscUlp32kBase`] counter.
    #[inline]
    pub fn disable<N: Decrement>(
        self,
        mut base: EnabledOscUlp32kBase<N>,
    ) -> (OscUlp32kToken, EnabledOscUlp32kBase<N::Dec>) {
        base.0.token.disable_32k();
        (self.0.token, base.dec())
    }
}

impl<N> Source for EnabledOscUlp32k<N> {
    type Id = OscUlp32kId;

    #[inline]
    fn freq(&self) -> Hertz {
        Hertz(32_768)
    }
}