Skip to main content

imxrt_hal/chip/drivers/ccm_10xx/
clock_gate.rs

1//! Functions for reading and manipulating clock gates.
2//!
3//! Use these functions to acquire [`Locator`]s to peripheral clock
4//! gates. Once you have a locator, use `set` to change the gate, and
5//! `get` to read the gate.
6//!
7//! Some locator-returning functions require a constant `N`, representing
8//! the Nth peripheral (the '4' in GPIO4). An invalid `N` for a given
9//! peripheral generates a compile-time error.
10//!
11//! ```no_run
12//! use imxrt_hal as hal;
13//! use imxrt_ral as ral;
14//!
15//! use hal::ccm::clock_gate;
16//!
17//! # || -> Option<()> {
18//! let mut ccm = unsafe { ral::ccm::CCM::instance() };
19//! // OK: GPT1 is valid.
20//! let setting = clock_gate::gpt_serial::<1>().get(&ccm);
21//! # Some(()) }();
22//! ```
23//! ```compile_fail
24//! # use imxrt_hal as hal;
25//! # use imxrt_ral as ral;
26//! # use hal::ccm::clock_gate;
27//! # || -> Option<()> {
28//! # let mut ccm = unsafe { ral::ccm::CCM::instance() };
29//! // ERROR: GPT33 is NOT a real peripheral.
30//! let setting = clock_gate::gpt_serial::<33>().get(&ccm);
31//! # Some(()) }();
32//! ```
33//!
34//! # Aggregate clock gates
35//!
36//! The module exposes collections of aggregate clock gates. It forms
37//! collections based on the root clock. The ordering of clock gates
38//! within these collections are unspecified.
39//!
40//! Additionally, the size of each collection may vary by chip. Since
41//! the collections are `const`, their size is known at compile time.
42//!
43//! ```no_run
44//! use imxrt_hal as hal;
45//! use imxrt_ral as ral;
46//!
47//! use hal::ccm::clock_gate;
48//!
49//! # || -> Option<()> {
50//! let mut ccm = unsafe { ral::ccm::CCM::instance() };
51//!
52//! // Turn on all clock gates downstream of the IPG clock.
53//! clock_gate::IPG_CLOCK_GATES.iter().for_each(|clock_gate| {
54//!     clock_gate.set(&mut ccm, clock_gate::ON);
55//! });
56//! # Some(()) }();
57//! ```
58
59use crate::ral::{self, ccm::CCM};
60
61/// A clock gate setting.
62#[cfg_attr(feature = "defmt", derive(defmt::Format))]
63#[derive(Debug, Clone, Copy, PartialEq, Eq)]
64#[repr(u32)]
65pub enum Setting {
66    /// Clock is off in all modes.
67    Off = 0,
68    /// Clock is on in run mode, but off in WAIT and STOP modes.
69    OnlyRun = 1,
70    /// Clock is on in all modes, except stop mode.
71    On = 3,
72}
73
74/// Helper constant to turn off clock gates.
75pub const OFF: Setting = Setting::Off;
76/// Helper constant to turn on clock gates.
77pub const ON: Setting = Setting::On;
78
79impl Setting {
80    fn from_raw(raw: u32) -> Self {
81        match raw {
82            0 => Setting::Off,
83            1 => Setting::OnlyRun,
84            3 => Setting::On,
85            _ => unreachable!(), // Reserved value in two bit field.
86        }
87    }
88}
89
90/// Clock gating register.
91#[cfg_attr(feature = "defmt", derive(defmt::Format))]
92#[derive(Debug, Clone, Copy, PartialEq, Eq)]
93#[allow(unused)]
94#[repr(u8)]
95enum Register {
96    CCGR0,
97    CCGR1,
98    CCGR2,
99    CCGR3,
100    CCGR4,
101    CCGR5,
102    CCGR6,
103    CCGR7,
104}
105
106use Register::*;
107
108/// Clock gate.
109#[cfg_attr(feature = "defmt", derive(defmt::Format))]
110#[derive(Debug, Clone, Copy, PartialEq, Eq)]
111#[allow(unused)]
112#[repr(u8)]
113enum Gate {
114    CG0,
115    CG1,
116    CG2,
117    CG3,
118    CG4,
119    CG5,
120    CG6,
121    CG7,
122    CG8,
123    CG9,
124    CG10,
125    CG11,
126    CG12,
127    CG13,
128    CG14,
129    CG15,
130}
131
132use Gate::*;
133
134impl Gate {
135    /// Compute the bitshift required to access this gate field
136    /// in the register.
137    #[inline(always)]
138    const fn shift(self) -> usize {
139        self as usize * 2
140    }
141}
142
143/// A clock gate locator.
144///
145/// These are reachable through the various function
146/// provided in this module.
147#[cfg_attr(feature = "defmt", derive(defmt::Format))]
148#[derive(Debug, PartialEq, Eq, Clone, Copy)]
149pub struct Locator {
150    register: Register,
151    gate: Gate,
152}
153
154const fn locator(register: Register, gate: Gate) -> Locator {
155    Locator { register, gate }
156}
157
158/// Acquire the clock gate register for a clock gate locator.
159#[inline(always)]
160fn clock_gate_register(ccm: &CCM, register: Register) -> &ral::RWRegister<u32> {
161    match register {
162        Register::CCGR0 => &ccm.CCGR0,
163        Register::CCGR1 => &ccm.CCGR1,
164        Register::CCGR2 => &ccm.CCGR2,
165        Register::CCGR3 => &ccm.CCGR3,
166        Register::CCGR4 => &ccm.CCGR4,
167        Register::CCGR5 => &ccm.CCGR5,
168        Register::CCGR6 => &ccm.CCGR6,
169        Register::CCGR7 => {
170            // If we're compiling this code, it's because a chip feature
171            // is activated.
172            cfg_if::cfg_if! {
173                if #[cfg(any(chip = "imxrt1060", chip = "imxrt1064"))] {
174                    // Only certain i.MX RT 10xx chips have CCGR7.
175                    &ccm.CCGR7
176                } else {
177                    // The RAL's 'Valid' trait ensures that no clock gate locator
178                    // with this clock gate register is reachable.
179                    unreachable!()
180                }
181            }
182        }
183    }
184}
185
186impl Locator {
187    /// Get the clock gate setting for the peripheral.
188    pub fn get(&self, ccm: &CCM) -> Setting {
189        let ccgr = clock_gate_register(ccm, self.register);
190        let raw = (ccgr.read() >> self.gate.shift()) & 0b11;
191        Setting::from_raw(raw)
192    }
193
194    /// Set the clock gate for this peripheral.
195    pub fn set(&self, ccm: &mut CCM, setting: Setting) {
196        let ccgr = clock_gate_register(ccm, self.register);
197        let mut raw = ccgr.read();
198        raw &= !(0b11 << self.gate.shift());
199        raw |= (setting as u32) << self.gate.shift();
200        ccgr.write(raw);
201    }
202}
203
204/// Returns the PIT clock gate locator.
205#[inline(always)]
206pub const fn pit() -> Locator {
207    locator(CCGR1, CG6)
208}
209
210/// Returns the GPT serial clock gate locator.
211#[inline(always)]
212pub const fn gpt_serial<const N: u8>() -> Locator
213where
214    ral::gpt::Instance<N>: ral::Valid,
215{
216    [locator(CCGR1, CG11), locator(CCGR0, CG13)][N as usize - 1]
217}
218
219/// Returns the GPT serial clock gate locator.
220#[inline(always)]
221pub const fn gpt_bus<const N: u8>() -> Locator
222where
223    ral::gpt::Instance<N>: ral::Valid,
224{
225    [locator(CCGR1, CG10), locator(CCGR0, CG12)][N as usize - 1]
226}
227
228/// Returns the GPIO clock gate locator.
229///
230/// Note that fast GPIOs do not have a clock gate,
231/// so `N` should not describe a fast GPIO port.
232///
233/// # Panics
234///
235/// Panics if `N` describes a fast GPIO port.
236#[inline(always)]
237pub const fn gpio<const N: u8>() -> Locator
238where
239    ral::gpio::Instance<N>: ral::Valid,
240{
241    [
242        locator(CCGR1, CG13),
243        locator(CCGR0, CG15),
244        locator(CCGR2, CG13),
245        locator(CCGR3, CG6),
246        locator(CCGR1, CG15),
247    ][N as usize - 1]
248}
249
250/// Returns the LPUART clock gate locator.
251#[inline(always)]
252pub const fn lpuart<const N: u8>() -> Locator
253where
254    ral::lpuart::Instance<N>: ral::Valid,
255{
256    [
257        locator(CCGR5, CG12),
258        locator(CCGR0, CG14),
259        locator(CCGR0, CG6),
260        locator(CCGR1, CG12),
261        locator(CCGR3, CG1),
262        locator(CCGR3, CG3),
263        locator(CCGR5, CG13),
264        locator(CCGR6, CG7),
265    ][N as usize - 1]
266}
267
268/// Returns the DMA clock gate locator.
269#[inline(always)]
270pub const fn dma() -> Locator {
271    locator(CCGR5, CG3)
272}
273
274/// Returns the LPI2C clock gate locator.
275#[inline(always)]
276pub const fn lpi2c<const N: u8>() -> Locator
277where
278    ral::lpi2c::Instance<N>: ral::Valid,
279{
280    [
281        locator(CCGR2, CG3),
282        locator(CCGR2, CG4),
283        locator(CCGR2, CG5),
284        locator(CCGR6, CG12),
285    ][N as usize - 1]
286}
287
288/// Returns the LPSPI clock gate locator.
289#[inline(always)]
290pub const fn lpspi<const N: u8>() -> Locator
291where
292    ral::lpspi::Instance<N>: ral::Valid,
293{
294    [
295        locator(CCGR1, CG0),
296        locator(CCGR1, CG1),
297        locator(CCGR1, CG2),
298        locator(CCGR1, CG3),
299    ][N as usize - 1]
300}
301
302#[allow(clippy::assertions_on_constants)]
303const _: () = assert!(ral::SOLE_INSTANCE == 0u8);
304
305/// Returns the FlexIO clock gate locator.
306#[inline(always)]
307pub const fn flexio<const N: u8>() -> Locator
308where
309    ral::flexio::Instance<N>: ral::Valid,
310{
311    [
312        locator(CCGR5, CG1),
313        locator(CCGR3, CG0),
314        locator(CCGR7, CG6),
315    ][if N == ral::SOLE_INSTANCE {
316        N as usize
317    } else {
318        N as usize - 1
319    }]
320}
321
322/// Returns the FlexPWM clock gate locator.
323#[inline(always)]
324pub const fn flexpwm<const N: u8>() -> Locator
325where
326    ral::pwm::Instance<N>: ral::Valid,
327{
328    [
329        locator(CCGR4, CG8),
330        locator(CCGR4, CG9),
331        locator(CCGR4, CG10),
332        locator(CCGR4, CG11),
333    ][if N == ral::SOLE_INSTANCE {
334        N as usize
335    } else {
336        N as usize - 1
337    }]
338    // because 1010 has only one PWM instance, and that's
339    // represented by ral::SOLE_INSTANCE (the number 0).
340    // Consider this as the precedent approach when adding
341    // support for 1170 (multiple PIT, DMA peripherals w.r.t
342    // the 10xx families).
343}
344
345/// Returns the TRNG clock gate locator.
346#[inline(always)]
347pub const fn trng() -> Locator {
348    locator(CCGR6, CG6)
349}
350
351/// Returns the SNVS LP clock gate locator.
352#[inline(always)]
353pub const fn snvs_lp() -> Locator {
354    locator(CCGR5, CG15)
355}
356
357/// Returns the SNVS HP clock gate locator.
358#[inline(always)]
359pub const fn snvs_hp() -> Locator {
360    locator(CCGR5, CG14)
361}
362
363/// Returns the USB clock gate locator.
364#[inline(always)]
365pub const fn usb() -> Locator {
366    locator(CCGR6, CG0)
367}
368
369/// Returns the USDHC clock gate locator.
370#[cfg(not(feature = "imxrt1010"))]
371#[inline(always)]
372pub const fn usdhc<const N: u8>() -> Locator
373where
374    ral::usdhc::Instance<N>: ral::Valid,
375{
376    [locator(CCGR6, CG1), locator(CCGR6, CG2)][N as usize - 1]
377}
378
379/// Returns the ADC clock gate locators.
380#[inline(always)]
381pub const fn adc<const N: u8>() -> Locator
382where
383    ral::adc::Instance<N>: ral::Valid,
384{
385    [locator(CCGR1, CG8), locator(CCGR1, CG4)][if N == ral::SOLE_INSTANCE {
386        N as usize
387    } else {
388        N as usize - 1
389    }]
390}
391
392/// Returns the FlexSPI clock gate locator.
393#[inline(always)]
394pub const fn flexspi<const N: u8>() -> Locator
395where
396    ral::flexspi::Instance<N>: ral::Valid,
397{
398    [locator(CCGR6, CG5), locator(CCGR7, CG1)][if N == ral::SOLE_INSTANCE {
399        N as usize
400    } else {
401        N as usize - 1
402    }]
403}
404
405/// Returns the SAI clock gate locators.
406#[inline(always)]
407pub const fn sai<const N: u8>() -> Locator
408where
409    ral::sai::Instance<N>: ral::Valid,
410{
411    [
412        locator(CCGR5, CG9),
413        locator(CCGR5, CG10),
414        locator(CCGR5, CG11),
415    ][if N == ral::SOLE_INSTANCE {
416        N as usize
417    } else {
418        N as usize - 1
419    }]
420}
421
422pub use crate::chip::config::ccm::clock_gate::*;