imxrt10xx/
ccm.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::platform::chip::ClockInterface;
6use kernel::utilities::registers::interfaces::{ReadWriteable, Readable, Writeable};
7use kernel::utilities::registers::{register_bitfields, register_structs, ReadOnly, ReadWrite};
8use kernel::utilities::StaticRef;
9
10register_structs! {
11    /// Clock Controller Module
12    CcmRegisters {
13        /// CCM Control Register
14        (0x000 => ccr: ReadWrite<u32, CCR::Register>),
15        (0x004 => _reserved0),
16        /// CCM Status Register
17        (0x008 => csr: ReadOnly<u32, CSR::Register>),
18        /// CCM Clock Switcher Register
19        (0x00C => ccsr: ReadWrite<u32>),
20        /// CCM Arm Clock Root Register
21        (0x010 => cacrr: ReadWrite<u32>),
22        /// CCM Bus Clock Divider Register
23        (0x014 => cbcdr: ReadWrite<u32, CBCDR::Register>),
24        /// CCM Bus Clock Multiplexer Register
25        (0x018 => cbcmr: ReadWrite<u32, CBCMR::Register>),
26        /// CCM Serial Clock Multiplexer Register 1
27        (0x01C => cscmr1: ReadWrite<u32, CSCMR1::Register>),
28        /// CCM Serial Clock Multiplexer Register 2
29        (0x020 => cscmr2: ReadWrite<u32>),
30        /// CCM Serial Clock Divider Register 1
31        (0x024 => cscdr1: ReadWrite<u32, CSCDR1::Register>),
32        /// CCM Clock Divider Register
33        (0x028 => cs1cdr: ReadWrite<u32>),
34        /// CCM Clock Divider Register
35        (0x02C => cs2cdr: ReadWrite<u32>),
36        /// CCM D1 Clock Divider Register
37        (0x030 => cdcdr: ReadWrite<u32>),
38        (0x034 => _reserved1),
39        /// CCM Serial Clock Divider Register 2
40        (0x038 => cscdr2: ReadWrite<u32>),
41        /// CCM Serial Clock Divider Register 3
42        (0x03C => cscdr3: ReadWrite<u32>),
43        (0x040 => _reserved2),
44        /// CCM Divider Handshake In-Process Register
45        (0x048 => cdhipr: ReadOnly<u32>),
46        (0x04C => _reserved3),
47        /// CCM Low Power Control Register
48        (0x054 => clpcr: ReadWrite<u32, CLPCR::Register>),
49        /// CCM Interrupt Status Register
50        (0x058 => cisr: ReadWrite<u32>),
51        /// CCM Interrupt Mask Register
52        (0x05C => cimr: ReadWrite<u32>),
53        /// CCM Clock Output Source Register
54        (0x060 => ccosr: ReadWrite<u32>),
55        /// CCM General Purpose Register
56        (0x064 => cgpr: ReadWrite<u32>),
57        /// CCM Clock Gating Registers
58        (0x068 => ccgr: [ReadWrite<u32, CCGR::Register>; 8]),
59        /// CCM Module Enable Overide Register
60        (0x088 => cmeor: ReadWrite<u32>),
61        (0x08C => @END),
62    }
63}
64
65register_bitfields![u32,
66    CCR [
67        /// Enable for REG_BYPASS_COUNTER
68        RBC_EN OFFSET(27) NUMBITS(1) [],
69        /// Counter for analog_reg_bypass
70        REG_BYPASS_COUNT OFFSET(21) NUMBITS(6) [],
71        /// On chip oscillator enable bit
72        COSC_EN OFFSET(12) NUMBITS(1) [],
73        /// Oscillator ready counter value
74        OSCNT OFFSET(0) NUMBITS(8) []
75    ],
76    CSR [
77        // Status indication of on board oscillator
78        COSC_READY OFFSET(5) NUMBITS(1) [],
79        // Status indication of CAMP2
80        CAMP2_READY OFFSET(3) NUMBITS(1) [],
81        // Status of the value of CCM_REF_EN_B output of ccm
82        REF_EN_B OFFSET(0) NUMBITS(1) []
83    ],
84
85    CBCDR [
86        /// SEMC clock source select
87        SEMC_CLK_SEL OFFSET(6) NUMBITS(1) [],
88        /// SEMC alternative clock select
89        SEMC_ALT_CLK_SEL OFFSET(7) NUMBITS(1) [],
90        /// Divider for ipg podf.
91        IPG_PODF OFFSET(8) NUMBITS(2) [],
92        /// Divider for AHB PODF
93        AHB_PODF OFFSET(10) NUMBITS(3) [],
94        /// Post divider for SEMC clock
95        SEMC_PODF OFFSET(16) NUMBITS(3) [],
96        /// Selector for peripheral main clock
97        PERIPH_CLK_SEL OFFSET(25) NUMBITS(1) [
98            PrePeriphClkSel = 0,
99            PeriphClk2Divided = 1
100        ],
101        /// Divider for periph_clk2_podf.
102        PERIPH_CLK2_PODF OFFSET(27) NUMBITS(3) []
103    ],
104
105    CBCMR [
106        /// Selector for lpspi clock multiplexer
107        LPSPI_CLK_SEL OFFSET(4) NUMBITS(2) [],
108        /// Selector for flexspi2 clock multiplexer
109        FLEXSPI2_CLK_SEL OFFSET(8) NUMBITS(2) [],
110        /// Selector for peripheral clk2 clock multiplexer
111        PERIPH_CLK2_SEL OFFSET(12) NUMBITS(2) [
112            PLL3Sw = 0,
113            Oscillator = 1,
114            PLL2Bypass = 2
115        ],
116        /// Selector for Trace clock multiplexer
117        TRACE_CLK_SEL OFFSET(14) NUMBITS(2) [],
118        /// Selector for pre_periph clock multiplexer
119        PRE_PERIPH_CLK_SEL OFFSET(18) NUMBITS(2) [
120            PLL2 = 0,
121            PLL2_PFD2 = 1,
122            PLL2_PFD0 = 2,
123            PLL1 = 3
124        ],
125        /// Post-divider for LCDIF clock.
126        LCDIF_PODF OFFSET(23) NUMBITS(3) [],
127        /// Divider for LPSPI. Divider should be updated when output clock is gated.
128        LPSPI_PODF OFFSET(26) NUMBITS(3) [],
129        /// Divider for flexspi2 clock root.
130        FLEXSPI2_PODF OFFSET(29) NUMBITS(3) []
131    ],
132
133    CCSR [
134        PLL3_SW_CLK_SEL OFFSET(0) NUMBITS(1) []
135    ],
136
137    CSCMR1 [
138        // Selector for the PERCLK clock multiplexer
139        PERCLK_CLK_SEL OFFSET(6) NUMBITS(1) [
140            // Derive clock from IPG CLK root
141            IpgClockRoot = 0,
142            // Derive clock from OSCILLATOR
143            Oscillator = 1
144        ],
145        // Divider for PERCLK PODF
146        //
147        // 0 = divide by 1
148        // 1 = divide by 2
149        // 2 = divide by 3
150        // ...
151        // 63 = divide by 64
152        PERCLK_PODF OFFSET(0) NUMBITS(6) []
153    ],
154
155    CSCDR1 [
156        // Divider for trace clock
157        TRACE_PODF OFFSET(25) NUMBITS(2) [],
158        // Divider for usdhc2 clock
159        USDHC2_PODF OFFSET(16) NUMBITS(3) [],
160        // Divider for usdhc2 clock
161        USDHC1_PODF OFFSET(11) NUMBITS(3) [],
162        // Selector for the UART clock multiplexor
163        UART_CLK_SEL OFFSET(6) NUMBITS(1) [
164            Pll3 = 0,
165            Oscillator = 1
166        ],
167        // Divider for uart clock podf
168        UART_CLK_PODF OFFSET(0) NUMBITS(6) []
169    ],
170
171    CLPCR [
172        WHATEVER OFFSET(2) NUMBITS(30) [],
173        LPM OFFSET(0) NUMBITS(2) []
174    ],
175
176    // Supports al clock gate registers
177    CCGR [
178        CG15 OFFSET(30) NUMBITS(2) [],
179        CG14 OFFSET(28) NUMBITS(2) [],
180        CG13 OFFSET(26) NUMBITS(2) [],
181        CG12 OFFSET(24) NUMBITS(2) [],
182        CG11 OFFSET(22) NUMBITS(2) [],
183        CG10 OFFSET(20) NUMBITS(2) [],
184        CG9 OFFSET(18) NUMBITS(2) [],
185        CG8 OFFSET(16) NUMBITS(2) [],
186        CG7 OFFSET(14) NUMBITS(2) [],
187        CG6 OFFSET(12) NUMBITS(2) [],
188        CG5 OFFSET(10) NUMBITS(2) [],
189        CG4 OFFSET(8) NUMBITS(2) [],
190        CG3 OFFSET(6) NUMBITS(2) [],
191        CG2 OFFSET(4) NUMBITS(2) [],
192        CG1 OFFSET(2) NUMBITS(2) [],
193        CG0 OFFSET(0) NUMBITS(2) []
194    ],
195];
196
197const CCM_BASE: StaticRef<CcmRegisters> =
198    unsafe { StaticRef::new(0x400FC000 as *const CcmRegisters) };
199
200pub struct Ccm {
201    registers: StaticRef<CcmRegisters>,
202}
203
204/// Describes the UART clock selection
205#[repr(u32)]
206pub enum UartClockSelection {
207    /// PLL3 80M
208    PLL3 = 0,
209    /// osc_clk
210    Oscillator = 1,
211}
212
213impl Ccm {
214    pub const fn new() -> Ccm {
215        Ccm {
216            registers: CCM_BASE,
217        }
218    }
219
220    pub fn set_low_power_mode(&self) {
221        self.registers.clpcr.modify(CLPCR::LPM.val(0b00_u32));
222    }
223
224    // Iomuxc_snvs clock
225    pub fn is_enabled_iomuxc_snvs_clock(&self) -> bool {
226        self.registers.ccgr[2].is_set(CCGR::CG2)
227    }
228
229    pub fn enable_iomuxc_snvs_clock(&self) {
230        self.registers.ccgr[2].modify(CCGR::CG2.val(0b01_u32));
231        self.registers.ccgr[3].modify(CCGR::CG15.val(0b01_u32));
232    }
233
234    pub fn disable_iomuxc_snvs_clock(&self) {
235        self.registers.ccgr[2].modify(CCGR::CG2::CLEAR);
236        self.registers.ccgr[3].modify(CCGR::CG15::CLEAR);
237    }
238
239    /// Iomuxc clock
240    pub fn is_enabled_iomuxc_clock(&self) -> bool {
241        self.registers.ccgr[4].is_set(CCGR::CG0) && self.registers.ccgr[4].is_set(CCGR::CG1)
242    }
243
244    pub fn enable_iomuxc_clock(&self) {
245        self.registers.ccgr[4].modify(CCGR::CG0.val(0b01_u32));
246        self.registers.ccgr[4].modify(CCGR::CG1.val(0b01_u32));
247    }
248
249    pub fn disable_iomuxc_clock(&self) {
250        self.registers.ccgr[4].modify(CCGR::CG0::CLEAR);
251        self.registers.ccgr[4].modify(CCGR::CG1::CLEAR)
252    }
253
254    /// GPIO1 clock
255    pub fn is_enabled_gpio1_clock(&self) -> bool {
256        self.registers.ccgr[1].is_set(CCGR::CG13)
257    }
258
259    pub fn enable_gpio1_clock(&self) {
260        self.registers.ccgr[1].modify(CCGR::CG13.val(0b11_u32))
261    }
262
263    pub fn disable_gpio1_clock(&self) {
264        self.registers.ccgr[1].modify(CCGR::CG13::CLEAR)
265    }
266
267    /// GPIO2 clock
268    pub fn is_enabled_gpio2_clock(&self) -> bool {
269        self.registers.ccgr[0].is_set(CCGR::CG15)
270    }
271
272    pub fn enable_gpio2_clock(&self) {
273        self.registers.ccgr[0].modify(CCGR::CG15.val(0b11_u32))
274    }
275
276    pub fn disable_gpio2_clock(&self) {
277        self.registers.ccgr[0].modify(CCGR::CG15::CLEAR)
278    }
279
280    /// GPIO3 clock
281    pub fn is_enabled_gpio3_clock(&self) -> bool {
282        self.registers.ccgr[2].is_set(CCGR::CG13)
283    }
284
285    pub fn enable_gpio3_clock(&self) {
286        self.registers.ccgr[2].modify(CCGR::CG13.val(0b11_u32))
287    }
288
289    pub fn disable_gpio3_clock(&self) {
290        self.registers.ccgr[2].modify(CCGR::CG13::CLEAR)
291    }
292
293    /// GPIO4 clock
294    pub fn is_enabled_gpio4_clock(&self) -> bool {
295        self.registers.ccgr[3].is_set(CCGR::CG6)
296    }
297
298    pub fn enable_gpio4_clock(&self) {
299        self.registers.ccgr[3].modify(CCGR::CG6.val(0b11_u32))
300    }
301
302    pub fn disable_gpio4_clock(&self) {
303        self.registers.ccgr[3].modify(CCGR::CG6::CLEAR)
304    }
305
306    /// GPIO5 clock
307    pub fn is_enabled_gpio5_clock(&self) -> bool {
308        self.registers.ccgr[1].is_set(CCGR::CG15)
309    }
310
311    pub fn enable_gpio5_clock(&self) {
312        self.registers.ccgr[1].modify(CCGR::CG15.val(0b11_u32))
313    }
314
315    pub fn disable_gpio5_clock(&self) {
316        self.registers.ccgr[1].modify(CCGR::CG15::CLEAR)
317    }
318
319    // GPT1 clock
320    pub fn is_enabled_gpt1_clock(&self) -> bool {
321        self.registers.ccgr[1].is_set(CCGR::CG11)
322    }
323
324    pub fn enable_gpt1_clock(&self) {
325        self.registers.ccgr[1].modify(CCGR::CG10.val(0b11_u32));
326        self.registers.ccgr[1].modify(CCGR::CG11.val(0b11_u32));
327    }
328
329    pub fn disable_gpt1_clock(&self) {
330        self.registers.ccgr[1].modify(CCGR::CG10::CLEAR);
331        self.registers.ccgr[1].modify(CCGR::CG11::CLEAR);
332    }
333
334    // GPT2 clock
335    pub fn is_enabled_gpt2_clock(&self) -> bool {
336        self.registers.ccgr[0].is_set(CCGR::CG13)
337    }
338
339    pub fn enable_gpt2_clock(&self) {
340        self.registers.ccgr[0].modify(CCGR::CG12.val(0b11_u32));
341        self.registers.ccgr[0].modify(CCGR::CG13.val(0b11_u32));
342    }
343
344    pub fn disable_gpt2_clock(&self) {
345        self.registers.ccgr[0].modify(CCGR::CG12::CLEAR);
346        self.registers.ccgr[0].modify(CCGR::CG13::CLEAR);
347    }
348
349    // LPI2C1 clock
350    pub fn is_enabled_lpi2c1_clock(&self) -> bool {
351        self.registers.ccgr[2].is_set(CCGR::CG3)
352    }
353
354    pub fn enable_lpi2c1_clock(&self) {
355        self.registers.ccgr[2].modify(CCGR::CG3.val(0b11_u32));
356    }
357
358    pub fn disable_lpi2c1_clock(&self) {
359        self.registers.ccgr[2].modify(CCGR::CG3::CLEAR);
360    }
361
362    // LPUART1 clock
363    pub fn is_enabled_lpuart1_clock(&self) -> bool {
364        self.registers.ccgr[5].is_set(CCGR::CG12)
365    }
366
367    pub fn enable_lpuart1_clock(&self) {
368        self.registers.ccgr[5].modify(CCGR::CG12.val(0b11_u32));
369    }
370
371    pub fn disable_lpuart1_clock(&self) {
372        self.registers.ccgr[5].modify(CCGR::CG12::CLEAR);
373    }
374
375    // LPUART2 clock
376    pub fn is_enabled_lpuart2_clock(&self) -> bool {
377        self.registers.ccgr[0].is_set(CCGR::CG14)
378    }
379
380    pub fn enable_lpuart2_clock(&self) {
381        self.registers.ccgr[0].modify(CCGR::CG14.val(0b11_u32));
382    }
383
384    pub fn disable_lpuart2_clock(&self) {
385        self.registers.ccgr[0].modify(CCGR::CG14::CLEAR);
386    }
387
388    // UART clock multiplexor
389    pub fn is_enabled_uart_clock_mux(&self) -> bool {
390        self.registers.cscdr1.is_set(CSCDR1::UART_CLK_SEL)
391    }
392
393    /// Set the UART clock selection
394    ///
395    /// Should only be called when *all* UART clock gates are disabled
396    pub fn set_uart_clock_sel(&self, selection: UartClockSelection) {
397        self.registers
398            .cscdr1
399            .modify(CSCDR1::UART_CLK_SEL.val(selection as u32));
400    }
401
402    /// Returns the UART clock selection
403    pub fn uart_clock_sel(&self) -> UartClockSelection {
404        use CSCDR1::UART_CLK_SEL::Value;
405        match self.registers.cscdr1.read_as_enum(CSCDR1::UART_CLK_SEL) {
406            Some(Value::Oscillator) => UartClockSelection::Oscillator,
407            Some(Value::Pll3) => UartClockSelection::PLL3,
408            None => unreachable!("Implemented all UART clock selections"),
409        }
410    }
411
412    /// Set the UART clock divider
413    ///
414    /// `divider` is a value bound by [1, 2^6].
415    pub fn set_uart_clock_podf(&self, divider: u32) {
416        let divider = divider.max(1).min(1 << 6) - 1;
417        self.registers
418            .cscdr1
419            .modify(CSCDR1::UART_CLK_PODF.val(divider));
420    }
421
422    /// Returns the UART clock divider
423    ///
424    /// The return is a value bound by [1, 2^6].
425    pub fn uart_clock_podf(&self) -> u32 {
426        self.registers.cscdr1.read(CSCDR1::UART_CLK_PODF) + 1
427    }
428    //
429    // PERCLK
430    //
431
432    /// Returns the selection for the periodic clock
433    pub fn perclk_sel(&self) -> PerclkClockSel {
434        use CSCMR1::PERCLK_CLK_SEL::Value;
435        match self.registers.cscmr1.read_as_enum(CSCMR1::PERCLK_CLK_SEL) {
436            Some(Value::Oscillator) => PerclkClockSel::Oscillator,
437            Some(Value::IpgClockRoot) => PerclkClockSel::IPG,
438            None => unreachable!("Implemented all periodic clock selections"),
439        }
440    }
441
442    /// Set the periodic clock selection
443    pub fn set_perclk_sel(&self, sel: PerclkClockSel) {
444        let sel = match sel {
445            PerclkClockSel::IPG => CSCMR1::PERCLK_CLK_SEL::IpgClockRoot,
446            PerclkClockSel::Oscillator => CSCMR1::PERCLK_CLK_SEL::Oscillator,
447        };
448        self.registers.cscmr1.modify(sel);
449    }
450
451    /// Set the periodic clock selection and divider
452    ///
453    /// This should only be called when all associated clock gates are disabled.
454    ///
455    /// `divider` will be clamped between 1 and 64.
456    pub fn set_perclk_divider(&self, divider: u8) {
457        let divider: u32 = divider.min(64).max(1).into();
458        self.registers
459            .cscmr1
460            .modify(CSCMR1::PERCLK_PODF.val(divider - 1));
461    }
462
463    /// Returns the periodic clock divider, guaranteed to be non-zero
464    pub fn perclk_divider(&self) -> u8 {
465        (self.registers.cscmr1.read(CSCMR1::PERCLK_PODF) as u8) + 1
466    }
467
468    /// Blocks until *all* handshakes are complete
469    fn wait_for_handshakes(&self) {
470        while self.registers.cdhipr.get() != 0 {}
471    }
472
473    /// Set the ARM clock root divider
474    ///
475    /// The ARM clock divider is just after the PLL1 output.
476    ///
477    /// Clamps `divider` between [1, 8].
478    pub fn set_arm_divider(&self, divider: u32) {
479        let podf = divider.min(8).max(1) - 1;
480        self.registers.cacrr.set(podf);
481        self.wait_for_handshakes();
482    }
483
484    /// Returns the ARM clock root divider
485    pub fn arm_divider(&self) -> u32 {
486        self.registers.cacrr.get() + 1
487    }
488
489    /// Set the PERIPH_CLK2 divider
490    ///
491    /// Clamps `divider` between [1, 8].
492    pub fn set_peripheral_clock2_divider(&self, divider: u32) {
493        let podf = divider.min(8).max(1) - 1;
494        self.registers
495            .cbcdr
496            .modify(CBCDR::PERIPH_CLK2_PODF.val(podf));
497    }
498
499    /// Returns the PERIPH_CLK2 divider
500    pub fn peripheral_clock2_divider(&self) -> u32 {
501        self.registers.cbcdr.read(CBCDR::PERIPH_CLK2_PODF) + 1
502    }
503
504    /// Set the AHB clock divider
505    ///
506    /// Clamps `divider` between [1, 8].
507    pub fn set_ahb_divider(&self, divider: u32) {
508        let podf = divider.min(8).max(1) - 1;
509        self.registers.cbcdr.modify(CBCDR::AHB_PODF.val(podf));
510        self.wait_for_handshakes();
511    }
512
513    /// Returns the AHB clock divider
514    pub fn ahb_divider(&self) -> u32 {
515        self.registers.cbcdr.read(CBCDR::AHB_PODF) + 1
516    }
517
518    /// Sets the IPG clock divider
519    ///
520    /// Clamps `divider` between [1, 4].
521    pub fn set_ipg_divider(&self, divider: u32) {
522        let podf = divider.min(4).max(1) - 1;
523        self.registers.cbcdr.modify(CBCDR::IPG_PODF.val(podf));
524    }
525
526    /// Set the peripheral clock selection
527    pub fn set_peripheral_clock_selection(&self, selection: PeripheralClockSelection) {
528        let selection = match selection {
529            PeripheralClockSelection::PrePeripheralClock => CBCDR::PERIPH_CLK_SEL::PrePeriphClkSel,
530            PeripheralClockSelection::PeripheralClock2Divided => {
531                CBCDR::PERIPH_CLK_SEL::PeriphClk2Divided
532            }
533        };
534        self.registers.cbcdr.modify(selection);
535        self.wait_for_handshakes();
536    }
537
538    /// Returns the peripheral clock selection
539    pub fn peripheral_clock_selection(&self) -> PeripheralClockSelection {
540        use CBCDR::PERIPH_CLK_SEL::Value;
541        match self.registers.cbcdr.read_as_enum(CBCDR::PERIPH_CLK_SEL) {
542            Some(Value::PrePeriphClkSel) => PeripheralClockSelection::PrePeripheralClock,
543            Some(Value::PeriphClk2Divided) => PeripheralClockSelection::PeripheralClock2Divided,
544            None => unreachable!(),
545        }
546    }
547
548    /// Set the pre-peripheral clock selection
549    pub fn set_pre_peripheral_clock_selection(&self, selection: PrePeripheralClockSelection) {
550        let selection = match selection {
551            PrePeripheralClockSelection::Pll2 => CBCMR::PRE_PERIPH_CLK_SEL::PLL2,
552            PrePeripheralClockSelection::Pll2Pfd2 => CBCMR::PRE_PERIPH_CLK_SEL::PLL2_PFD2,
553            PrePeripheralClockSelection::Pll2Pfd0 => CBCMR::PRE_PERIPH_CLK_SEL::PLL2_PFD0,
554            PrePeripheralClockSelection::Pll1 => CBCMR::PRE_PERIPH_CLK_SEL::PLL1,
555        };
556        self.registers.cbcmr.modify(selection);
557    }
558
559    /// Returns the pre-peripheral clock selection
560    pub fn pre_peripheral_clock_selection(&self) -> PrePeripheralClockSelection {
561        use CBCMR::PRE_PERIPH_CLK_SEL::Value;
562        match self.registers.cbcmr.read_as_enum(CBCMR::PRE_PERIPH_CLK_SEL) {
563            Some(Value::PLL2) => PrePeripheralClockSelection::Pll2,
564            Some(Value::PLL2_PFD0) => PrePeripheralClockSelection::Pll2Pfd0,
565            Some(Value::PLL2_PFD2) => PrePeripheralClockSelection::Pll2Pfd2,
566            Some(Value::PLL1) => PrePeripheralClockSelection::Pll1,
567            None => unreachable!(),
568        }
569    }
570
571    /// Set the peripheral clock 2 selection
572    pub fn set_peripheral_clock2_selection(&self, selection: PeripheralClock2Selection) {
573        let selection = match selection {
574            PeripheralClock2Selection::Pll3 => CBCMR::PERIPH_CLK2_SEL::PLL3Sw,
575            PeripheralClock2Selection::Oscillator => CBCMR::PERIPH_CLK2_SEL::Oscillator,
576            PeripheralClock2Selection::Pll2Bypass => CBCMR::PERIPH_CLK2_SEL::PLL2Bypass,
577        };
578        self.registers.cbcmr.modify(selection);
579        self.wait_for_handshakes();
580    }
581
582    /// Returns the selection for peripheral clock 2
583    pub fn peripheral_clock2_selection(&self) -> PeripheralClock2Selection {
584        use CBCMR::PERIPH_CLK2_SEL::Value;
585        match self.registers.cbcmr.read_as_enum(CBCMR::PERIPH_CLK2_SEL) {
586            Some(Value::PLL3Sw) => PeripheralClock2Selection::Pll3,
587            Some(Value::PLL2Bypass) => PeripheralClock2Selection::Pll2Bypass,
588            Some(Value::Oscillator) => PeripheralClock2Selection::Oscillator,
589            None => unreachable!(),
590        }
591    }
592
593    /// Enable the DCDC clock gate
594    pub fn enable_dcdc_clock(&self) {
595        self.registers.ccgr[6].modify(CCGR::CG3.val(0b11));
596    }
597
598    /// Disable the DCDC clock gate
599    pub fn disable_dcdc_clock(&self) {
600        self.registers.ccgr[6].modify(CCGR::CG3.val(0b00));
601    }
602
603    /// Indicates if the DCDC clock gate is enaled
604    pub fn is_enabled_dcdc_clock(&self) -> bool {
605        self.registers.ccgr[6].read(CCGR::CG3) != 0
606    }
607
608    /// Enable the DMA clock gate
609    pub fn enable_dma_clock(&self) {
610        self.registers.ccgr[5].modify(CCGR::CG3.val(0b11));
611    }
612
613    /// Disable the DMA clock gate
614    pub fn disable_dma_clock(&self) {
615        self.registers.ccgr[5].modify(CCGR::CG3.val(0b00));
616    }
617
618    /// Indicates if the DMA clock gate is enabled
619    pub fn is_enabled_dma_clock(&self) -> bool {
620        self.registers.ccgr[5].read(CCGR::CG3) != 0
621    }
622}
623
624/// Clock selections for the main peripheral
625#[derive(PartialEq, Eq)]
626#[repr(u32)]
627pub enum PeripheralClockSelection {
628    /// Pre peripheral clock
629    PrePeripheralClock,
630    /// Peripheral clock 2, with some division
631    PeripheralClock2Divided,
632}
633
634/// Pre-peripheral clock selections
635#[derive(PartialEq, Eq)]
636#[repr(u32)]
637pub enum PrePeripheralClockSelection {
638    Pll2,
639    Pll2Pfd2,
640    Pll2Pfd0,
641    Pll1,
642}
643
644/// Peripheral clock 2 selection
645#[derive(PartialEq, Eq)]
646#[repr(u32)]
647pub enum PeripheralClock2Selection {
648    Pll3,
649    Oscillator,
650    Pll2Bypass,
651}
652
653enum ClockGate {
654    CCGR0(HCLK0),
655    CCGR1(HCLK1),
656    CCGR2(HCLK2),
657    CCGR3(HCLK3),
658    CCGR4(HCLK4),
659    CCGR5(HCLK5),
660    CCGR6(HCLK6),
661}
662
663/// A peripheral clock gate
664///
665/// `PeripheralClock` provides a LPCG API for controlling peripheral
666/// clock gates.
667pub struct PeripheralClock<'a> {
668    ccm: &'a Ccm,
669    clock_gate: ClockGate,
670}
671
672impl<'a> PeripheralClock<'a> {
673    pub const fn ccgr0(ccm: &'a Ccm, gate: HCLK0) -> Self {
674        Self {
675            ccm,
676            clock_gate: ClockGate::CCGR0(gate),
677        }
678    }
679    pub const fn ccgr1(ccm: &'a Ccm, gate: HCLK1) -> Self {
680        Self {
681            ccm,
682            clock_gate: ClockGate::CCGR1(gate),
683        }
684    }
685    pub const fn ccgr2(ccm: &'a Ccm, gate: HCLK2) -> Self {
686        Self {
687            ccm,
688            clock_gate: ClockGate::CCGR2(gate),
689        }
690    }
691    pub const fn ccgr3(ccm: &'a Ccm, gate: HCLK3) -> Self {
692        Self {
693            ccm,
694            clock_gate: ClockGate::CCGR3(gate),
695        }
696    }
697    pub const fn ccgr4(ccm: &'a Ccm, gate: HCLK4) -> Self {
698        Self {
699            ccm,
700            clock_gate: ClockGate::CCGR4(gate),
701        }
702    }
703    pub const fn ccgr5(ccm: &'a Ccm, gate: HCLK5) -> Self {
704        Self {
705            ccm,
706            clock_gate: ClockGate::CCGR5(gate),
707        }
708    }
709    pub const fn ccgr6(ccm: &'a Ccm, gate: HCLK6) -> Self {
710        Self {
711            ccm,
712            clock_gate: ClockGate::CCGR6(gate),
713        }
714    }
715}
716
717pub enum HCLK0 {
718    GPIO2,
719    LPUART2,
720    GPT2,
721}
722
723pub enum HCLK1 {
724    GPIO1,
725    GPIO5,
726    GPT1, // and others ...
727}
728pub enum HCLK2 {
729    LPI2C1,
730    GPIO3,
731    IOMUXCSNVS, // and others ...
732}
733
734pub enum HCLK3 {
735    GPIO4,
736    // and others ...
737}
738
739pub enum HCLK4 {
740    IOMUXC,
741    // and others ...
742}
743
744pub enum HCLK5 {
745    LPUART1,
746    DMA,
747    // and others ...
748}
749
750pub enum HCLK6 {
751    DCDC,
752}
753
754/// Periodic clock selection for GPTs and PITs
755#[derive(Debug, Clone, Copy, PartialEq, Eq)]
756pub enum PerclkClockSel {
757    /// IPG clock selection (default)
758    IPG,
759    /// Crystal oscillator
760    Oscillator,
761}
762
763impl ClockInterface for PeripheralClock<'_> {
764    fn is_enabled(&self) -> bool {
765        match self.clock_gate {
766            ClockGate::CCGR0(ref v) => match v {
767                HCLK0::GPIO2 => self.ccm.is_enabled_gpio2_clock(),
768                HCLK0::GPT2 => self.ccm.is_enabled_gpt2_clock(),
769                HCLK0::LPUART2 => self.ccm.is_enabled_lpuart2_clock(),
770            },
771            ClockGate::CCGR1(ref v) => match v {
772                HCLK1::GPIO1 => self.ccm.is_enabled_gpio1_clock(),
773                HCLK1::GPIO5 => self.ccm.is_enabled_gpio5_clock(),
774                HCLK1::GPT1 => self.ccm.is_enabled_gpt1_clock(),
775            },
776            ClockGate::CCGR2(ref v) => match v {
777                HCLK2::LPI2C1 => self.ccm.is_enabled_lpi2c1_clock(),
778                HCLK2::GPIO3 => self.ccm.is_enabled_gpio3_clock(),
779                HCLK2::IOMUXCSNVS => self.ccm.is_enabled_iomuxc_snvs_clock(),
780            },
781            ClockGate::CCGR3(ref v) => match v {
782                HCLK3::GPIO4 => self.ccm.is_enabled_gpio4_clock(),
783            },
784            ClockGate::CCGR4(ref v) => match v {
785                HCLK4::IOMUXC => self.ccm.is_enabled_iomuxc_clock(),
786            },
787            ClockGate::CCGR5(ref v) => match v {
788                HCLK5::LPUART1 => self.ccm.is_enabled_lpuart1_clock(),
789                HCLK5::DMA => self.ccm.is_enabled_dma_clock(),
790            },
791            ClockGate::CCGR6(ref v) => match v {
792                HCLK6::DCDC => self.ccm.is_enabled_dcdc_clock(),
793            },
794        }
795    }
796
797    fn enable(&self) {
798        match self.clock_gate {
799            ClockGate::CCGR0(ref v) => match v {
800                HCLK0::GPIO2 => self.ccm.enable_gpio2_clock(),
801                HCLK0::GPT2 => self.ccm.enable_gpt2_clock(),
802                HCLK0::LPUART2 => self.ccm.enable_lpuart2_clock(),
803            },
804            ClockGate::CCGR1(ref v) => match v {
805                HCLK1::GPIO1 => self.ccm.enable_gpio1_clock(),
806                HCLK1::GPIO5 => self.ccm.enable_gpio5_clock(),
807                HCLK1::GPT1 => self.ccm.enable_gpt1_clock(),
808            },
809            ClockGate::CCGR2(ref v) => match v {
810                HCLK2::LPI2C1 => self.ccm.enable_lpi2c1_clock(),
811                HCLK2::GPIO3 => self.ccm.enable_gpio3_clock(),
812                HCLK2::IOMUXCSNVS => self.ccm.enable_iomuxc_snvs_clock(),
813            },
814            ClockGate::CCGR3(ref v) => match v {
815                HCLK3::GPIO4 => self.ccm.enable_gpio4_clock(),
816            },
817            ClockGate::CCGR4(ref v) => match v {
818                HCLK4::IOMUXC => self.ccm.enable_iomuxc_clock(),
819            },
820            ClockGate::CCGR5(ref v) => match v {
821                HCLK5::LPUART1 => self.ccm.enable_lpuart1_clock(),
822                HCLK5::DMA => self.ccm.enable_dma_clock(),
823            },
824            ClockGate::CCGR6(ref v) => match v {
825                HCLK6::DCDC => self.ccm.enable_dcdc_clock(),
826            },
827        }
828    }
829
830    fn disable(&self) {
831        match self.clock_gate {
832            ClockGate::CCGR0(ref v) => match v {
833                HCLK0::GPIO2 => self.ccm.disable_gpio2_clock(),
834                HCLK0::GPT2 => self.ccm.disable_gpt2_clock(),
835                HCLK0::LPUART2 => self.ccm.disable_lpuart2_clock(),
836            },
837            ClockGate::CCGR1(ref v) => match v {
838                HCLK1::GPIO1 => self.ccm.disable_gpio1_clock(),
839                HCLK1::GPIO5 => self.ccm.disable_gpio5_clock(),
840                HCLK1::GPT1 => self.ccm.disable_gpt1_clock(),
841            },
842            ClockGate::CCGR2(ref v) => match v {
843                HCLK2::LPI2C1 => self.ccm.disable_lpi2c1_clock(),
844                HCLK2::GPIO3 => self.ccm.disable_gpio3_clock(),
845                HCLK2::IOMUXCSNVS => self.ccm.disable_iomuxc_snvs_clock(),
846            },
847            ClockGate::CCGR3(ref v) => match v {
848                HCLK3::GPIO4 => self.ccm.disable_gpio4_clock(),
849            },
850            ClockGate::CCGR4(ref v) => match v {
851                HCLK4::IOMUXC => self.ccm.disable_iomuxc_clock(),
852            },
853            ClockGate::CCGR5(ref v) => match v {
854                HCLK5::LPUART1 => self.ccm.disable_lpuart1_clock(),
855                HCLK5::DMA => self.ccm.disable_dma_clock(),
856            },
857            ClockGate::CCGR6(ref v) => match v {
858                HCLK6::DCDC => self.ccm.disable_dcdc_clock(),
859            },
860        }
861    }
862}