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}