//! Clock controller module. use crate::ral; pub use ral::ccm::CCM; pub type Instance = ral_registers::Instance; /// Wait for all handshake bits to deassert. fn wait_handshake(ccm: ral::ccm::CCM) { while ral::read_reg!(ral::ccm, ccm, CDHIPR) != 0 {} } /// PERCLK clock. /// /// The PERCLK clock controls GPT and PIT timers. pub mod perclk_clk { use crate::ral::{self, ccm::CCM}; /// PERCLK clock selection. #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(u32)] pub enum Selection { /// Derive from the IPG clock root. Ipg = 0, /// Derive from the oscillator clock. Oscillator = 1, } /// Set the PERCLK clock selection. pub fn set_selection(ccm: CCM, selection: Selection) { ral::modify_reg!(ral::ccm, ccm, CSCMR1, PERCLK_CLK_SEL: selection as u32); } /// Returns the PERCLK clock selection. pub fn selection(ccm: CCM) -> Selection { if ral::read_reg!(ral::ccm, ccm, CSCMR1, PERCLK_CLK_SEL == 1) { Selection::Oscillator } else { Selection::Ipg } } /// The smallest PERCLK divider. pub const MIN_DIVIDER: u32 = 1; /// The largest PERCLK divider. pub const MAX_DIVIDER: u32 = 64; /// Set the PERCLK clock divider. /// /// The implementation clamps `divider` between [`MIN_DIVIDER`] and [`MAX_DIVIDER`]. pub fn set_divider(ccm: CCM, divider: u32) { let podf = divider.clamp(MIN_DIVIDER, MAX_DIVIDER) - 1; ral::modify_reg!(ral::ccm, ccm, CSCMR1, PERCLK_PODF: podf); } /// Returns the PERCLK clock divider. pub fn divider(ccm: CCM) -> u32 { ral::read_reg!(ral::ccm, ccm, CSCMR1, PERCLK_PODF) + 1 } } /// IPG clock. /// /// The IPG clock is divided from the core clock. pub mod ipg_clk { use crate::ral::{self, ccm::CCM}; /// Returns the IPG clock divider. pub fn divider(ccm: CCM) -> u32 { ral::read_reg!(ral::ccm, ccm, CBCDR, IPG_PODF) + 1 } /// The smallest IPG divider. pub const MIN_DIVIDER: u32 = 1; /// The largest IPG divider. pub const MAX_DIVIDER: u32 = 4; /// Sets the IPG clock divider. /// /// The implementation clamps `divider` between [`MIN_DIVIDER`] and [`MAX_DIVIDER`]. pub fn set_divider(ccm: CCM, divider: u32) { let podf = divider.clamp(MIN_DIVIDER, MAX_DIVIDER) - 1; ral::modify_reg!(ral::ccm, ccm, CBCDR, IPG_PODF: podf); } } /// Low power mode. /// /// From the reference manual, /// /// > Setting the low power mode that system will enter on next assertion of dsm_request signal. /// /// Practically, this affects the processor behavior when you use WFI, WFE, or enter another /// low-power state. Low-power settings that aren't "run" halt the ARM SYSTICK peripheral. #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(u32)] pub enum LowPowerMode { /// Remain in run mode when entering low power. RemainInRun = ral::ccm::CLPCR::LPM::RUN, /// Move to wait mode when entering low power. TransferToWait = ral::ccm::CLPCR::LPM::WAIT, /// Stop when entering low power. TransferToStop = ral::ccm::CLPCR::LPM::STOP, } /// Set the CCM low power mode. pub fn set_low_power_mode(ccm: ral::ccm::CCM, mode: LowPowerMode) { ral::modify_reg!(ral::ccm, ccm, CLPCR, LPM: mode as u32); } /// Returns the CCM low power mode. /// /// Returns `None` if the low power mode is the reserved field value. pub fn low_power_mode(ccm: ral::ccm::CCM) -> Option { use ral::ccm::CLPCR::LPM::{RUN, STOP, WAIT}; Some(match ral::read_reg!(ral::ccm, ccm, CLPCR, LPM) { RUN => LowPowerMode::RemainInRun, WAIT => LowPowerMode::TransferToWait, STOP => LowPowerMode::TransferToStop, _ => return None, }) } /// UART clock root. /// /// `uart_clk` provides the clock source for all LPUART peripherals. /// You must disable LPUART clock gates before selecting the clock /// and divider. pub mod uart_clk { use crate::ral::{self, ccm::CCM}; /// Returns the UART clock divider. pub fn divider(ccm: CCM) -> u32 { ral::read_reg!(ral::ccm, ccm, CSCDR1, UART_CLK_PODF) + 1 } /// The smallest UART clock divider. pub const MIN_DIVIDER: u32 = 1; /// The largest UART clock divider. pub const MAX_DIVIDER: u32 = 1 << 6; /// Set the UART clock divider. /// /// The implementation clamps `divider` between [`MIN_DIVIDER`] and [`MAX_DIVIDER`]. pub fn set_divider(ccm: CCM, divider: u32) { let podf = divider.clamp(MIN_DIVIDER, MAX_DIVIDER) - 1; ral::modify_reg!(ral::ccm, ccm, CSCDR1, UART_CLK_PODF: podf); } /// UART clock selection. #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(u32)] pub enum Selection { /// PLL 3 divided by 6. /// /// This is typically 480MHz / 6 == 80MHz. Pll3Div6 = 0, /// 24MHz oscillator. Oscillator = 1, } /// Return the UART clock selection. pub fn selection(ccm: CCM) -> Selection { match ral::read_reg!(ral::ccm, ccm, CSCDR1, UART_CLK_SEL) { 0 => Selection::Pll3Div6, 1 => Selection::Oscillator, _ => unreachable!(), } } /// Set the UART clock selection. pub fn set_selection(ccm: CCM, selection: Selection) { ral::modify_reg!(ral::ccm, ccm, CSCDR1, UART_CLK_SEL: selection as u32); } } /// LPI2C clock root. /// /// `lpi2c_clk` provides the clock source for all LPI2C peripherals. /// You must disable LPI2C clock gates before selecting the clock /// and divider. pub mod lpi2c_clk { use crate::ral::{self, ccm::CCM}; /// Returns the LPI2C clock divider. pub fn divider(ccm: CCM) -> u32 { ral::read_reg!(ral::ccm, ccm, CSCDR2, LPI2C_CLK_PODF) + 1 } /// The smallest LPI2C clock divider. pub const MIN_DIVIDER: u32 = 1; /// The largest LPI2C clock divider. pub const MAX_DIVIDER: u32 = 64; /// Set the LPI2C clock divider. /// /// The implementation clamps `divider` between [`MIN_DIVIDER`] and [`MAX_DIVIDER`]. pub fn set_divider(ccm: CCM, divider: u32) { let podf = divider.clamp(MIN_DIVIDER, MAX_DIVIDER) - 1; ral::modify_reg!(ral::ccm, ccm, CSCDR2, LPI2C_CLK_PODF: podf); } /// LPI2C clock selections. #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(u32)] pub enum Selection { /// Derive from PLL3 divided by 8. Pll3Div8 = 0, /// Derive from the crystal oscillator. Oscillator = 1, } /// Returns the LPI2C clock selection. pub fn selection(ccm: CCM) -> Selection { match ral::read_reg!(ral::ccm, ccm, CSCDR2, LPI2C_CLK_SEL) { 0 => Selection::Pll3Div8, 1 => Selection::Oscillator, _ => unreachable!(), } } /// Set the LPI2C clock selection. pub fn set_selection(ccm: CCM, selection: Selection) { ral::modify_reg!(ral::ccm, ccm, CSCDR2, LPI2C_CLK_SEL: selection as u32); } } /// LPSPI clock root. /// /// `lpspi_clk` provides the clock source for all LPSPI peripherals. /// You must disable LPSPI clock gates before selecting the clock /// and divider. pub mod lpspi_clk { use crate::ral::{self, ccm::CCM}; /// Returns the LPSPI clock divider. pub fn divider(ccm: CCM) -> u32 { ral::read_reg!(ral::ccm, ccm, CBCMR, LPSPI_PODF) + 1 } /// The smallest LPSPI clock divider. pub const MIN_DIVIDER: u32 = 1; /// The largest LPSPI clock divider. pub const MAX_DIVIDER: u32 = 8; /// Set the LPSPI clock divider. /// /// The implementation clamps `divider` between [`MIN_DIVIDER`] and [`MAX_DIVIDER`]. pub fn set_divider(ccm: CCM, divider: u32) { // 1010 MCUs support an extra bit in this field, so this // could be a max of 16 for those chips. let podf = divider.clamp(MIN_DIVIDER, MAX_DIVIDER) - 1; ral::modify_reg!(ral::ccm, ccm, CBCMR, LPSPI_PODF: podf); } /// LPSPI clock selections. #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(u32)] pub enum Selection { /// Derive from PLL3_PFD1. Pll3Pfd1 = 0, /// Derive from the PLL3_PFD0. Pll3Pfd0 = 1, /// Derive from PLL2. Pll2 = 2, /// Derive from PLL2_PFD2. Pll2Pfd2 = 3, } /// Returns the LPSPI clock selection. pub fn selection(ccm: CCM) -> Selection { match ral::read_reg!(ral::ccm, ccm, CBCMR, LPSPI_CLK_SEL) { 0 => Selection::Pll3Pfd1, 1 => Selection::Pll3Pfd0, 2 => Selection::Pll2, 3 => Selection::Pll2Pfd2, _ => unreachable!(), } } /// Set the LPSPI clock selection. pub fn set_selection(ccm: CCM, selection: Selection) { ral::modify_reg!(ral::ccm, ccm, CBCMR, LPSPI_CLK_SEL: selection as u32); } } /// AHB (ARM) clock root. /// /// The AHB module exposes all selections and dividers that affect /// the AHB / ARM clock. This includes all clock trees behind the main /// selector, and the driving PLL. /// /// Chip-specific features affect what's exposed from this module. /// /// Note: the i.MX RT 1010 processors refer to the AHB clock root as the /// "core clock root." Nevertheless, the core clock root has an "AHB divider." /// For consistency, we refer to the 1010's core clock root as the AHB clock /// root. pub mod ahb_clk { use crate::ral::{self, ccm::CCM}; /// Set the AHB divider. /// /// The implementation clamps `divider` between 1 and 8. pub fn set_divider(ccm: CCM, divider: u32) { let podf = divider.clamp(1, 8) - 1; ral::modify_reg!(ral::ccm, ccm, CBCDR, AHB_PODF: podf); super::wait_handshake(ccm); } /// Returns the AHB divider. pub fn divider(ccm: CCM) -> u32 { ral::read_reg!(ral::ccm, ccm, CBCDR, AHB_PODF) + 1 } /// Peripheral clock selection. #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(u32)] pub enum Selection { /// Derive from PRE_PERIPH_CLK. PrePeriphClkSel = 0, /// Derive from PERIPH_CLK2. PeriphClk2Sel = 1, } /// Set the peripheral clock selection. pub fn set_selection(ccm: CCM, selection: Selection) { ral::modify_reg!(ral::ccm, ccm, CBCDR, PERIPH_CLK_SEL: selection as u32); super::wait_handshake(ccm); } /// Returns the peripheral clock selection. pub fn selection(ccm: CCM) -> Selection { match ral::read_reg!(ral::ccm, ccm, CBCDR, PERIPH_CLK_SEL) { 0 => Selection::PrePeriphClkSel, 1 => Selection::PeriphClk2Sel, _ => unreachable!(), } } } /// ARM divider. /// /// This divides the output from the AHB PLL (either PLL1 or PLL6, depending /// on the system). pub mod arm_divider { use crate::ral::{self, ccm::CCM}; /// Set the ARM divider. /// /// The implementation clamps `divider` between 1 and 8. pub fn set_divider(ccm: CCM, divider: u32) { let podf = divider.clamp(1, 8) - 1; ral::modify_reg!(ral::ccm, ccm, CACRR, ARM_PODF: podf); crate::ccm::wait_handshake(ccm); } /// Returns the ARM divider. pub fn divider(ccm: CCM) -> u32 { ral::read_reg!(ral::ccm, ccm, CACRR, ARM_PODF) + 1 } } /// One of the accessory muxes upstream of the AHB / ARM clock. pub mod periph_clk2 { use crate::ral::{self, ccm::CCM}; /// Set the peripheral clock 2 divider. /// /// The implementation clamps `divider` between 1 and 8. You should first switch /// away the core clock selection before changing this divider. pub fn set_divider(ccm: CCM, divider: u32) { let podf = divider.clamp(1, 8) - 1; ral::modify_reg!(ral::ccm, ccm, CBCDR, PERIPH_CLK2_PODF: podf); } /// Returns the peripheral clock 2 divider. pub fn divider(ccm: CCM) -> u32 { ral::read_reg!(ral::ccm, ccm, CBCDR, PERIPH_CLK2_PODF) + 1 } /// Peripheral CLK2 selection. #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(u32)] pub enum Selection { /// Use PLL3 (possibly bypassed by an upstream mux). Pll3Sw = 0, /// Crystall oscillator. Osc = 1, /// The PLL2 bypass. Pll2Bypass = 2, } /// Set the peripheral clock2 selection. pub fn set_selection(ccm: CCM, selection: Selection) { ral::modify_reg!(ral::ccm, ccm, CBCMR, PERIPH_CLK2_SEL: selection as u32); crate::ccm::wait_handshake(ccm); } /// Returns the peripheral clock2 selection. pub fn selection(ccm: CCM) -> Selection { let raw = ral::read_reg!(ral::ccm, ccm, CBCMR, PERIPH_CLK2_SEL); match raw { 0 => Selection::Pll3Sw, 1 => Selection::Osc, 2 => Selection::Pll2Bypass, _ => unreachable!(), } } } /// FlexSPI1 with AXI/SEMC selectors. pub mod flexspi1_clk_axi_semc { use crate::{ccm::CCM, ral}; /// FlexSPI1 selections #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(u32)] pub enum Selection { /// The SEMC clock root. AxiSemc = 0, /// PLL3. Pll3 = 1, /// PFD2 of PLL2. Pll2Pfd2 = 2, /// PFD0 of PLL3. Pll3Pfd0 = 3, } /// Set the FlexSPI1 clock selection. pub fn set_selection(ccm: CCM, selection: Selection) { ral::modify_reg!(ral::ccm, ccm, CSCMR1, FLEXSPI_CLK_SEL: selection as u32); } /// Return the FlexSPI1 clock selection. pub fn selection(ccm: CCM) -> Selection { match ral::read_reg!(ral::ccm, ccm, CSCMR1, FLEXSPI_CLK_SEL) { 0 => Selection::AxiSemc, 1 => Selection::Pll3, 2 => Selection::Pll2Pfd2, 3 => Selection::Pll3Pfd0, _ => unreachable!(), } } /// The smallest divider clamped by the implementation. pub const MIN_DIVIDER: u32 = 1; /// The largest divider clamped by the implementation. pub const MAX_DIVIDER: u32 = 8; /// Return the divider. pub fn divider(ccm: CCM) -> u32 { 1 + ral::read_reg!(ral::ccm, ccm, CSCMR1, FLEXSPI_PODF) } /// Set the FlexSPI1 root clock divider. /// /// The implementation clamps the input between [`MIN_DIVIDER`] /// and [`MAX_DIVIDER`]. pub fn set_divider(ccm: CCM, divider: u32) { let divider = divider.clamp(MIN_DIVIDER, MAX_DIVIDER) - 1; ral::modify_reg!(ral::ccm, ccm, CSCMR1, FLEXSPI_PODF: divider); } } /// FlexSPI1 with a PLL2 root clock. /// /// This root clock can also switch to the `periph_clk2` source. /// However, this isn't yet implemented. pub mod flexspi1_clk_root_pll2 { #[doc(inline)] pub use super::flexspi1_clk_axi_semc::{MAX_DIVIDER, MIN_DIVIDER, divider, set_divider}; use crate::{ccm::CCM, ral}; /// FlexSPI1 selections #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(u32)] pub enum Selection { /// PLL2. Pll2 = 0, /// PLL3. Pll3 = 1, /// PFD2 of PLL2. Pll2Pfd2 = 2, /// PFD0 of PLL3. Pll3Pfd0 = 3, } /// Set the FlexSPI1 clock selection. pub fn set_selection(ccm: CCM, selection: Selection) { ral::modify_reg!(ral::ccm, ccm, CSCMR1, FLEXSPI_CLK_SEL: selection as u32); } /// Return the FlexSPI1 clock selection. pub fn selection(ccm: CCM) -> Selection { match ral::read_reg!(ral::ccm, ccm, CSCMR1, FLEXSPI_CLK_SEL) { 0 => Selection::Pll2, 1 => Selection::Pll3, 2 => Selection::Pll2Pfd2, 3 => Selection::Pll3Pfd0, _ => unreachable!(), } } } /// Pre-peripheral clock. pub mod pre_periph_clk_pll1 { use crate::ral::{self, ccm::CCM}; /// Pre-peripheral clock selection. #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(u32)] pub enum Selection { /// PLL2. Pll2 = 0, /// PFD2 of PLL2 Pll2Pfd2 = 1, /// PFD0 of PLL2. Pll2Pfd0 = 2, /// PLL1. Pll1 = 3, } /// Set the pre-peripheral clock selection. pub fn set_selection(ccm: CCM, selection: Selection) { ral::modify_reg!(ral::ccm, ccm, CBCMR, PRE_PERIPH_CLK_SEL: selection as u32); } /// Returns the pre-peripheral clock selection. pub fn selection(ccm: CCM) -> Selection { use Selection::*; match ral::read_reg!(ral::ccm, ccm, CBCMR, PRE_PERIPH_CLK_SEL) { 0 => Pll2, 1 => Pll2Pfd2, 2 => Pll2Pfd0, 3 => Pll1, _ => unreachable!(), } } } /// Pre-peripheral clock. pub mod pre_periph_clk_pll6 { use crate::ral::{self, ccm::CCM}; /// Pre-peripheral clock selection. #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(u32)] pub enum Selection { /// PLL2. Pll2 = 0, /// PFD3 of PLL3. Pll3Pfd3 = 1, /// PFD3 of PLL2. Pll2Pfd3 = 2, /// PLL6. Pll6 = 3, } /// Set the pre-peripheral clock selection. pub fn set_selection(ccm: CCM, selection: Selection) { ral::modify_reg!(ral::ccm, ccm, CBCMR, PRE_PERIPH_CLK_SEL: selection as u32); } /// Returns the pre-peripheral clock selection. pub fn selection(ccm: CCM) -> Selection { use Selection::*; match ral::read_reg!(ral::ccm, ccm, CBCMR, PRE_PERIPH_CLK_SEL) { 0 => Pll2, 1 => Pll3Pfd3, 2 => Pll2Pfd3, 3 => Pll6, _ => unreachable!(), } } } /// Clock gate control. pub mod clock_gate { use crate::ral::{self, ccm::CCM}; /// A clock gate locator. /// /// This enum encodes the register and field for a clock gate. /// Note that not all clock gates are valid for all MCUs. #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(u16)] pub enum Locator { Ccgr0Cg00 = clock_gate(0, 00), Ccgr0Cg01 = clock_gate(0, 01), Ccgr0Cg02 = clock_gate(0, 02), Ccgr0Cg03 = clock_gate(0, 03), Ccgr0Cg04 = clock_gate(0, 04), Ccgr0Cg05 = clock_gate(0, 05), Ccgr0Cg06 = clock_gate(0, 06), Ccgr0Cg07 = clock_gate(0, 07), Ccgr0Cg08 = clock_gate(0, 08), Ccgr0Cg09 = clock_gate(0, 09), Ccgr0Cg10 = clock_gate(0, 10), Ccgr0Cg11 = clock_gate(0, 11), Ccgr0Cg12 = clock_gate(0, 12), Ccgr0Cg13 = clock_gate(0, 13), Ccgr0Cg14 = clock_gate(0, 14), Ccgr0Cg15 = clock_gate(0, 15), Ccgr1Cg00 = clock_gate(1, 00), Ccgr1Cg01 = clock_gate(1, 01), Ccgr1Cg02 = clock_gate(1, 02), Ccgr1Cg03 = clock_gate(1, 03), Ccgr1Cg04 = clock_gate(1, 04), Ccgr1Cg05 = clock_gate(1, 05), Ccgr1Cg06 = clock_gate(1, 06), Ccgr1Cg07 = clock_gate(1, 07), Ccgr1Cg08 = clock_gate(1, 08), Ccgr1Cg09 = clock_gate(1, 09), Ccgr1Cg10 = clock_gate(1, 10), Ccgr1Cg11 = clock_gate(1, 11), Ccgr1Cg12 = clock_gate(1, 12), Ccgr1Cg13 = clock_gate(1, 13), Ccgr1Cg14 = clock_gate(1, 14), Ccgr1Cg15 = clock_gate(1, 15), Ccgr2Cg00 = clock_gate(2, 00), Ccgr2Cg01 = clock_gate(2, 01), Ccgr2Cg02 = clock_gate(2, 02), Ccgr2Cg03 = clock_gate(2, 03), Ccgr2Cg04 = clock_gate(2, 04), Ccgr2Cg05 = clock_gate(2, 05), Ccgr2Cg06 = clock_gate(2, 06), Ccgr2Cg07 = clock_gate(2, 07), Ccgr2Cg08 = clock_gate(2, 08), Ccgr2Cg09 = clock_gate(2, 09), Ccgr2Cg10 = clock_gate(2, 10), Ccgr2Cg11 = clock_gate(2, 11), Ccgr2Cg12 = clock_gate(2, 12), Ccgr2Cg13 = clock_gate(2, 13), Ccgr2Cg14 = clock_gate(2, 14), Ccgr2Cg15 = clock_gate(2, 15), Ccgr3Cg00 = clock_gate(3, 00), Ccgr3Cg01 = clock_gate(3, 01), Ccgr3Cg02 = clock_gate(3, 02), Ccgr3Cg03 = clock_gate(3, 03), Ccgr3Cg04 = clock_gate(3, 04), Ccgr3Cg05 = clock_gate(3, 05), Ccgr3Cg06 = clock_gate(3, 06), Ccgr3Cg07 = clock_gate(3, 07), Ccgr3Cg08 = clock_gate(3, 08), Ccgr3Cg09 = clock_gate(3, 09), Ccgr3Cg10 = clock_gate(3, 10), Ccgr3Cg11 = clock_gate(3, 11), Ccgr3Cg12 = clock_gate(3, 12), Ccgr3Cg13 = clock_gate(3, 13), Ccgr3Cg14 = clock_gate(3, 14), Ccgr3Cg15 = clock_gate(3, 15), Ccgr4Cg00 = clock_gate(4, 00), Ccgr4Cg01 = clock_gate(4, 01), Ccgr4Cg02 = clock_gate(4, 02), Ccgr4Cg03 = clock_gate(4, 03), Ccgr4Cg04 = clock_gate(4, 04), Ccgr4Cg05 = clock_gate(4, 05), Ccgr4Cg06 = clock_gate(4, 06), Ccgr4Cg07 = clock_gate(4, 07), Ccgr4Cg08 = clock_gate(4, 08), Ccgr4Cg09 = clock_gate(4, 09), Ccgr4Cg10 = clock_gate(4, 10), Ccgr4Cg11 = clock_gate(4, 11), Ccgr4Cg12 = clock_gate(4, 12), Ccgr4Cg13 = clock_gate(4, 13), Ccgr4Cg14 = clock_gate(4, 14), Ccgr4Cg15 = clock_gate(4, 15), Ccgr5Cg00 = clock_gate(5, 00), Ccgr5Cg01 = clock_gate(5, 01), Ccgr5Cg02 = clock_gate(5, 02), Ccgr5Cg03 = clock_gate(5, 03), Ccgr5Cg04 = clock_gate(5, 04), Ccgr5Cg05 = clock_gate(5, 05), Ccgr5Cg06 = clock_gate(5, 06), Ccgr5Cg07 = clock_gate(5, 07), Ccgr5Cg08 = clock_gate(5, 08), Ccgr5Cg09 = clock_gate(5, 09), Ccgr5Cg10 = clock_gate(5, 10), Ccgr5Cg11 = clock_gate(5, 11), Ccgr5Cg12 = clock_gate(5, 12), Ccgr5Cg13 = clock_gate(5, 13), Ccgr5Cg14 = clock_gate(5, 14), Ccgr5Cg15 = clock_gate(5, 15), Ccgr6Cg00 = clock_gate(6, 00), Ccgr6Cg01 = clock_gate(6, 01), Ccgr6Cg02 = clock_gate(6, 02), Ccgr6Cg03 = clock_gate(6, 03), Ccgr6Cg04 = clock_gate(6, 04), Ccgr6Cg05 = clock_gate(6, 05), Ccgr6Cg06 = clock_gate(6, 06), Ccgr6Cg07 = clock_gate(6, 07), Ccgr6Cg08 = clock_gate(6, 08), Ccgr6Cg09 = clock_gate(6, 09), Ccgr6Cg10 = clock_gate(6, 10), Ccgr6Cg11 = clock_gate(6, 11), Ccgr6Cg12 = clock_gate(6, 12), Ccgr6Cg13 = clock_gate(6, 13), Ccgr6Cg14 = clock_gate(6, 14), Ccgr6Cg15 = clock_gate(6, 15), Ccgr7Cg00 = clock_gate(7, 00), Ccgr7Cg01 = clock_gate(7, 01), Ccgr7Cg02 = clock_gate(7, 02), Ccgr7Cg03 = clock_gate(7, 03), Ccgr7Cg04 = clock_gate(7, 04), Ccgr7Cg05 = clock_gate(7, 05), Ccgr7Cg06 = clock_gate(7, 06), Ccgr7Cg07 = clock_gate(7, 07), Ccgr7Cg08 = clock_gate(7, 08), Ccgr7Cg09 = clock_gate(7, 09), Ccgr7Cg10 = clock_gate(7, 10), Ccgr7Cg11 = clock_gate(7, 11), Ccgr7Cg12 = clock_gate(7, 12), Ccgr7Cg13 = clock_gate(7, 13), Ccgr7Cg14 = clock_gate(7, 14), Ccgr7Cg15 = clock_gate(7, 15), } /// Encode a clock gate. const fn clock_gate(register: u8, field: u8) -> u16 { ((register as u16) << 8) | ((field * 2) as u16) } impl Locator { /// Access the register index. const fn register(self) -> usize { (((self as u16) >> 8) & 0xFF) as usize } /// Produce the bit shift for the field. const fn shift(self) -> u32 { ((self as u16) & 0xFF) as u32 } /// Produce the mask for the field. const fn mask(self) -> u32 { 0b11 << self.shift() } } /// The activity for a [`Locator`]. #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(u32)] pub enum Activity { /// Clock is off in all modes. Off = 0, /// Clock is on in run mode, but off in WAIT and STOP modes. OnlyRun = 1, /// Clock is on in all modes, except stop mode. On = 3, } impl From for Activity { fn from(value: bool) -> Self { if value { Self::On } else { Self::Off } } } /// Helper constant to turn off a clock gate. pub const OFF: Activity = Activity::Off; /// Helper constant to turn on a clock gate. pub const ON: Activity = Activity::On; /// Returns a clock gate's activity. /// /// Returns `None` if the field represents the reserved value. pub fn get(ccm: CCM, locator: Locator) -> Option { let ccgr = ral::read_reg!(ral::ccm, ccm, CCGR[locator.register()]); let field = (ccgr & locator.mask()) >> locator.shift(); Some(match field { 0 => Activity::Off, 1 => Activity::OnlyRun, 3 => Activity::On, _ => return None, }) } /// Set the clock gate's activity. pub fn set(ccm: CCM, locator: Locator, activity: Activity) { ral::modify_reg!(ral::ccm, ccm, CCGR[locator.register()], |mut ccgr| { ccgr &= !locator.mask(); ccgr |= (activity as u32) << locator.shift(); ccgr }); } }