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
//! This module is intentionally private. Its contents are publicly exported
//! from the `v2` module, which is where the corresponding documentation will
//! appear.

use typenum::U1;

use crate::pac::{GCLK, MCLK, NVMCTRL, OSC32KCTRL, OSCCTRL};

use super::*;

/// Collection of low-level PAC structs
///
/// This struct serves to guard access to the low-level PAC structs. It places
/// them behind an `unsafe` barrier.
///
/// Normally, users trade the low-level PAC structs for the higher-level
/// `clock::v2` API. However, in some cases, the `clock::v2` API may not be
/// sufficient. In these cases, users can access the registers directly by
/// calling [`Pac::steal`] to recover the PAC structs.
pub struct Pac {
    oscctrl: OSCCTRL,
    osc32kctrl: OSC32KCTRL,
    gclk: GCLK,
    mclk: MCLK,
}

impl Pac {
    /// Escape hatch allowing to access low-level PAC structs
    ///
    /// Consume the [`Pac`] and return the low-level PAC structs. This is
    /// useful when the `clock::v2` API does not provide a necessary feature, or
    /// when dealing with the legacy `clock::v1` API. For example, many of the
    /// `clock::v1` functions require access to the [`MCLK`] peripheral.
    ///
    /// # Safety
    ///
    /// Directly configuring clocks through the PAC API can invalidate the
    /// type-level guarantees of the `clock` module API.
    pub unsafe fn steal(self) -> (OSCCTRL, OSC32KCTRL, GCLK, MCLK) {
        (self.oscctrl, self.osc32kctrl, self.gclk, self.mclk)
    }
}

/// Bus clock objects
///
/// This type is constructed using the [`clock_system_at_reset`] function, which
/// consumes the PAC-level clocking structs and returns the HAL-level clocking
/// structs in their reset state.
///
/// This type contains the [bus clocks](super#bus-clocks), which are a necessary
/// to implement memory safety for the [`AhbClk`]s and [`ApbClk`]s.
///
/// [`AhbClk`]: super::ahb::AhbClk
/// [`ApbClk`]: super::apb::ApbClk
pub struct Buses {
    pub ahb: ahb::Ahb,
    pub apb: apb::Apb,
}

/// Enabled clocks at power-on reset
///
/// This type is constructed using the [`clock_system_at_reset`] function, which
/// consumes the PAC-level clocking structs and returns the HAL-level clocking
/// structs in their reset state.
///
/// This type represents the clocks as they are configured at power-on reset.
/// The main clock, [`Gclk0`](gclk::Gclk0), runs at 48 MHz using the
/// [`Dfll`](dfll::Dfll) in open-loop mode. The ultra-low power
/// [base oscillator](osculp32k::OscUlp32kBase) is also enabled and running, as
/// it can never be disabled.
///
/// As described in the [top-level](super::super) documentation for the `clock`
/// module, only [`Enabled`] clocks can be used as a [`Source`] for downstream
/// clocks. This struct contains all of the `Enabled` clocks at reset.
///
/// This struct also contains the [`Pac`] wrapper struct, which provides
/// `unsafe` access to the low-level PAC structs.
pub struct Clocks {
    /// Wrapper providing `unsafe` access to low-level PAC structs
    pub pac: Pac,
    /// Enabled AHB clocks
    pub ahbs: ahb::AhbClks,
    /// Enabled APB clocks
    pub apbs: apb::ApbClks,
    /// Main system clock, driven at 48 MHz by the DFLL in open loop mode
    pub gclk0: Enabled<gclk::Gclk0<dfll::DfllId>, U1>,
    /// DFLL48 in open loop mode
    pub dfll: Enabled<dfll::Dfll, U1>,
    /// Always-enabled base oscillator for the [`OscUlp1k`](osculp32k::OscUlp1k)
    /// and [`OscUlp32k`](osculp32k::OscUlp32k) clocks.
    pub osculp32k_base: Enabled<osculp32k::OscUlp32kBase>,
}

/// Type-level tokens for unused clocks at power-on reset
///
/// This type is constructed using the [`clock_system_at_reset`] function, which
/// consumes the PAC-level clocking structs and returns the HAL-level clocking
/// structs in their reset state.
///
/// As described in the [top-level](super::super) documentation for the `clock`
/// module, token types are used to guanrantee the uniqueness of each clock. To
/// configure or enable a clock, you must provide the corresponding token.
pub struct Tokens {
    /// Tokens to create [`apb::ApbClk`]s
    pub apbs: apb::ApbTokens,
    /// Token to create [`dpll::Dpll0`]
    pub dpll0: dpll::DpllToken<dpll::Dpll0Id>,
    /// Token to create [`dpll::Dpll1`]
    pub dpll1: dpll::DpllToken<dpll::Dpll1Id>,
    /// Tokens to create [`gclk::Gclk`]
    pub gclks: gclk::GclkTokens,
    /// Tokens to create [`pclk::Pclk`]s
    pub pclks: pclk::PclkTokens,
    /// Tokens to create [`rtcosc::RtcOsc`]
    pub rtcosc: rtcosc::RtcOscToken,
    /// Tokens [`xosc::Xosc0`]
    pub xosc0: xosc::XoscToken<xosc::Xosc0Id>,
    /// Token to create [`xosc::Xosc1`]
    pub xosc1: xosc::XoscToken<xosc::Xosc1Id>,
    /// Tokens to create [`xosc32k::Xosc32kBase`], [`xosc32k::Xosc1k`] and
    /// [`xosc32k::Xosc32k`]
    pub xosc32k: xosc32k::Xosc32kTokens,
    /// Tokens to create [`osculp32k::OscUlp1k`] and [`osculp32k::OscUlp32k`]
    pub osculp32k: osculp32k::OscUlp32kTokens,
}

/// Consume the PAC clocking structs and return a HAL-level
/// representation of the clocks at power-on reset
///
/// This function consumes the [`OSCCTRL`], [`OSC32KCTRL`], [`GCLK`] and
/// [`MCLK`] PAC structs and returns the [`Buses`], [`Clocks`] and [`Tokens`].
///
/// See the [module-level documentation](super) for more details.
#[inline]
pub fn clock_system_at_reset(
    oscctrl: OSCCTRL,
    osc32kctrl: OSC32KCTRL,
    gclk: GCLK,
    mclk: MCLK,
    nvmctrl: &mut NVMCTRL,
) -> (Buses, Clocks, Tokens) {
    // Safety: No bus, clock or token is instantiated more than once
    unsafe {
        let buses = Buses {
            ahb: ahb::Ahb::new(),
            apb: apb::Apb::new(),
        };
        let pac = Pac {
            oscctrl,
            osc32kctrl,
            gclk,
            mclk,
        };
        let dfll = Enabled::<_>::new(dfll::Dfll::open_loop(dfll::DfllToken::new()));
        let (gclk0, dfll) = gclk::Gclk0::from_source(gclk::GclkToken::new(), dfll);
        let gclk0 = Enabled::new(gclk0);
        let clocks = Clocks {
            pac,
            ahbs: ahb::AhbClks::new(),
            apbs: apb::ApbClks::new(),
            gclk0,
            dfll,
            osculp32k_base: osculp32k::OscUlp32kBase::new(),
        };
        let tokens = Tokens {
            apbs: apb::ApbTokens::new(),
            dpll0: dpll::DpllToken::new(),
            dpll1: dpll::DpllToken::new(),
            gclks: gclk::GclkTokens::new(nvmctrl),
            pclks: pclk::PclkTokens::new(),
            rtcosc: rtcosc::RtcOscToken::new(),
            xosc0: xosc::XoscToken::new(),
            xosc1: xosc::XoscToken::new(),
            xosc32k: xosc32k::Xosc32kTokens::new(),
            osculp32k: osculp32k::OscUlp32kTokens::new(),
        };
        (buses, clocks, tokens)
    }
}