msp432/
cs.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! Clock System (CS)
6
7use kernel::platform::chip::NoClockControl;
8use kernel::utilities::peripheral_management::{PeripheralManagement, PeripheralManager};
9use kernel::utilities::registers::interfaces::{ReadWriteable, Readable, Writeable};
10use kernel::utilities::registers::{
11    register_bitfields, register_structs, ReadOnly, ReadWrite, WriteOnly,
12};
13use kernel::utilities::StaticRef;
14
15pub const MCLK_HZ: u32 = 48_000_000;
16pub const HSMCLK_HZ: u32 = 12_000_000;
17pub const SMCLK_HZ: u32 = 1_500_000;
18pub const ACLK_HZ: u32 = 32_768;
19
20const CS_BASE: StaticRef<CsRegisters> =
21    unsafe { StaticRef::new(0x4001_0400u32 as *const CsRegisters) };
22
23const KEY: u32 = 0x695A;
24
25register_structs! {
26    /// CS
27    pub CsRegisters {
28        /// Key Register
29        (0x00 => key: ReadWrite<u32, CSKEY::Register>),
30        /// Control 0 Register
31        (0x04 => ctl0: ReadWrite<u32, CSCTL0::Register>),
32        /// Control 1 Register
33        (0x08 => ctl1: ReadWrite<u32, CSCTL1::Register>),
34        /// Control 2 Register
35        (0x0C => ctl2: ReadWrite<u32, CSCTL2::Register>),
36        /// Control 3 Register
37        (0x10 => ctl3: ReadWrite<u32, CSCTL3::Register>),
38        (0x14 => _reserved0),
39        /// Clock Enable Register
40        (0x30 => clken: ReadWrite<u32, CSCLKEN::Register>),
41        /// Status Register
42        (0x34 => stat: ReadOnly<u32, CSSTAT::Register>),
43        (0x38 => _reserved1),
44        /// Interrupt Enable Register
45        (0x40 => ie: ReadWrite<u32, CSIE::Register>),
46        (0x44 => _reserved2),
47        /// Interrupt Flag Register
48        (0x48 => ifg: ReadOnly<u32, CSIFG::Register>),
49        (0x4C => _reserved3),
50        /// Clear Interrupt Flag Register
51        (0x50 => clrifg: WriteOnly<u32, CSCLRIFG::Register>),
52        (0x54 => _reserved4),
53        /// Set Interrupt Flag Register
54        (0x58 => setifg: WriteOnly<u32, CSSETIFG::Register>),
55        (0x5C => _reserved5),
56        /// DCO External Resistor Calibration 0 Register
57        (0x60 => dcoercal0: ReadWrite<u32, CSDCOERCAL0::Register>),
58        /// DCO External Resistor Calibration 1 Register
59        (0x64 => dcoercal1: ReadWrite<u32, CSDCOERCAL1::Register>),
60        (0x68 => @END),
61    }
62}
63
64register_bitfields! [u32,
65    CSKEY [
66        /// For accessing any other register, it must be unlocked using this key-register
67        KEY OFFSET(0) NUMBITS(16)
68    ],
69    CSCTL0 [
70        /// For calibrating the DCO frequency
71        DCOTUNE OFFSET(0) NUMBITS(10),
72        /// DCO frequency range select
73        DCORSEL OFFSET(16) NUMBITS(3),
74        /// Enable/disable DCO external resistor mode
75        DCORES OFFSET(22) NUMBITS(1),
76        /// Enable DCO
77        DCOEN OFFSET(23) NUMBITS(23)
78    ],
79    CSCTL1 [
80        /// Select MCLK source
81        SELM OFFSET(0) NUMBITS(3),
82        /// Select SMCLK and HSMCLK source
83        SELS OFFSET(4) NUMBITS(3),
84        /// Select ACLK source
85        SELA OFFSET(8) NUMBITS(3),
86        /// Select BLCK source
87        SELB OFFSET(12) NUMBITS(1),
88        /// MCLK source divider
89        DIVM OFFSET(16) NUMBITS(3),
90        /// HSMCLK source divider
91        DIVHS OFFSET(20) NUMBITS(3),
92        /// ACLK source divider
93        DIVA OFFSET(24) NUMBITS(3),
94        /// SMCLK divider
95        DIVS OFFSET(28) NUMBITS(3)
96    ],
97    CSCTL2 [
98        /// Set drive-strength for LXFT oscillator
99        LFXTDRIVE OFFSET(0) NUMBITS(2),
100        /// Turn on LFXT oscillator
101        LFXT_EN OFFSET(8) NUMBITS(1),
102        /// LFXT bypass select
103        LFXTBYPASS OFFSET(9) NUMBITS(1),
104        /// HFXT oscillator drive selection
105        HFXTDRIVE OFFSET(16) NUMBITS(1),
106        /// HFXT frequency selection
107        HFXTFREQ OFFSET(20) NUMBITS(3),
108        /// Turn on HFXT oscillator
109        HFXT_EN OFFSET(24) NUMBITS(1),
110        /// HFXT bypass select
111        HFXTBYPASS OFFSET(25) NUMBITS(1)
112    ],
113    CSCTL3 [
114        /// Start flag counter for LFXT
115        FCNTLF OFFSET(0) NUMBITS(2),
116        /// Reset start fault counter for LFXT
117        RFCNTLF OFFSET(2) NUMBITS(1),
118        /// Enable start fault counter for LFXT
119        FCNTLF_EN OFFSET(0) NUMBITS(1),
120        /// Start flag counter for HFXT
121        FCNTHF OFFSET(4) NUMBITS(2),
122        /// Reset start fault counter for HFXT
123        RFCNTHF OFFSET(6) NUMBITS(1),
124        /// Enable start fault counter for HFXT
125        FCNTHF_EN OFFSET(7) NUMBITS(1)
126    ],
127    CSCLKEN [
128        /// ACLK system clock conditional request enable
129        ACLK_EN OFFSET(0) NUMBITS(1),
130        /// MCLK system clock conditional request enable
131        MCLK_EN OFFSET(1) NUMBITS(1),
132        /// HSMCLK system clock conditional request enable
133        HSMCLK_EN OFFSET(2) NUMBITS(1),
134        /// SMCLK system clock conditional request enable
135        SMCLK_EN OFFSET(3) NUMBITS(1),
136        /// Turn on the VLO oscillator
137        VLO_EN OFFSET(8) NUMBITS(1),
138        /// Turn on the REFO oscillator
139        REFO_EN OFFSET(9) NUMBITS(1),
140        /// Turn on the MODOSC oscillator
141        MODOSC_EN OFFSET(10) NUMBITS(1),
142        /// Select REFO nominal frequency: 0 = 32.768kHz, 1=128kHz
143        REFOFSEL OFFSET(15) NUMBITS(1)
144    ],
145    /// Status of the different clock-sources
146    CSSTAT [
147        /// DCO status, 1=active, 0=inactive
148        DCO_ON OFFSET(0) NUMBITS(1),
149        /// DCO bias status, 1=active, 0=inactive
150        DCOBIAS_ON OFFSET(1) NUMBITS(1),
151        /// HFXT status, 1=active, 0=inactive
152        HFXT_ON OFFSET(2) NUMBITS(1),
153        /// MODOSC status, 1=active, 0=inactive
154        MODOSC_ON OFFSET(4) NUMBITS(1),
155        /// VLO status, 1=active, 0=inactive
156        VLO_ON OFFSET(5) NUMBITS(1),
157        /// LFXT status, 1=active, 0=inactive
158        LFXT_ON OFFSET(6) NUMBITS(1),
159        /// REFO status, 1=active, 0=inactive
160        REFO_ON OFFSET(7) NUMBITS(1),
161        /// ACLK system clock status, 1=active, 0=inactive
162        ACLK_ON OFFSET(16) NUMBITS(1),
163        /// MCLK system clock status, 1=active, 0=inactive
164        MCLK_ON OFFSET(17) NUMBITS(1),
165        /// HSMCLK system clock status, 1=active, 0=inactive
166        HSMCLK_ON OFFSET(18) NUMBITS(1),
167        /// SMCLK system clock status, 1=active, 0=inactive
168        SMCLK_ON OFFSET(19) NUMBITS(1),
169        /// MODCLK system clock status, 1=active, 0=inactive
170        MODCLK_ON OFFSET(20) NUMBITS(1),
171        /// VLOCLK system clock status, 1=active, 0=inactive
172        VLOCLK_ON OFFSET(21) NUMBITS(1),
173        /// LFXTCLK system clock status, 1=active, 0=inactive
174        LFXTCLK_ON OFFSET(22) NUMBITS(1),
175        /// REFOCLK system clock status, 1=active, 0=inactive
176        REFOCLK_ON OFFSET(23) NUMBITS(1),
177        /// ACLK ready status, indicates if the clock is stable after a change in the frequency/divider settings
178        ACLK_READY OFFSET(24) NUMBITS(1),
179        /// MCLK ready status, indicates if the clock is stable after a change in the frequency/divider settings
180        MCLK_READY OFFSET(25) NUMBITS(1),
181        /// HSMCLK ready status, indicates if the clock is stable after a change in the frequency/divider settings
182        HSMCLK_READY OFFSET(26) NUMBITS(1),
183        /// SMCLK ready status, indicates if the clock is stable after a change in the frequency/divider settings
184        SMCLK_READY OFFSET(27) NUMBITS(1),
185        /// BCLK ready status, indicates if the clock is stable after a change in the frequency/divider settings
186        BCLK_READY OFFSET(28) NUMBITS(1)
187    ],
188    /// Interrupt enable register
189    CSIE [
190        /// LFXT oscillator fault flag
191        LFXTIE OFFSET(0) NUMBITS(1),
192        /// HFXT oscillator fault flag
193        HFXTIE OFFSET(1) NUMBITS(1),
194        /// DCO external resistor open circuit fault flag
195        DCOR_OPNIE OFFSET(6) NUMBITS(1),
196        /// LFXT start fault counter
197        FCNTLFIE OFFSET(8) NUMBITS(1),
198        /// HFXT start fault counter
199        FCNTHFIE OFFSET(9) NUMBITS(1)
200    ],
201    /// Interrupt flag register
202    CSIFG [
203        /// LFXT oscillator fault flag
204        LFXTIFG OFFSET(0) NUMBITS(1),
205        /// HFXT oscillator fault flag
206        HFXTIFG OFFSET(1) NUMBITS(1),
207        /// DCO external resistor open circuit fault flag
208        DCOR_OPNIFG OFFSET(6) NUMBITS(1),
209        /// LFXT start fault counter
210        FCNTLFIFG OFFSET(8) NUMBITS(1),
211        /// HFXT start fault counter
212        FCNTHFIFG OFFSET(9) NUMBITS(1)
213    ],
214    /// iIterrupt clear register
215    CSCLRIFG [
216        /// LFXT oscillator fault flag
217        LFXTIFG OFFSET(0) NUMBITS(1),
218        /// HFXT oscillator fault flag
219        HFXTIFG OFFSET(1) NUMBITS(1),
220        /// DCO external resistor open circuit fault flag
221        DCOR_OPNIFG OFFSET(6) NUMBITS(1),
222        /// LFXT start fault counter
223        FCNTLFIFG OFFSET(8) NUMBITS(1),
224        /// HFXT start fault counter
225        FCNTHFIFG OFFSET(9) NUMBITS(1)
226    ],
227    /// Interrupt set/assert register
228    CSSETIFG [
229        /// LFXT oscillator fault flag
230        SET_LFXTIFG OFFSET(0) NUMBITS(1),
231        /// HFXT oscillator fault flag
232        SET_HFXTIFG OFFSET(1) NUMBITS(1),
233        /// DCO external resistor open circuit fault flag
234        SET_DCOR_OPNIFG OFFSET(6) NUMBITS(1),
235        /// LFXT start fault counter
236        SET_FCNTLFIFG OFFSET(8) NUMBITS(1),
237        /// HFXT start fault counter
238        SET_FCNTHFIFG OFFSET(9) NUMBITS(1)
239    ],
240    /// DCO external resistor calibration 0 register
241    CSDCOERCAL0 [
242        /// DCO temperature compensation calibration
243        DCO_TCCAL OFFSET(0) NUMBITS(1),
244        /// DCO frequency calibration for DCO frequency range (DCORSEL) 0 to 4
245        DCO_FCAL_RSEL04 OFFSET(16) NUMBITS(10)
246    ],
247    /// DCO external resistor calibration 1 register
248    CSDCOERCAL1 [
249        /// DCO frequency calibration for DCO frequency range (DCORSEL) 5
250        DCO_FCAL_RSEL5 OFFSET(0) NUMBITS(10)
251    ]
252];
253
254type CsRegisterManager<'a> = PeripheralManager<'a, ClockSystem, NoClockControl>;
255
256pub struct ClockSystem {
257    registers: StaticRef<CsRegisters>,
258}
259
260impl ClockSystem {
261    pub const fn new() -> ClockSystem {
262        ClockSystem { registers: CS_BASE }
263    }
264
265    fn set_mclk_48mhz(&self) {
266        let cs = CsRegisterManager::new(self);
267
268        // Set HFXT to 40-48MHz range
269        cs.registers.ctl2.modify(CSCTL2::HFXTFREQ.val(6));
270
271        // Set HFXT (48MHz) as MCLK source
272        cs.registers
273            .ctl1
274            .modify(CSCTL1::SELM.val(5) + CSCTL1::DIVM.val(0));
275
276        while cs.registers.ifg.is_set(CSIFG::HFXTIFG) {
277            cs.registers
278                .clrifg
279                .write(CSCLRIFG::HFXTIFG::SET + CSCLRIFG::FCNTHFIFG::SET);
280        }
281    }
282
283    // Setup the subsystem master clock (HSMCLK) to 1/4 of the master-clock -> 12MHz
284    fn set_hsmclk_12mhz(&self) {
285        let cs = CsRegisterManager::new(self);
286
287        // Set HFXT (48MHz) as clock-source for HSMCLK
288        cs.registers.ctl1.modify(CSCTL1::SELS.val(5));
289
290        // Set HSMCLK divider to 4 -> 48MHz / 4 = 12MHz
291        cs.registers.ctl1.modify(CSCTL1::DIVHS.val(2));
292    }
293
294    // Setup the low-speed subsystem master clock (SMCLK) to 1/32 of the master-clock -> 1.5MHz
295    fn set_smclk_1500khz(&self) {
296        let cs = CsRegisterManager::new(self);
297
298        // Set HFXT (48MHz) as clock-source for SMCLK
299        cs.registers.ctl1.modify(CSCTL1::SELS.val(5));
300
301        // Set SMCLK divider to 32 -> 48MHz / 32 = 1.5MHz
302        cs.registers.ctl1.modify(CSCTL1::DIVS.val(5));
303    }
304
305    // Setup the auxiliary clock (ACLK) to 32.768kHz
306    fn set_aclk_32khz(&self) {
307        let cs = CsRegisterManager::new(self);
308
309        // Set LFXT (32.768kHz) as clock-source for ACLK
310        cs.registers.ctl1.modify(CSCTL1::SELA.val(0));
311
312        // SET ACLK divider to 1 -> 32.768kHz
313        cs.registers.ctl1.modify(CSCTL1::DIVA.val(0));
314    }
315
316    pub fn setup_clocks(&self) {
317        self.set_mclk_48mhz();
318        self.set_hsmclk_12mhz();
319        self.set_smclk_1500khz();
320        self.set_aclk_32khz();
321    }
322}
323
324impl PeripheralManagement<NoClockControl> for ClockSystem {
325    type RegisterType = CsRegisters;
326
327    fn get_registers(&self) -> &CsRegisters {
328        &self.registers
329    }
330
331    fn get_clock(&self) -> &NoClockControl {
332        &kernel::platform::chip::NO_CLOCK_CONTROL
333    }
334
335    fn before_peripheral_access(&self, _c: &NoClockControl, r: &Self::RegisterType) {
336        // Unlocks the registers in order to allow write accesses
337        r.key.modify(CSKEY::KEY.val(KEY));
338    }
339
340    fn after_peripheral_access(&self, _c: &NoClockControl, r: &Self::RegisterType) {
341        // Locks the registers in order to prevent write accesses
342        // Every value except KEY written to the key register will perform the lock
343        r.key.modify(CSKEY::KEY.val(0));
344    }
345}