1use 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
132pub enum InterruptField {
134 HFCLKSTARTED = 1 << 0,
135 LFCLKSTARTED = 1 << 1,
136 DONE = 1 << 3,
137 CTTO = 1 << 4,
138}
139
140pub enum LowClockSource {
142 RC = 0,
143 XTAL = 1,
144 SYNTH = 2,
145 MASK = 3,
146}
147
148pub enum HighClockSource {
150 RC = 0,
151 XTAL = 1,
152}
153
154pub struct Clock {
156 registers: StaticRef<ClockRegisters>,
157 client: OptionalCell<&'static dyn ClockClient>,
158}
159
160pub trait ClockClient {
161 fn event(&self);
166}
167
168impl Clock {
169 pub const fn new() -> Clock {
171 Clock {
172 registers: CLOCK_BASE,
173 client: OptionalCell::empty(),
174 }
175 }
176
177 pub fn set_client(&self, client: &'static dyn ClockClient) {
179 self.client.set(client);
180 }
181
182 pub fn interrupt_enable(&self, interrupt: InterruptField) {
184 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 pub fn interrupt_disable(&self, interrupt: InterruptField) {
199 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 pub fn high_start(&self) {
215 self.registers.tasks_hfclkstart.write(Control::ENABLE::SET);
216 }
217
218 pub fn high_stop(&self) {
220 self.registers.tasks_hfclkstop.write(Control::ENABLE::SET);
221 }
222
223 pub fn high_started(&self) -> bool {
225 self.registers
226 .events_hfclkstarted
227 .matches_all(Status::READY.val(1))
228 }
229
230 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 pub fn high_running(&self) -> bool {
240 self.registers
241 .hfclkstat
242 .matches_all(HfClkStat::STATE::RUNNING)
243 }
244
245 pub fn low_start(&self) {
247 self.registers.tasks_lfclkstart.write(Control::ENABLE::SET);
248 }
249
250 pub fn low_stop(&self) {
252 self.registers.tasks_lfclkstop.write(Control::ENABLE::SET);
253 }
254
255 pub fn low_started(&self) -> bool {
257 self.registers
258 .events_lfclkstarted
259 .matches_all(Status::READY::SET)
260 }
261
262 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 pub fn low_running(&self) -> bool {
273 self.registers
274 .lfclkstat
275 .matches_all(LfClkStat::STATE::RUNNING)
276 }
277
278 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}