rp2040/xosc.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
5use kernel::utilities::registers::interfaces::{ReadWriteable, Readable};
6use kernel::utilities::registers::{register_bitfields, register_structs, ReadWrite};
7use kernel::utilities::StaticRef;
8
9register_structs! {
10 /// Controls the crystal oscillator
11 XoscRegisters {
12 /// Crystal Oscillator Control
13 (0x000 => ctrl: ReadWrite<u32, CTRL::Register>),
14 /// Crystal Oscillator Status
15 (0x004 => status: ReadWrite<u32, STATUS::Register>),
16 /// Crystal Oscillator pause control\n
17 /// This is used to save power by pausing the XOSC\n
18 /// On power-up this field is initialised to WAKE\n
19 /// An invalid write will also select WAKE\n
20 /// WARNING: stop the PLLs before selecting dormant mode\n
21 /// WARNING: setup the irq before selecting dormant mode
22 (0x008 => dormant: ReadWrite<u32, DORMANT::Register>),
23 /// Controls the startup delay
24 (0x00C => startup: ReadWrite<u32, STARTUP::Register>),
25 (0x010 => _reserved0),
26 /// A down counter running at the xosc frequency which counts to zero and stops.\n
27 /// To start the counter write a non-zero value.\n
28 /// Can be used for short software pauses when setting up time sensitive
29 (0x01C => count: ReadWrite<u32>),
30 (0x020 => @END),
31 }
32}
33
34register_bitfields![u32,
35 CTRL [
36 /// On power-up this field is initialised to DISABLE and the chip runs from the ROSC
37 /// If the chip has subsequently been programmed to run from the XOS
38 /// The 12-bit code is intended to give some protection against acci
39 ENABLE OFFSET(12) NUMBITS(12) [
40 ENABLE = 0xfab,
41 DISABLE = 0xd1e
42 ],
43 /// Frequency range. This resets to 0xAA0 and cannot be changed.
44 FREQ_RANGE OFFSET(0) NUMBITS(12) [
45
46 _1_15MHZ = 0xaa0
47 ]
48 ],
49 STATUS [
50 /// Oscillator is running and stable
51 STABLE OFFSET(31) NUMBITS(1) [],
52 /// An invalid value has been written to CTRL_ENABLE or CTRL_FREQ_RANGE or DORMANT
53 BADWRITE OFFSET(24) NUMBITS(1) [],
54 /// Oscillator is enabled but not necessarily running and stable, resets to 0
55 ENABLED OFFSET(12) NUMBITS(1) [],
56 /// The current frequency range setting, always reads 0
57 FREQ_RANGE OFFSET(0) NUMBITS(2) [
58
59 _1_15MHZ = 0
60 ]
61 ],
62 DORMANT [
63 VALUE OFFSET (0) NUMBITS (32) [
64 DORMANT = 0x636f6d61,
65 WAKE = 0x77616b65
66 ]
67 ],
68 STARTUP [
69 /// Multiplies the startup_delay by 4. This is of little value to the user given tha
70 X4 OFFSET(20) NUMBITS(1) [],
71 /// in multiples of 256*xtal_period
72 DELAY OFFSET(0) NUMBITS(14) []
73 ],
74 COUNT [
75
76 COUNT OFFSET(0) NUMBITS(8) []
77 ]
78];
79
80const XOSC_BASE: StaticRef<XoscRegisters> =
81 unsafe { StaticRef::new(0x40024000 as *const XoscRegisters) };
82
83pub struct Xosc {
84 registers: StaticRef<XoscRegisters>,
85}
86
87impl Xosc {
88 pub const fn new() -> Self {
89 Self {
90 registers: XOSC_BASE,
91 }
92 }
93
94 pub fn init(&self) {
95 // there is only one frequency range available
96 // RP2040 Manual https://datasheets.raspberrypi.org/rp2040/rp2040-datasheet.pdf section 2.16.7
97 self.registers.ctrl.modify(CTRL::FREQ_RANGE::_1_15MHZ);
98 let startup_delay = (((12 * 1000000) / 1000) + 128) / 256;
99 self.registers
100 .startup
101 .modify(STARTUP::DELAY.val(startup_delay));
102 self.registers.ctrl.modify(CTRL::ENABLE::ENABLE);
103 // wait for the oscillator to become stable
104 while !self.registers.status.is_set(STATUS::STABLE) {}
105 }
106
107 pub fn disable(&self) {
108 self.registers.ctrl.modify(CTRL::ENABLE::DISABLE);
109 }
110
111 /// disable the oscillator until an interrupt arrives
112 pub fn dormant(&self) {
113 self.registers.dormant.modify(DORMANT::VALUE::DORMANT);
114 // wait for the oscillator to become stable
115 while !self.registers.status.is_set(STATUS::STABLE) {}
116 }
117}