nrf52/
clock.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 peripheral driver, nRF52
6//!
7//! Based on Phil Levis clock driver for nRF51
8//!
9//! HFCLK - High Frequency Clock:
10//!
11//! * 64 MHz internal oscillator (HFINT)
12//! * 64 MHz crystal oscillator, using 32 MHz external crystal (HFXO)
13//! * The HFXO must be running to use the RADIO, NFC module or the calibration mechanism
14//!   associated with the 32.768 kHz RC oscillator.
15//!
16//! LFCLK - Low Frequency Clock Source:
17//!
18//! * 32.768 kHz RC oscillator (LFRC)
19//! * 32.768 kHz crystal oscillator (LFXO)
20//! * 32.768 kHz synthesized from HFCLK (LFSYNT)
21//!
22
23use kernel::utilities::cells::OptionalCell;
24use kernel::utilities::registers::interfaces::{Readable, Writeable};
25use kernel::utilities::registers::{
26    register_bitfields, register_structs, ReadOnly, ReadWrite, WriteOnly,
27};
28use kernel::utilities::StaticRef;
29
30register_structs! {
31    ClockRegisters {
32        (0x000 => tasks_hfclkstart: WriteOnly<u32, Control::Register>),
33        (0x004 => tasks_hfclkstop: WriteOnly<u32, Control::Register>),
34        (0x008 => tasks_lfclkstart: ReadWrite<u32, Control::Register>),
35        (0x00C => tasks_lfclkstop: WriteOnly<u32, Control::Register>),
36        (0x010 => tasks_cal: WriteOnly<u32, Control::Register>),
37        (0x014 => tasks_ctstart: WriteOnly<u32, Control::Register>),
38        (0x018 => tasks_ctstop: WriteOnly<u32, Control::Register>),
39        (0x01C => _reserved1),
40        (0x100 => events_hfclkstarted: ReadOnly<u32, Status::Register>),
41        (0x104 => events_lfclkstarted: ReadOnly<u32, Status::Register>),
42        (0x108 => _reserved2),
43        (0x10C => events_done: ReadOnly<u32, Status::Register>),
44        (0x110 => events_ctto: ReadOnly<u32, Status::Register>),
45        (0x114 => _reserved3),
46        (0x304 => intenset: ReadWrite<u32, Interrupt::Register>),
47        (0x308 => intenclr: ReadWrite<u32, Interrupt::Register>),
48        (0x30C => _reserved4),
49        (0x408 => hfclkrun: ReadOnly<u32, Status::Register>),
50        (0x40C => hfclkstat: ReadOnly<u32, HfClkStat::Register>),
51        (0x410 => _reserved5),
52        (0x414 => lfclkrun: ReadOnly<u32, Control::Register>),
53        (0x418 => lfclkstat: ReadWrite<u32, LfClkStat::Register>),
54        (0x41C => lfclksrccopy: ReadOnly<u32, LfClkSrcCopy::Register>),
55        (0x420 => _reserved6),
56        (0x518 => lfclksrc: ReadWrite<u32, LfClkSrc::Register>),
57        (0x51C => _reserved7),
58        (0x538 => ctiv: ReadWrite<u32, Ctiv::Register>),
59        (0x53C => _reserved8),
60        (0x55C => traceconfig: ReadWrite<u32, TraceConfig::Register>),
61        (0x560 => @END),
62    }
63}
64
65register_bitfields! [u32,
66    Control [
67        ENABLE OFFSET(0) NUMBITS(1)
68    ],
69    Status [
70        READY OFFSET(0) NUMBITS(1)
71    ],
72    Interrupt [
73        HFCLKSTARTED OFFSET(0) NUMBITS(1),
74        LFCLKSTARTED OFFSET(1) NUMBITS(1),
75        DONE OFFSET(3) NUMBITS(1),
76        CTTO OFFSET(4) NUMBITS(1)
77    ],
78    HfClkStat [
79        SRC OFFSET(0) NUMBITS(1) [
80            RC = 0,
81            XTAL = 1
82        ],
83        STATE OFFSET(16) NUMBITS(1) [
84            RUNNING = 1
85        ]
86    ],
87    LfClkStat [
88        SRC OFFSET(0) NUMBITS(2) [
89            RC = 0,
90            XTAL = 1,
91            SYNTH = 2
92        ],
93        STATE OFFSET(16) NUMBITS(1) [
94            RUNNING = 1
95        ]
96    ],
97    LfClkSrcCopy [
98        SRC OFFSET(0) NUMBITS(2) [
99            RC = 0,
100            XTAL = 1,
101            SYNTH = 2
102        ]
103    ],
104    LfClkSrc [
105        SRC OFFSET(0) NUMBITS(2) [
106            RC = 0,
107            XTAL = 1,
108            SYNTH = 2
109        ]
110    ],
111    Ctiv [
112        CTIV OFFSET(0) NUMBITS(7) []
113    ],
114    TraceConfig [
115        TracePortSpeed OFFSET(0) NUMBITS(2) [
116            THIRTYTWO = 0,
117            SIXTEEN = 1,
118            EIGHT = 2,
119            FOUR = 3
120        ],
121        TraceMux OFFSET(16) NUMBITS(2) [
122            GPIO = 0,
123            SERIAL = 1,
124            PARALELL = 2
125        ]
126    ]
127];
128
129const CLOCK_BASE: StaticRef<ClockRegisters> =
130    unsafe { StaticRef::new(0x40000000 as *const ClockRegisters) };
131
132/// Interrupt sources
133pub enum InterruptField {
134    HFCLKSTARTED = 1 << 0,
135    LFCLKSTARTED = 1 << 1,
136    DONE = 1 << 3,
137    CTTO = 1 << 4,
138}
139
140/// Low frequency clock source
141pub enum LowClockSource {
142    RC = 0,
143    XTAL = 1,
144    SYNTH = 2,
145    MASK = 3,
146}
147
148/// High frequency clock source
149pub enum HighClockSource {
150    RC = 0,
151    XTAL = 1,
152}
153
154/// Clock struct
155pub struct Clock {
156    registers: StaticRef<ClockRegisters>,
157    client: OptionalCell<&'static dyn ClockClient>,
158}
159
160pub trait ClockClient {
161    /// All clock interrupts are control signals, e.g., when
162    /// a clock has started etc. We don't actually handle any
163    /// of them for now, but keep this trait in place for if we
164    /// do need to in the future.
165    fn event(&self);
166}
167
168impl Clock {
169    /// Constructor
170    pub const fn new() -> Clock {
171        Clock {
172            registers: CLOCK_BASE,
173            client: OptionalCell::empty(),
174        }
175    }
176
177    /// Client for callbacks
178    pub fn set_client(&self, client: &'static dyn ClockClient) {
179        self.client.set(client);
180    }
181
182    /// Enable interrupt
183    pub fn interrupt_enable(&self, interrupt: InterruptField) {
184        // this is a little too verbose
185        match interrupt {
186            InterruptField::CTTO => self.registers.intenset.write(Interrupt::CTTO::SET),
187            InterruptField::DONE => self.registers.intenset.write(Interrupt::DONE::SET),
188            InterruptField::HFCLKSTARTED => {
189                self.registers.intenset.write(Interrupt::HFCLKSTARTED::SET)
190            }
191            InterruptField::LFCLKSTARTED => {
192                self.registers.intenset.write(Interrupt::LFCLKSTARTED::SET)
193            }
194        }
195    }
196
197    /// Disable interrupt
198    pub fn interrupt_disable(&self, interrupt: InterruptField) {
199        // this is a little too verbose
200        match interrupt {
201            InterruptField::CTTO => self.registers.intenset.write(Interrupt::CTTO::SET),
202            InterruptField::DONE => self.registers.intenset.write(Interrupt::DONE::SET),
203            InterruptField::HFCLKSTARTED => {
204                self.registers.intenset.write(Interrupt::HFCLKSTARTED::SET)
205            }
206            InterruptField::LFCLKSTARTED => {
207                self.registers.intenset.write(Interrupt::LFCLKSTARTED::SET)
208            }
209        }
210    }
211
212    /// Start the high frequency clock - specifically HFXO, and sets the high frequency
213    /// clock source to HFXO
214    pub fn high_start(&self) {
215        self.registers.tasks_hfclkstart.write(Control::ENABLE::SET);
216    }
217
218    /// Stop the high frequency clock
219    pub fn high_stop(&self) {
220        self.registers.tasks_hfclkstop.write(Control::ENABLE::SET);
221    }
222
223    /// Check if the high frequency clock has started
224    pub fn high_started(&self) -> bool {
225        self.registers
226            .events_hfclkstarted
227            .matches_all(Status::READY.val(1))
228    }
229
230    /// Read clock source from the high frequency clock
231    pub fn high_source(&self) -> HighClockSource {
232        match self.registers.hfclkstat.read(HfClkStat::SRC) {
233            0 => HighClockSource::RC,
234            _ => HighClockSource::XTAL,
235        }
236    }
237
238    /// Check if the high frequency clock is running
239    pub fn high_running(&self) -> bool {
240        self.registers
241            .hfclkstat
242            .matches_all(HfClkStat::STATE::RUNNING)
243    }
244
245    /// Start the low frequency clock
246    pub fn low_start(&self) {
247        self.registers.tasks_lfclkstart.write(Control::ENABLE::SET);
248    }
249
250    /// Stop the low frequency clock
251    pub fn low_stop(&self) {
252        self.registers.tasks_lfclkstop.write(Control::ENABLE::SET);
253    }
254
255    /// Check if the low frequency clock has started
256    pub fn low_started(&self) -> bool {
257        self.registers
258            .events_lfclkstarted
259            .matches_all(Status::READY::SET)
260    }
261
262    /// Read clock source from the low frequency clock
263    pub fn low_source(&self) -> LowClockSource {
264        match self.registers.lfclkstat.read(LfClkStat::SRC) {
265            0b1 => LowClockSource::XTAL,
266            0b10 => LowClockSource::SYNTH,
267            _ => LowClockSource::RC,
268        }
269    }
270
271    /// Check if the low frequency clock is running
272    pub fn low_running(&self) -> bool {
273        self.registers
274            .lfclkstat
275            .matches_all(LfClkStat::STATE::RUNNING)
276    }
277
278    /// Set low frequency clock source
279    pub fn low_set_source(&self, clock_source: LowClockSource) {
280        self.registers
281            .lfclksrc
282            .write(LfClkSrc::SRC.val(clock_source as u32));
283    }
284}