lpc55s6x_hal/peripherals/
syscon.rs

1//! API for system configuration (SYSCON) - always on
2//!
3//! The entry point to this API is [`SYSCON`]. Please refer to [`SYSCON`]'s
4//! documentation for additional information.
5//!
6//! This module mostly provides infrastructure required by other parts of the
7//! HAL API. For this reason, only a small subset of SYSCON functionality is
8//! currently implemented.
9//!
10//! The SYSCON peripheral is described in the user manual, chapter 4.
11
12// use core::marker::PhantomData;
13
14// use crate::raw::syscon::{
15//     // pdruncfg, presetctrl, starterp1, sysahbclkctrl, PDRUNCFG, PRESETCTRL, STARTERP1, SYSAHBCLKCTRL,
16//     // UARTCLKDIV, UARTFRGDIV, UARTFRGMULT,
17// };
18
19// use cortex_m_semihosting::dbg;
20
21// use crate::raw;
22// use crate::{
23//     time::{
24//         self,
25//         clock,
26//     },
27//     typestates::init_state,
28// };
29
30crate::wrap_always_on_peripheral!(Syscon, SYSCON);
31
32impl Syscon {
33    // TODO: relocate
34    pub fn rev_id(&self) -> u8 {
35        self.raw.dieid.read().rev_id().bits()
36    }
37}
38
39/// The main API for the SYSCON peripheral
40impl Syscon {
41    /// Enables the clock for a peripheral or other hardware component
42    pub fn enable_clock<P: ClockControl>(&mut self, peripheral: &mut P) {
43        peripheral.enable_clock(self);
44    }
45
46    /// Disable peripheral clock
47    pub fn disable_clock<P: ClockControl>(&mut self, peripheral: &mut P) {
48        peripheral.disable_clock(self);
49    }
50
51    /// Check if peripheral clock is enabled
52    pub fn is_clock_enabled<P: ClockControl>(&self, peripheral: &P) -> bool {
53        peripheral.is_clock_enabled(&self)
54    }
55
56    /// Reset a peripheral
57    pub fn reset<P: ResetControl>(&mut self, peripheral: &mut P) {
58        peripheral.assert_reset(self);
59        peripheral.clear_reset(self);
60    }
61
62}
63
64/// TODO: do this systematically
65/// By default, fro_12m is enabled in MAINCLKSELA
66impl Syscon {
67    // pub fn get_main_clk(&self) -> u8 {
68    //     self.raw.mainclksela.read().sel().bits()
69    // }
70
71    // pub fn get_num_wait_states(&self) -> u8 {
72    //     self.raw.fmccr.read().flashtim().bits()
73    // }
74
75    // pub fn set_num_wait_states(&mut self, num_wait_states: u8) {
76    //     self.raw.fmccr.modify(|_, w| unsafe { w.flashtim().bits(num_wait_states) } );
77    // }
78
79    // pub fn set_ahbclkdiv(&self, div: u8) {
80    //     assert!(div >= 1);
81    //     // dbg!(self.raw.ahbclkdiv.read().div().bits());
82    //     self.raw.ahbclkdiv.modify(unsafe { |_, w| w.div().bits(div - 1) });
83    //     // dbg!(self.raw.ahbclkdiv.read().div().bits());
84    // }
85
86    // pub(crate) fn fro1mhz_as_main_clk(&mut self) {
87    //     self.raw.mainclksela.modify(|_, w| w.sel().enum_0x2());
88    // }
89
90    // pub(crate) fn fro12mz_as_main_clk(&mut self) {
91    //     // TODO: change these names in the PAC to their UM names
92    //     // e.g. enum_0x0 -> fro_12m etc.
93    //     self.raw.mainclksela.modify(|_, w| w.sel().enum_0x0());
94    // }
95
96    // pub(crate) fn fro96mhz_as_main_clk(&mut self) {
97    //     // 1. may have to anactrl_fro192m_ctrl_ena_96mhzclk
98
99    //     // 2. set voltage for 96MHz frequency
100
101    //     // 3. set flash access cycles
102    //     // formula is min(8, floor(9e-7*freq))
103    //     // /* see fsl_clock.c, CLOCK_SetFLASHAccessCyclesForFreq */
104    //     // in this case it's 8
105    //     let num_wait_states = 8;
106    //     self.set_num_wait_states(num_wait_states);
107
108    //     // TODO: change these names in the PAC to their UM names
109    //     // e.g. enum_0x0 -> fro_12m etc.
110    //     self.raw.mainclksela.modify(|_, w| w.sel().enum_0x3());
111    //     self.raw.mainclkselb.modify(|_, w| w.sel().enum_0x0());
112    // }
113
114    // /// TODO: Check if fro_hf is actually 96Mhz??
115    // /// UM ANACTRL.FRO192M_CTRL.ENA_96MHZCLK says the 96Mhz clock
116    // /// is disabled by default
117    // pub fn fro_hf_as_usbfs_clk(&mut self) {
118    //     // 96 Mhz via changing main clock and sourcing that
119    //     // self.fro_hf_as_main_clk();
120    //     // self.raw.usb0clksel.modify(|_, w| w.sel().enum_0x0());
121
122    //     // Divide by n = 2 to get 48 Mhz (i.e., write (n - 1))
123    //     dbg!(self.raw.usb0clkdiv.read().div().bits());
124    //     self.raw
125    //         .usb0clkdiv
126    //         .modify(unsafe { |_, w| w.div().bits(0) });
127    //     dbg!(self.raw.usb0clkdiv.read().div().bits());
128    //     // Wait until the clock is stable (fsl_clock.c doesn't do this)
129    //     while self.raw.usb0clkdiv.read().reqflag().is_ongoing() {}
130    //     dbg!(self.raw.usb0clkdiv.read().div().bits());
131
132    //     // Directly pick fro_hf as usbfs clock
133    //     self.raw.usb0clksel.modify(|_, w| w.sel().enum_0x3());
134    // }
135
136    // pub fn is_enabled_usb0_hostm(&self) -> bool {
137    //     self.raw.ahbclkctrl2.read().usb0_hostm().is_enable()
138    // }
139
140    // pub fn enable_usb0_hostm(&mut self) {
141    //     self.raw.ahbclkctrl2.modify(|_, w| w.usb0_hostm().enable());
142    // }
143
144    // pub fn is_enabled_usb0_hosts(&self) -> bool {
145    //     self.raw.ahbclkctrl2.read().usb0_hosts().is_enable()
146    // }
147
148    // pub fn enable_usb0_hosts(&mut self) {
149    //     self.raw.ahbclkctrl2.modify(|_, w| w.usb0_hosts().enable());
150    // }
151}
152
153/// Internal trait for controlling peripheral clocks
154///
155/// This trait is an internal implementation detail and should neither be
156/// implemented nor used outside of LPC82x HAL. Any changes to this trait won't
157/// be considered breaking changes.
158///
159/// Compared to https://git.io/fjpf9 (in lpc-rs/lpc8xx-hal/lpc8xx-hal-common)
160/// we use a less minimal API in order to hide the fact that there are three
161/// different AHLBCKLCTRL?, which a HAL user shouldn't really need to know about.
162pub trait ClockControl {
163    /// Internal method to enable a peripheral clock
164    fn enable_clock(&self, s: &mut Syscon);
165
166    /// Internal method to disable a peripheral clock
167    fn disable_clock(&self, s: &mut Syscon);
168
169    /// Check if peripheral clock is enabled
170    fn is_clock_enabled(&self, s: &Syscon) -> bool;
171}
172
173//
174// Unwrapped implementation for easier understanding
175//
176// impl ClockControl for raw::UTICK {
177//     fn enable_clock<'h>(&self, h: &'h mut Handle) -> &'h mut Handle {
178//         h.ahbclkctrl1.modify(|_, w| w.utick0().enable());
179//         h
180//     }
181
182//     fn disable_clock<'h>(&self, h: &'h mut Handle) -> &'h mut Handle {
183//         h.ahbclkctrl1.modify(|_, w| w.utick0().disable());
184//         h
185//     }
186
187//     fn is_clock_enabled(&self, h: &Handle) -> bool {
188//         h.ahbclkctrl1.read().utick0().is_enable()
189//     }
190// }
191
192macro_rules! impl_clock_control {
193    ($clock_control:ty, $clock:ident, $register:ident) => {
194        impl ClockControl for $clock_control {
195            fn enable_clock(&self, s: &mut Syscon) {
196                s.raw.$register.modify(|_, w| w.$clock().enable());
197                while s.raw.$register.read().$clock().is_disable() {}
198            }
199
200            fn disable_clock(&self, s: &mut Syscon) {
201                s.raw.$register.modify(|_, w| w.$clock().disable());
202            }
203
204            fn is_clock_enabled(&self, s: &Syscon) -> bool {
205                s.raw.$register.read().$clock().is_enable()
206            }
207        }
208    };
209}
210
211impl_clock_control!(raw::ADC0, adc, ahbclkctrl0);
212impl_clock_control!(raw::FLASH, flash, ahbclkctrl0);
213impl_clock_control!(raw::FLEXCOMM0, fc0, ahbclkctrl1);
214impl_clock_control!(raw::FLEXCOMM1, fc1, ahbclkctrl1);
215impl_clock_control!(raw::FLEXCOMM2, fc2, ahbclkctrl1);
216impl_clock_control!(raw::FLEXCOMM3, fc3, ahbclkctrl1);
217impl_clock_control!(raw::FLEXCOMM4, fc4, ahbclkctrl1);
218impl_clock_control!(raw::FLEXCOMM5, fc5, ahbclkctrl1);
219impl_clock_control!(raw::FLEXCOMM6, fc6, ahbclkctrl1);
220impl_clock_control!(raw::FLEXCOMM7, fc7, ahbclkctrl1);
221impl_clock_control!(raw::FLEXCOMM8, hs_lspi, ahbclkctrl2);
222impl_clock_control!(raw::IOCON, iocon, ahbclkctrl0);
223impl_clock_control!(raw::GINT0, gint, ahbclkctrl0);
224impl_clock_control!(raw::PINT, pint, ahbclkctrl0);
225
226impl_clock_control!(raw::USB0, usb0_dev, ahbclkctrl1);
227impl_clock_control!(raw::USBFSH, usb0_hosts, ahbclkctrl2);  // well what about usb0_hostm?
228impl_clock_control!(raw::UTICK0, utick, ahbclkctrl1);
229
230impl_clock_control!(raw::ANACTRL, analog_ctrl, ahbclkctrl2);
231impl_clock_control!(raw::CASPER, casper, ahbclkctrl2);
232// there is no GPIO_SEC. what to do? create a PhantomData one?
233// impl_clock_control!(raw::GPIO_SEC, gpio_sec, ahbclkctrl2);
234impl_clock_control!(raw::PUF, puf, ahbclkctrl2);
235impl_clock_control!(raw::RNG, rng, ahbclkctrl2);
236
237// GPIO needs a separate implementation
238impl ClockControl for raw::GPIO {
239    fn enable_clock(&self, s: &mut Syscon) {
240        s.raw.ahbclkctrl0.modify(|_, w| w.gpio0().enable());
241        s.raw.ahbclkctrl0.modify(|_, w| w.gpio1().enable());
242    }
243
244    fn disable_clock(&self, s: &mut Syscon) {
245        s.raw.ahbclkctrl0.modify(|_, w| w.gpio0().disable());
246        s.raw.ahbclkctrl0.modify(|_, w| w.gpio1().disable());
247    }
248
249    #[allow(clippy::nonminimal_bool)]
250    fn is_clock_enabled(&self, s: &Syscon) -> bool {
251        s.raw.ahbclkctrl0.read().gpio0().is_enable() && s.raw.ahbclkctrl0.read().gpio1().is_enable()
252    }
253}
254
255pub trait ResetControl {
256    /// Internal method to assert peripheral reset
257    fn assert_reset(&self, syscon: &mut Syscon);
258
259    /// Internal method to clear peripheral reset
260    fn clear_reset(&self, syscon: &mut Syscon);
261}
262
263macro_rules! impl_reset_control {
264    ($reset_control:ty, $field:ident, $register:ident) => {
265        impl<'a> ResetControl for $reset_control {
266            fn assert_reset(&self, syscon: &mut Syscon) {
267                syscon.raw.$register.modify(|_, w| w.$field().asserted());
268                while syscon.raw.$register.read().$field().is_released() {}
269            }
270
271            fn clear_reset(&self, syscon: &mut Syscon) {
272                syscon.raw.$register.modify(|_, w| w.$field().released());
273                while syscon.raw.$register.read().$field().is_asserted() {}
274            }
275        }
276    };
277    ($reset_control:ty, $field1:ident, $field2:ident, $register:ident) => {
278        impl<'a> ResetControl for $reset_control {
279            fn assert_reset(&self, syscon: &mut Syscon) {
280                syscon.raw.$register.modify(|_, w| w.$field1().asserted());
281                while syscon.raw.$register.read().$field1().is_released() {}
282                syscon.raw.$register.modify(|_, w| w.$field2().asserted());
283                while syscon.raw.$register.read().$field2().is_released() {}
284            }
285
286            fn clear_reset(&self, syscon: &mut Syscon) {
287                syscon.raw.$register.modify(|_, w| w.$field1().released());
288                while syscon.raw.$register.read().$field1().is_asserted() {}
289                syscon.raw.$register.modify(|_, w| w.$field2().released());
290                while syscon.raw.$register.read().$field2().is_asserted() {}
291            }
292        }
293    };
294}
295
296// to be completed
297impl_reset_control!(raw::CASPER, casper_rst, presetctrl2);
298impl_reset_control!(raw::FLEXCOMM0, fc0_rst, presetctrl1);
299impl_reset_control!(raw::FLEXCOMM1, fc1_rst, presetctrl1);
300impl_reset_control!(raw::FLEXCOMM2, fc2_rst, presetctrl1);
301impl_reset_control!(raw::FLEXCOMM3, fc3_rst, presetctrl1);
302impl_reset_control!(raw::FLEXCOMM4, fc4_rst, presetctrl1);
303impl_reset_control!(raw::FLEXCOMM5, fc5_rst, presetctrl1);
304impl_reset_control!(raw::FLEXCOMM6, fc6_rst, presetctrl1);
305impl_reset_control!(raw::FLEXCOMM7, fc7_rst, presetctrl1);
306impl_reset_control!(raw::FLEXCOMM8, hs_lspi_rst, presetctrl2);
307impl_reset_control!(raw::USB0, usb0_dev_rst, presetctrl1);
308impl_reset_control!(raw::UTICK0, utick_rst, presetctrl1);
309
310impl_reset_control!(raw::USBFSH, usb0_hostm_rst, usb0_hosts_rst, presetctrl2);
311