1use core::convert::TryFrom;
2
3use mk20d7::{mcg::RegisterBlock, mcg::c1};
4
5use sim::MAXIMUM_CLOCK_FREQUENCY;
6use bitrate::{U32BitrateExt, KiloHertz, MegaHertz};
7
8pub const FLL_RANGE_MIN: f32 = 31.25;
9pub const FLL_RANGE_MAX: f32 = 39.0625;
10
11pub const PLL_DIVIDER_NUMERATOR_MIN: u8 = 24;
12pub const PLL_DIVIDER_NUMERATOR_MAX: u8 = 55;
13pub const PLL_DIVIDER_DENOMINATOR_MIN: u8 = 1;
14pub const PLL_DIVIDER_DENOMINATOR_MAX: u8 = 25;
15
16pub struct MultipurposeClockGenerator<'a> {
17 mcg: &'a RegisterBlock,
18 pub external_crystal_frequency: MegaHertz<u32>,
19}
20
21pub struct Fei<'a> { mcg: &'a mut MultipurposeClockGenerator<'a> }
22#[allow(dead_code)] pub struct Fee<'a> { mcg: &'a mut MultipurposeClockGenerator<'a> }
23#[allow(dead_code)] pub struct Fbi<'a> { mcg: &'a mut MultipurposeClockGenerator<'a> }
24pub struct Fbe<'a> { mcg: &'a mut MultipurposeClockGenerator<'a> }
25pub struct Pee<'a> { #[allow(dead_code)] mcg: &'a mut MultipurposeClockGenerator<'a> }
26pub struct Pbe<'a> { mcg: &'a mut MultipurposeClockGenerator<'a> }
27#[allow(dead_code)] pub struct Blpi<'a> { mcg: &'a mut MultipurposeClockGenerator<'a> }
28#[allow(dead_code)] pub struct Blpe<'a> { mcg: &'a mut MultipurposeClockGenerator<'a> }
29#[allow(dead_code)] pub struct Stop<'a> { mcg: &'a mut MultipurposeClockGenerator<'a> }
30
31pub enum ClockMode<'a> {
33 Fei(Fei<'a>), Fee(Fee<'a>), Fbi(Fbi<'a>), Fbe(Fbe<'a>), Pee(Pee<'a>), Pbe(Pbe<'a>), Blpi(Blpi<'a>), Blpe(Blpe<'a>), Stop(Stop<'a>), }
43
44impl<'a> MultipurposeClockGenerator<'a> {
45 pub fn new(mcg: &'a RegisterBlock, external_crystal_frequency: MegaHertz<u32>) -> MultipurposeClockGenerator<'a> {
46 MultipurposeClockGenerator { mcg, external_crystal_frequency }
47 }
48
49 pub fn clock_mode(&'a mut self) -> ClockMode<'a> {
50 let clock_source = self.mcg.c1.read().clks();
51 let internal_clock_reference = self.mcg.c1.read().irefs().bit_is_set();
52 let pll_enabled = self.mcg.c6.read().plls().bit_is_set();
53 let low_power_enabled = self.mcg.c2.read().lp().bit_is_set();
54
55 let external_crystal_frequency_khz: KiloHertz<u32> = self.external_crystal_frequency.into();
56 let fll = external_crystal_frequency_khz.0 as f32 / f32::from(self.get_external_crystal_frequency_divider());
57 let fll_range_ok = fll >= FLL_RANGE_MIN && fll <= FLL_RANGE_MAX;
58
59 let mcg = self;
60 match (clock_source, internal_clock_reference, pll_enabled, low_power_enabled, fll_range_ok) {
61 (c1::CLKSR::_00, true, false, _, _) => ClockMode::Fei(Fei { mcg }),
62 (c1::CLKSR::_00, false, false, _, true) => ClockMode::Fee(Fee { mcg }),
63 (c1::CLKSR::_01, true, false, false, _) => ClockMode::Fbi(Fbi { mcg }),
64 (c1::CLKSR::_10, false, false, false, true) => ClockMode::Fbe(Fbe { mcg }),
65 (c1::CLKSR::_00, false, true, _, _) => ClockMode::Pee(Pee { mcg }),
66 (c1::CLKSR::_10, false, true, false, _) => ClockMode::Pbe(Pbe { mcg }),
67 (c1::CLKSR::_01, true, false, true, _) => ClockMode::Blpi(Blpi { mcg }),
68 (c1::CLKSR::_10, false, _, true, _) => ClockMode::Blpe(Blpe { mcg }),
69 _ => panic!("The current clock mode cannot be represented as a known struct"),
70 }
71 }
72
73 pub fn external_crystal_is_requested(&self) -> bool {
74 self.mcg.c2.read().erefs0().bit_is_set()
75 }
76
77 pub fn enable_external_crystal_request(&mut self) {
78 if self.external_crystal_is_requested() { return; }
79 self.mcg.c2.write(|w| w.erefs0().set_bit());
80 while self.mcg.s.read().oscinit0().bit_is_clear() {} }
82
83 pub fn disable_external_crystal_request(&mut self) {
84 if !self.external_crystal_is_requested() { return; }
85 self.mcg.c2.write(|w| w.erefs0().clear_bit());
86 while self.mcg.s.read().oscinit0().bit_is_set() {} }
88
89 pub fn set_external_crystal_frequency_range_low(&mut self) {
90 self.mcg.c2.write(|w| w.range0()._00());
91 }
92
93 pub fn set_external_crystal_frequency_range_high(&mut self) {
94 self.mcg.c2.write(|w| w.range0()._01());
95 }
96
97 pub fn set_external_crystal_frequency_divider(&self, divider: u16) {
98 let crystal_low_frequency = self.mcg.c2.read().range0().is_00();
99 let real_time_clock = self.mcg.c7.read().oscsel().bit_is_set();
100 let rtc_or_low_freq_crystal = crystal_low_frequency || real_time_clock;
101
102 self.mcg.c1.write(
103 |w| {
104 let frdiv_w = w.frdiv();
105 match divider {
106 _ if rtc_or_low_freq_crystal && divider == 1 || divider == 32 => frdiv_w._000(),
107 _ if rtc_or_low_freq_crystal && divider == 2 || divider == 64 => frdiv_w._001(),
108 _ if rtc_or_low_freq_crystal && divider == 4 || divider == 128 => frdiv_w._010(),
109 _ if rtc_or_low_freq_crystal && divider == 8 || divider == 256 => frdiv_w._011(),
110 _ if rtc_or_low_freq_crystal && divider == 16 || divider == 512 => frdiv_w._100(),
111 _ if rtc_or_low_freq_crystal && divider == 32 || divider == 1024 => frdiv_w._101(),
112 _ if rtc_or_low_freq_crystal && divider == 64 || divider == 1280 => frdiv_w._110(),
113 _ if rtc_or_low_freq_crystal && divider == 128 || divider == 1536 => frdiv_w._111(),
114 _ => panic!("Invalid external clock divider: {}", divider),
115 }
116 }
117 );
118 }
119
120 pub fn get_external_crystal_frequency_divider(&self) -> u16 {
121 let crystal_low_frequency = self.mcg.c2.read().range0().is_00();
122 let real_time_clock = self.mcg.c7.read().oscsel().bit_is_set();
123 let rtc_or_low_freq_crystal = crystal_low_frequency || real_time_clock;
124
125 match self.mcg.c1.read().frdiv() {
126 c1::FRDIVR::_000 => if rtc_or_low_freq_crystal { 1 } else { 32 },
127 c1::FRDIVR::_001 => if rtc_or_low_freq_crystal { 2 } else { 64 },
128 c1::FRDIVR::_010 => if rtc_or_low_freq_crystal { 4 } else { 128 },
129 c1::FRDIVR::_011 => if rtc_or_low_freq_crystal { 8 } else { 256 },
130 c1::FRDIVR::_100 => if rtc_or_low_freq_crystal { 16 } else { 512 },
131 c1::FRDIVR::_101 => if rtc_or_low_freq_crystal { 32 } else { 1024 },
132 c1::FRDIVR::_110 => if rtc_or_low_freq_crystal { 64 } else { 1280 },
133 c1::FRDIVR::_111 => if rtc_or_low_freq_crystal { 128 } else { 1536 },
134 }
135 }
136
137 pub fn use_external_crystal(&mut self) {
138 self.mcg.c1.write(
139 |w| {
140 w.clks()._10();
141 w.irefs().clear_bit()
142 }
143 );
144
145 while self.mcg.s.read().irefst().bit_is_set() {} while !self.mcg.s.read().clkst().is_10() {} }
150
151 pub fn set_pll_frequency_divider(&mut self, numerator: u8, denominator: u8) {
152 if numerator < PLL_DIVIDER_NUMERATOR_MIN || numerator > PLL_DIVIDER_NUMERATOR_MAX {
153 panic!("Invalid PLL VCO divide factor: {}", numerator);
154 }
155
156 if denominator < PLL_DIVIDER_DENOMINATOR_MIN || denominator > PLL_DIVIDER_DENOMINATOR_MAX {
157 panic!("Invalid PLL reference divide factor: {}", denominator);
158 }
159
160 self.mcg.c5.write(|w| unsafe { w.prdiv0().bits(denominator - PLL_DIVIDER_DENOMINATOR_MIN) });
161 self.mcg.c6.write(|w| unsafe { w.vdiv0().bits(numerator - PLL_DIVIDER_NUMERATOR_MIN) });
162 }
163
164 pub fn get_pll_frequency_divider(&self) -> (u8, u8) {
165 let numerator = self.mcg.c6.read().vdiv0().bits() + PLL_DIVIDER_NUMERATOR_MIN;
166 let denominator = self.mcg.c5.read().prdiv0().bits() + PLL_DIVIDER_DENOMINATOR_MIN;
167 (numerator, denominator)
168 }
169
170 pub fn set_pll_frequency(&mut self, frequency: MegaHertz<u32>) {
171 let divider = pll_frequency_divider_gcd(
172 u8::try_from(frequency.0).unwrap(),
173 u8::try_from(self.external_crystal_frequency.0).unwrap()
174 );
175 self.set_pll_frequency_divider(divider.0, divider.1);
176 }
177
178 pub fn get_pll_frequency(&self) -> MegaHertz<u32> {
179 let (numerator, denominator) = self.get_pll_frequency_divider();
180 let num = u32::from(numerator);
181 let den = u32::from(denominator);
182 ((num * self.external_crystal_frequency.0) / den).mhz()
183 }
184
185 pub fn enable_pll(&mut self) {
186 self.mcg.c6.write(|w| w.plls().set_bit());
187 while self.mcg.s.read().pllst().bit_is_clear() {} while self.mcg.s.read().lock0().bit_is_clear() {} }
190
191 pub fn use_pll(&mut self) {
192 self.mcg.c1.write(|w| w.clks()._10());
193
194 while !self.mcg.s.read().clkst().is_10() {}
199 }
200}
201
202impl<'a> Into<Fbe<'a>> for Fei<'a> {
203 fn into(self) -> Fbe<'a> {
204 self.mcg.set_external_crystal_frequency_range_high();
205 self.mcg.enable_external_crystal_request();
206 self.mcg.set_external_crystal_frequency_divider(512); self.mcg.use_external_crystal();
208 match self.mcg.clock_mode() {
209 ClockMode::Fbe(fbe) => fbe,
210 _ => panic!("Somehow the clock wasn't in FBE mode"),
211 }
212 }
213}
214
215impl<'a> Into<Pbe<'a>> for Fbe<'a> {
216 fn into(self) -> Pbe<'a> {
217 self.mcg.set_pll_frequency(u32::from(MAXIMUM_CLOCK_FREQUENCY).mhz()); self.mcg.enable_pll();
219 match self.mcg.clock_mode() {
220 ClockMode::Pbe(pbe) => pbe,
221 _ => panic!("Somehow the clock wasn't in PBE mode"),
222 }
223 }
224}
225
226impl<'a> Into<Pee<'a>> for Pbe<'a> {
227 fn into(self) -> Pee<'a> {
228 self.mcg.use_pll();
229 match self.mcg.clock_mode() {
230 ClockMode::Pee(pee) => pee,
231 _ => panic!("Somehow the clock wasn't in PEE mode"),
232 }
233 }
234}
235
236fn pll_frequency_divider_gcd(numerator: u8, denominator: u8) -> (u8, u8) {
237 let mut num = numerator;
239 let mut den = denominator;
240 while den != 0 {
241 let temp = den;
242 den = num % den;
243 num = temp;
244 }
245 let gcd = num;
246 num = numerator / gcd;
247 den = denominator / gcd;
248
249 if num == 0 || den == 0 || num > PLL_DIVIDER_NUMERATOR_MAX || den > PLL_DIVIDER_DENOMINATOR_MAX {
251 panic!("Cannot find a GCD for PLL frequency divider {}/{}.", numerator, denominator);
252 }
253
254 let mut freq_num = num;
256 let mut freq_den = den;
257 let mut mul = 1;
258 while freq_num < PLL_DIVIDER_NUMERATOR_MIN || freq_den < PLL_DIVIDER_DENOMINATOR_MIN {
259 mul += 1;
260 match (num.checked_mul(mul), den.checked_mul(mul)) {
261 (Some(new_freq_num), Some(new_freq_den)) if
262 new_freq_num <= PLL_DIVIDER_NUMERATOR_MAX &&
263 new_freq_den <= PLL_DIVIDER_DENOMINATOR_MAX => {
264 freq_num = new_freq_num;
265 freq_den = new_freq_den;
266 },
267 _ => panic!("Cannot find a GCD for PLL frequency divider {}/{}.", numerator, denominator),
268 }
269 }
270
271 (freq_num, freq_den)
272}