aboutsummaryrefslogtreecommitdiff
path: root/drivers/ccm-11xx/src/ral_11xx/pll.rs
diff options
context:
space:
mode:
authorIan McIntyre <me@mciantyre.dev>2025-11-30 18:52:34 -0500
committerIan McIntyre <me@mciantyre.dev>2025-11-30 19:10:51 -0500
commit76199f21616ad86cf68f3b063c1ce23c6fc5a52f (patch)
tree4c076d0afd649803a2bd9a5ed5cbb1f1c74fb459 /drivers/ccm-11xx/src/ral_11xx/pll.rs
First commit
Diffstat (limited to 'drivers/ccm-11xx/src/ral_11xx/pll.rs')
-rw-r--r--drivers/ccm-11xx/src/ral_11xx/pll.rs598
1 files changed, 598 insertions, 0 deletions
diff --git a/drivers/ccm-11xx/src/ral_11xx/pll.rs b/drivers/ccm-11xx/src/ral_11xx/pll.rs
new file mode 100644
index 0000000..d5e04d4
--- /dev/null
+++ b/drivers/ccm-11xx/src/ral_11xx/pll.rs
@@ -0,0 +1,598 @@
+use core::num::NonZero;
+
+pub type Instance = ral_registers::Instance<RegisterBlock>;
+
+#[repr(C)]
+#[allow(non_snake_case)]
+pub struct RegisterBlock {
+ reserved_0: [u8; 512],
+ pub ARM_PLL_CTRL: u32,
+ reserved_1: [u8; 12],
+ pub SYS_PLL3_CTRL: u32,
+ reserved_2: [u8; 12],
+ pub SYS_PLL3_UPDATE: u32,
+ reserved_3: [u8; 12],
+ pub SYS_PLL3_PFD: u32,
+ reserved_4: [u8; 12],
+ pub SYS_PLL2_CTRL: u32,
+ reserved_5: [u8; 12],
+ pub SYS_PLL2_UPDATE: u32,
+ reserved_6: [u8; 12],
+ pub SYS_PLL2_SS: u32,
+ reserved_7: [u8; 12],
+ pub SYS_PLL2_PFD: u32,
+ reserved_8: [u8; 44],
+ pub SYS_PLL2_MFD: u32,
+ reserved_9: [u8; 12],
+ pub SYS_PLL1_SS: u32,
+ reserved_10: [u8; 12],
+ pub SYS_PLL1_CTRL: u32,
+ reserved_11: [u8; 12],
+ pub SYS_PLL1_DENOMINATOR: u32,
+ reserved_12: [u8; 12],
+ pub SYS_PLL1_NUMERATOR: u32,
+ reserved_13: [u8; 12],
+ pub SYS_PLL1_DIV_SELECT: u32,
+ reserved_14: [u8; 12],
+ pub PLL_AUDIO_CTRL: u32,
+ reserved_15: [u8; 12],
+ pub PLL_AUDIO_SS: u32,
+ reserved_16: [u8; 12],
+ pub PLL_AUDIO_DENOMINATOR: u32,
+ reserved_17: [u8; 12],
+ pub PLL_AUDIO_NUMERATOR: u32,
+ reserved_18: [u8; 12],
+ pub PLL_AUDIO_DIV_SELECT: u32,
+ reserved_19: [u8; 12],
+ pub PLL_VIDEO_CTRL: u32,
+ reserved_20: [u8; 12],
+ pub PLL_VIDEO_SS: u32,
+ reserved_21: [u8; 12],
+ pub PLL_VIDEO_DENOMINATOR: u32,
+ reserved_22: [u8; 12],
+ pub PLL_VIDEO_NUMERATOR: u32,
+ reserved_23: [u8; 12],
+ pub PLL_VIDEO_DIV_SELECT: u32,
+}
+
+ral_registers::register! {
+ #[doc = "SYS_PLL1_CTRL_REGISTER"]
+ pub SYS_PLL1_CTRL<u32> RW [
+ #[doc = "ENABLE_CLK"]
+ ENABLE_CLK start(13) width(1) RW {}
+ #[doc = "SYS_PLL1_GATE"]
+ SYS_PLL1_GATE start(14) width(1) RW {}
+ #[doc = "SYS_PLL1_DIV2"]
+ SYS_PLL1_DIV2 start(25) width(1) RW {}
+ #[doc = "SYS_PLL1_DIV5"]
+ SYS_PLL1_DIV5 start(26) width(1) RW {}
+ #[doc = "SYS_PLL1_DIV5_CONTROL_MODE"]
+ SYS_PLL1_DIV5_CONTROL_MODE start(27) width(1) RW {
+ #[doc = "Software Mode (Default)"]
+ SW = 0,
+ #[doc = "GPC Mode"]
+ GPC = 0x1,
+ }
+ #[doc = "SYS_PLL1_DIV2_CONTROL_MODE"]
+ SYS_PLL1_DIV2_CONTROL_MODE start(28) width(1) RW {
+ #[doc = "Software Mode (Default)"]
+ SW = 0,
+ #[doc = "GPC Mode"]
+ GPC = 0x1,
+ }
+ #[doc = "SYS_PLL1_STABLE"]
+ SYS_PLL1_STABLE start(29) width(1) RO {}
+ #[doc = "SYS_PLL1_AI_BUSY"]
+ SYS_PLL1_AI_BUSY start(30) width(1) RO {}
+ #[doc = "SYS_PLL1_CONTROL_MODE"]
+ SYS_PLL1_CONTROL_MODE start(31) width(1) RW {
+ #[doc = "Software Mode (Default)"]
+ SW = 0,
+ #[doc = "GPC Mode"]
+ GPC = 0x1,
+ }
+ ]
+}
+
+/// Manage all SYS_PLL1 clocks using setpoints.
+pub fn enable_sys_pll1_setpoints(pll: ral_registers::Instance<RegisterBlock>) {
+ ral_registers::modify_reg!(self, pll, SYS_PLL1_CTRL,
+ SYS_PLL1_CONTROL_MODE: GPC,
+ SYS_PLL1_DIV2_CONTROL_MODE: GPC,
+ SYS_PLL1_DIV5_CONTROL_MODE: GPC,
+ );
+}
+
+ral_registers::register! {
+ #[doc = "ARM_PLL_CTRL_REGISTER"]
+ pub ARM_PLL_CTRL<u32> RW [
+ #[doc = "DIV_SELECT"]
+ DIV_SELECT start(0) width(8) RW {}
+ #[doc = "PLL Start up initialization"]
+ HOLD_RING_OFF start(12) width(1) RW {}
+ #[doc = "Powers up the PLL."]
+ POWERUP start(13) width(1) RW {}
+ #[doc = "Enable the clock output."]
+ ENABLE_CLK start(14) width(1) RW {}
+ #[doc = "POST_DIV_SEL"]
+ POST_DIV_SEL start(15) width(2) RW {
+ #[doc = "Divide by 2"]
+ DIV2 = 0,
+ #[doc = "Divide by 4"]
+ DIV4 = 0x1,
+ #[doc = "Divide by 8"]
+ DIV8 = 0x2,
+ #[doc = "Divide by 1"]
+ DIV1 = 0x3,
+ }
+ #[doc = "Bypass the pll."]
+ BYPASS start(17) width(1) RW {}
+ #[doc = "ARM_PLL_STABLE"]
+ ARM_PLL_STABLE start(29) width(1) RO {}
+ #[doc = "ARM_PLL_GATE"]
+ ARM_PLL_GATE start(30) width(1) RW {}
+ #[doc = "pll_arm_control_mode"]
+ ARM_PLL_CONTROL_MODE start(31) width(1) RW {
+ #[doc = "Software Mode (Default)"]
+ SW = 0,
+ #[doc = "GPC Mode"]
+ GPC = 0x1,
+ }
+ ]
+}
+
+/// Post divider for the ARM PLL.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+#[repr(u32)]
+pub enum ArmPllPostDiv {
+ /// Divide by 2.
+ Div2 = 0,
+ /// Divide by 4.
+ Div4 = 1,
+ /// Divide by 8.
+ Div8 = 2,
+ /// Divide by 1.
+ Div1 = 3,
+}
+
+impl ArmPllPostDiv {
+ /// Return the divisor for this post divider.
+ #[must_use]
+ pub const fn divisor(self) -> u32 {
+ match self {
+ Self::Div2 => 2,
+ Self::Div4 => 4,
+ Self::Div8 => 8,
+ Self::Div1 => 1,
+ }
+ }
+}
+
+/// The ARM PLL loop divider.
+///
+/// This value is always clamped between 104 and 208.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+#[repr(transparent)]
+pub struct ArmPllDivSelect(NonZero<u32>);
+
+impl ArmPllDivSelect {
+ /// Construct a loop divider.
+ ///
+ /// The implementation clamps the value between 104 and 208.
+ #[must_use]
+ pub const fn new(div_select: u32) -> Option<Self> {
+ if 104 <= div_select && div_select <= 208 {
+ Some(Self(NonZero::new(div_select).unwrap()))
+ } else {
+ None
+ }
+ }
+ /// Returns the divider as a raw value.
+ #[must_use]
+ #[inline]
+ pub const fn get(self) -> u32 {
+ self.0.get()
+ }
+}
+
+/// Manage the ARM PLL with setpoints.
+///
+/// `post_div` is the post divider selection applied when the
+/// PLL is enabled. Similarly `div_select` is the loop divider.
+/// Use [`arm_pll_frequency`] to understand the expected frequency
+/// affected by this call.
+pub fn enable_arm_pll_setpoints(
+ pll: ral_registers::Instance<RegisterBlock>,
+ post_div: ArmPllPostDiv,
+ div_select: ArmPllDivSelect,
+) {
+ ral_registers::modify_reg!(self, pll, ARM_PLL_CTRL,
+ DIV_SELECT: div_select.get(),
+ POST_DIV_SEL: post_div as u32,
+ ARM_PLL_GATE: 1,
+ ARM_PLL_CONTROL_MODE: GPC,
+ ENABLE_CLK: 0,
+ );
+}
+
+/// Computes the expected ARM PLL frequency.
+pub const fn arm_pll_frequency(post_div: ArmPllPostDiv, div_select: ArmPllDivSelect) -> u32 {
+ 24_000_000 / 2 / post_div.divisor() * div_select.get()
+}
+
+ral_registers::register! {
+ #[doc = "SYS_PLL2_CTRL_REGISTER"]
+ pub SYS_PLL2_CTRL<u32> RW [
+ #[doc = "Enable Internal PLL Regulator"]
+ PLL_REG_EN start(3) width(1) RW {}
+ #[doc = "PLL Start up initialization"]
+ HOLD_RING_OFF start(11) width(1) RW {}
+ #[doc = "Enable the clock output."]
+ ENABLE_CLK start(13) width(1) RW {}
+ #[doc = "Bypass the pll."]
+ BYPASS start(16) width(1) RW {}
+ #[doc = "DITHER_ENABLE"]
+ DITHER_ENABLE start(17) width(1) RW {}
+ #[doc = "PFD_OFFSET_EN"]
+ PFD_OFFSET_EN start(18) width(1) RW {}
+ #[doc = "PLL_DDR_OVERRIDE"]
+ PLL_DDR_OVERRIDE start(19) width(1) RW {}
+ #[doc = "Powers up the PLL."]
+ POWERUP start(23) width(1) RW {}
+ #[doc = "SYS_PLL2_STABLE"]
+ SYS_PLL2_STABLE start(29) width(1) RO {}
+ #[doc = "SYS_PLL2_GATE"]
+ SYS_PLL2_GATE start(30) width(1) RW {}
+ #[doc = "SYS_PLL2_control_mode"]
+ SYS_PLL2_CONTROL_MODE start(31) width(1) RW {
+ #[doc = "Software Mode (Default)"]
+ SW = 0,
+ #[doc = "GPC Mode"]
+ GPC = 0x1,
+ }
+ ]
+}
+
+ral_registers::register! {
+ #[doc = "SYS_PLL2_UPDATE_REGISTER"]
+ pub SYS_PLL2_UPDATE<u32> RW [
+ #[doc = "PFD0_UPDATE"]
+ PFD0_UPDATE start(1) width(1) RW {}
+ #[doc = "PFD1_UPDATE"]
+ PFD1_UPDATE start(2) width(1) RW {}
+ #[doc = "PFD2_UPDATE"]
+ PFD2_UPDATE start(3) width(1) RW {}
+ #[doc = "PFD3_UPDATE"]
+ PFD3_UPDATE start(4) width(1) RW {}
+ #[doc = "pfd0_control_mode"]
+ PFD0_CONTROL_MODE start(5) width(1) RW {
+ #[doc = "Software Mode (Default)"]
+ SW = 0,
+ #[doc = "GPC Mode"]
+ GPC = 0x1,
+ }
+ #[doc = "pfd1_control_mode"]
+ PFD1_CONTROL_MODE start(6) width(1) RW {
+ #[doc = "Software Mode (Default)"]
+ SW = 0,
+ #[doc = "GPC Mode"]
+ GPC = 0x1,
+ }
+ #[doc = "pfd2_control_mode"]
+ PFD2_CONTROL_MODE start(7) width(1) RW {
+ #[doc = "Software Mode (Default)"]
+ SW = 0,
+ #[doc = "GPC Mode"]
+ GPC = 0x1,
+ }
+ #[doc = "pfd3_control_mode"]
+ PFD3_CONTROL_MODE start(8) width(1) RW {
+ #[doc = "Software Mode (Default)"]
+ SW = 0,
+ #[doc = "GPC Mode"]
+ GPC = 0x1,
+ }
+ ]
+}
+
+/// Manage SYS_PLL2 clocks and PFDs using setpoints.
+pub fn enable_sys_pll2_setpoints(pll: ral_registers::Instance<RegisterBlock>) {
+ ral_registers::modify_reg!(self, pll, SYS_PLL2_UPDATE,
+ PFD3_CONTROL_MODE: GPC,
+ PFD2_CONTROL_MODE: GPC,
+ PFD1_CONTROL_MODE: GPC,
+ PFD0_CONTROL_MODE: GPC,
+ );
+ ral_registers::modify_reg!(self, pll, SYS_PLL2_CTRL,
+ SYS_PLL2_CONTROL_MODE: GPC,
+ SYS_PLL2_GATE: 1,
+ ENABLE_CLK: 0,
+ );
+}
+
+ral_registers::register! {
+ #[doc = "SYS_PLL3_CTRL_REGISTER"]
+ pub SYS_PLL3_CTRL<u32> RW [
+ #[doc = "SYS PLL3 DIV2 gate"]
+ SYS_PLL3_DIV2 start(3) width(1) RW {}
+ #[doc = "Enable Internal PLL Regulator"]
+ PLL_REG_EN start(4) width(1) RW {}
+ #[doc = "PLL Start up initialization"]
+ HOLD_RING_OFF start(11) width(1) RW {}
+ #[doc = "Enable the clock output."]
+ ENABLE_CLK start(13) width(1) RW {}
+ #[doc = "BYPASS"]
+ BYPASS start(16) width(1) RW {}
+ #[doc = "Powers up the PLL."]
+ POWERUP start(21) width(1) RW {}
+ #[doc = "SYS_PLL3_DIV2_CONTROL_MODE"]
+ SYS_PLL3_DIV2_CONTROL_MODE start(28) width(1) RW {
+ #[doc = "Software Mode (Default)"]
+ SW = 0,
+ #[doc = "GPC Mode"]
+ GPC = 0x1,
+ }
+ #[doc = "SYS_PLL3_STABLE"]
+ SYS_PLL3_STABLE start(29) width(1) RO {}
+ #[doc = "SYS_PLL3_GATE"]
+ SYS_PLL3_GATE start(30) width(1) RW {}
+ #[doc = "SYS_PLL3_control_mode"]
+ SYS_PLL3_CONTROL_MODE start(31) width(1) RW {
+ #[doc = "Software Mode (Default)"]
+ SW = 0,
+ #[doc = "GPC Mode"]
+ GPC = 0x1,
+ }
+ ]
+}
+
+ral_registers::register! {
+ #[doc = "SYS_PLL3_UPDATE_REGISTER"]
+ pub SYS_PLL3_UPDATE<u32> RW [
+ #[doc = "PFD0_OVERRIDE"]
+ PFD0_UPDATE start(1) width(1) RW {}
+ #[doc = "PFD1_OVERRIDE"]
+ PFD1_UPDATE start(2) width(1) RW {}
+ #[doc = "PFD2_OVERRIDE"]
+ PFD2_UPDATE start(3) width(1) RW {}
+ #[doc = "PFD3_UPDATE"]
+ PFD3_UPDATE start(4) width(1) RW {}
+ #[doc = "pfd0_control_mode"]
+ PFD0_CONTROL_MODE start(5) width(1) RW {
+ #[doc = "Software Mode (Default)"]
+ SW = 0,
+ #[doc = "GPC Mode"]
+ GPC = 0x1,
+ }
+ #[doc = "pfd1_control_mode"]
+ PFD1_CONTROL_MODE start(6) width(1) RW {
+ #[doc = "Software Mode (Default)"]
+ SW = 0,
+ #[doc = "GPC Mode"]
+ GPC = 0x1,
+ }
+ #[doc = "pdf2_control_mode"]
+ PFD2_CONTROL_MODE start(7) width(1) RW {
+ #[doc = "Software Mode (Default)"]
+ SW = 0,
+ #[doc = "GPC Mode"]
+ GPC = 0x1,
+ }
+ #[doc = "pfd3_control_mode"]
+ PFD3_CONTROL_MODE start(8) width(1) RW {
+ #[doc = "Software Mode (Default)"]
+ SW = 0,
+ #[doc = "GPC Mode"]
+ GPC = 0x1,
+ }
+ ]
+}
+
+/// Manage SYS_PLL3 clocks and PFDs using setpoints.
+pub fn enable_sys_pll3_setpoints(pll: ral_registers::Instance<RegisterBlock>) {
+ ral_registers::modify_reg!(self, pll, SYS_PLL3_UPDATE,
+ PFD3_CONTROL_MODE: GPC,
+ PFD2_CONTROL_MODE: GPC,
+ PFD1_CONTROL_MODE: GPC,
+ PFD0_CONTROL_MODE: GPC,
+ );
+ ral_registers::modify_reg!(self, pll, SYS_PLL3_CTRL,
+ SYS_PLL3_CONTROL_MODE: GPC,
+ SYS_PLL3_DIV2_CONTROL_MODE: GPC,
+ SYS_PLL3_GATE: 1,
+ ENABLE_CLK: 0,
+ );
+}
+
+ral_registers::register! {
+ #[doc = "SYS_PLL3_PFD_REGISTER"]
+ pub SYS_PLL3_PFD<u32> RW [
+ #[doc = "PFD0_FRAC"]
+ PFD0_FRAC start(0) width(6) RW {}
+ #[doc = "PFD0_STABLE"]
+ PFD0_STABLE start(6) width(1) RO {}
+ #[doc = "PFD0_DIV1_CLKGATE"]
+ PFD0_DIV1_CLKGATE start(7) width(1) RW {}
+ #[doc = "PFD1_FRAC"]
+ PFD1_FRAC start(8) width(6) RW {}
+ #[doc = "PFD1_STABLE"]
+ PFD1_STABLE start(14) width(1) RO {}
+ #[doc = "PFD1_DIV1_CLKGATE"]
+ PFD1_DIV1_CLKGATE start(15) width(1) RW {}
+ #[doc = "PFD2_FRAC"]
+ PFD2_FRAC start(16) width(6) RW {}
+ #[doc = "PFD2_STABLE"]
+ PFD2_STABLE start(22) width(1) RO {}
+ #[doc = "PFD2_DIV1_CLKGATE"]
+ PFD2_DIV1_CLKGATE start(23) width(1) RW {}
+ #[doc = "PFD3_FRAC"]
+ PFD3_FRAC start(24) width(6) RW {}
+ #[doc = "PFD3_STABLE"]
+ PFD3_STABLE start(30) width(1) RO {}
+ #[doc = "PFD3_DIV1_CLKGATE"]
+ PFD3_DIV1_CLKGATE start(31) width(1) RW {}
+ ]
+}
+
+ral_registers::register! {
+ #[doc = "SYS_PLL2_PFD_REGISTER"]
+ pub SYS_PLL2_PFD<u32> RW [
+ #[doc = "PFD0_FRAC"]
+ PFD0_FRAC start(0) width(6) RW {}
+ #[doc = "PFD0_STABLE"]
+ PFD0_STABLE start(6) width(1) RO {}
+ #[doc = "PFD0_DIV1_CLKGATE"]
+ PFD0_DIV1_CLKGATE start(7) width(1) RW {}
+ #[doc = "PFD1_FRAC"]
+ PFD1_FRAC start(8) width(6) RW {}
+ #[doc = "PFD1_STABLE"]
+ PFD1_STABLE start(14) width(1) RO {}
+ #[doc = "PFD1_DIV1_CLKGATE"]
+ PFD1_DIV1_CLKGATE start(15) width(1) RW {}
+ #[doc = "PFD2_FRAC"]
+ PFD2_FRAC start(16) width(6) RW {}
+ #[doc = "PFD2_STABLE"]
+ PFD2_STABLE start(22) width(1) RO {}
+ #[doc = "PFD2_DIV1_CLKGATE"]
+ PFD2_DIV1_CLKGATE start(23) width(1) RW {}
+ #[doc = "PFD3_FRAC"]
+ PFD3_FRAC start(24) width(6) RW {}
+ #[doc = "PFD3_STABLE"]
+ PFD3_STABLE start(30) width(1) RO {}
+ #[doc = "PFD3_DIV1_CLKGATE"]
+ PFD3_DIV1_CLKGATE start(31) width(1) RW {}
+ ]
+}
+
+/// A fractional divider for a PFD.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+#[repr(transparent)]
+pub struct PfdFrac(NonZero<u8>);
+
+impl PfdFrac {
+ /// Create a new PDF fractional divider.
+ ///
+ /// Returns `None` if `div` is not between 12 and 35.
+ pub const fn new(div: u8) -> Option<Self> {
+ // Safety: div is between 12 and 35.
+ unsafe {
+ if 12 <= div && div <= 35 {
+ Some(Self(NonZero::new_unchecked(div)))
+ } else {
+ None
+ }
+ }
+ }
+
+ /// Similar to `new`, but this will automatically clamp
+ /// the value between the 12 and 35.
+ pub const fn clamp(div: u8) -> Self {
+ // Safety: div is clamped between 12 and 35.
+ unsafe {
+ Self(NonZero::new_unchecked(if div < 12 {
+ 12
+ } else if div > 35 {
+ 35
+ } else {
+ div
+ }))
+ }
+ }
+
+ /// Return the inner value.
+ #[inline]
+ pub const fn get(self) -> u8 {
+ self.0.get()
+ }
+}
+
+/// Returns the PLL3 PFD fractional dividers.
+///
+/// If a divider is invalid, the implementation returns `None`
+/// for that divider.
+pub fn pll3_pfd_fracs(pll: ral_registers::Instance<RegisterBlock>) -> [Option<PfdFrac>; 4] {
+ let (pfd0, pfd1, pfd2, pfd3) = ral_registers::read_reg!(
+ self,
+ pll,
+ SYS_PLL3_PFD,
+ PFD0_FRAC,
+ PFD1_FRAC,
+ PFD2_FRAC,
+ PFD3_FRAC
+ );
+
+ [
+ PfdFrac::new(pfd0 as _),
+ PfdFrac::new(pfd1 as _),
+ PfdFrac::new(pfd2 as _),
+ PfdFrac::new(pfd3 as _),
+ ]
+}
+
+/// Set the PLL3 PFD fractional dividers.
+///
+/// The call updates all four dividers without affecting the gating.
+/// However, it does not update the values.
+pub fn set_pll3_pfd_fracs(pll: ral_registers::Instance<RegisterBlock>, pfds: [PfdFrac; 4]) {
+ ral_registers::modify_reg!(self, pll, SYS_PLL3_PFD,
+ PFD3_FRAC: pfds[3].get() as u32,
+ PFD2_FRAC: pfds[2].get() as u32,
+ PFD1_FRAC: pfds[1].get() as u32,
+ PFD0_FRAC: pfds[0].get() as u32,
+ );
+}
+
+/// Update the PFD fractional divider values that were previously
+/// set.
+///
+/// Only those that have a `true` update are updated.
+pub fn update_pll3_pfd_fracs(pll: ral_registers::Instance<RegisterBlock>, update: [bool; 4]) {
+ ral_registers::modify_reg!(self, pll, SYS_PLL3_UPDATE,
+ PFD3_UPDATE: update[3] as u32,
+ PFD2_UPDATE: update[2] as u32,
+ PFD1_UPDATE: update[1] as u32,
+ PFD0_UPDATE: update[0] as u32,
+ );
+ ral_registers::modify_reg!(self, pll, SYS_PLL3_UPDATE,
+ PFD3_UPDATE: false as u32,
+ PFD2_UPDATE: false as u32,
+ PFD1_UPDATE: false as u32,
+ PFD0_UPDATE: false as u32,
+ );
+}
+
+/// Returns the PLL2 PFD fractional dividers.
+///
+/// If a divider is invalid, the implementation returns `None`
+/// for that divider.
+pub fn pll2_pfd_fracs(pll: ral_registers::Instance<RegisterBlock>) -> [Option<PfdFrac>; 4] {
+ let (pfd0, pfd1, pfd2, pfd3) = ral_registers::read_reg!(
+ self,
+ pll,
+ SYS_PLL2_PFD,
+ PFD0_FRAC,
+ PFD1_FRAC,
+ PFD2_FRAC,
+ PFD3_FRAC
+ );
+
+ [
+ PfdFrac::new(pfd0 as _),
+ PfdFrac::new(pfd1 as _),
+ PfdFrac::new(pfd2 as _),
+ PfdFrac::new(pfd3 as _),
+ ]
+}
+
+/// Set the PLL2 PFD fractional dividers.
+///
+/// The call updates all four dividers without affecting the gating.
+/// However, it does not update the values.
+pub fn set_pll2_pfd_fracs(pll: ral_registers::Instance<RegisterBlock>, pfds: [PfdFrac; 4]) {
+ ral_registers::modify_reg!(self, pll, SYS_PLL2_PFD,
+ PFD3_FRAC: pfds[3].get() as u32,
+ PFD2_FRAC: pfds[2].get() as u32,
+ PFD1_FRAC: pfds[1].get() as u32,
+ PFD0_FRAC: pfds[0].get() as u32,
+ );
+}