From b06e705a737a7b1d040ab415b4e7ecc71cd79094 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis <dirbaio@dirbaio.net>
Date: Tue, 4 Jan 2022 19:25:50 +0100
Subject: [PATCH 1/6] stm32/rcc: change family-specific code from dirs to
 single files.

Consistent with how other peripherals handle their versions.
---
 embassy-stm32/src/rcc/{f0/mod.rs => f0.rs}    |   2 +-
 embassy-stm32/src/rcc/{f1/mod.rs => f1.rs}    |   2 +-
 embassy-stm32/src/rcc/{f3/mod.rs => f3.rs}    |   2 +-
 embassy-stm32/src/rcc/{f4/mod.rs => f4.rs}    |  37 +++-
 embassy-stm32/src/rcc/f4/max.rs               |  21 ---
 embassy-stm32/src/rcc/{f7/mod.rs => f7.rs}    |  26 ++-
 embassy-stm32/src/rcc/f7/max.rs               |  19 ---
 embassy-stm32/src/rcc/{g0/mod.rs => g0.rs}    |   2 +-
 embassy-stm32/src/rcc/{g4/mod.rs => g4.rs}    |   2 +-
 embassy-stm32/src/rcc/{h7/mod.rs => h7.rs}    | 158 +++++++++++++++++-
 embassy-stm32/src/rcc/h7/pll.rs               | 145 ----------------
 embassy-stm32/src/rcc/{l0/mod.rs => l0.rs}    |   2 +-
 embassy-stm32/src/rcc/{l1/mod.rs => l1.rs}    |   2 +-
 embassy-stm32/src/rcc/{l4/mod.rs => l4.rs}    |   2 +-
 embassy-stm32/src/rcc/mod.rs                  |  67 +++-----
 embassy-stm32/src/rcc/{u5/mod.rs => u5.rs}    |   2 +-
 embassy-stm32/src/rcc/{wb/mod.rs => wb.rs}    |   2 +-
 embassy-stm32/src/rcc/{wl5x/mod.rs => wl5.rs} |   2 +-
 18 files changed, 234 insertions(+), 261 deletions(-)
 rename embassy-stm32/src/rcc/{f0/mod.rs => f0.rs} (99%)
 rename embassy-stm32/src/rcc/{f1/mod.rs => f1.rs} (99%)
 rename embassy-stm32/src/rcc/{f3/mod.rs => f3.rs} (99%)
 rename embassy-stm32/src/rcc/{f4/mod.rs => f4.rs} (89%)
 delete mode 100644 embassy-stm32/src/rcc/f4/max.rs
 rename embassy-stm32/src/rcc/{f7/mod.rs => f7.rs} (92%)
 delete mode 100644 embassy-stm32/src/rcc/f7/max.rs
 rename embassy-stm32/src/rcc/{g0/mod.rs => g0.rs} (99%)
 rename embassy-stm32/src/rcc/{g4/mod.rs => g4.rs} (99%)
 rename embassy-stm32/src/rcc/{h7/mod.rs => h7.rs} (81%)
 delete mode 100644 embassy-stm32/src/rcc/h7/pll.rs
 rename embassy-stm32/src/rcc/{l0/mod.rs => l0.rs} (99%)
 rename embassy-stm32/src/rcc/{l1/mod.rs => l1.rs} (99%)
 rename embassy-stm32/src/rcc/{l4/mod.rs => l4.rs} (99%)
 rename embassy-stm32/src/rcc/{u5/mod.rs => u5.rs} (99%)
 rename embassy-stm32/src/rcc/{wb/mod.rs => wb.rs} (99%)
 rename embassy-stm32/src/rcc/{wl5x/mod.rs => wl5.rs} (99%)

diff --git a/embassy-stm32/src/rcc/f0/mod.rs b/embassy-stm32/src/rcc/f0.rs
similarity index 99%
rename from embassy-stm32/src/rcc/f0/mod.rs
rename to embassy-stm32/src/rcc/f0.rs
index 916ed39fc..07a28cc3e 100644
--- a/embassy-stm32/src/rcc/f0/mod.rs
+++ b/embassy-stm32/src/rcc/f0.rs
@@ -201,7 +201,7 @@ impl<'d> Rcc<'d> {
     }
 }
 
-pub unsafe fn init(config: Config) {
+pub(crate) unsafe fn init(config: Config) {
     let rcc = Rcc::new(<peripherals::RCC as embassy::util::Steal>::steal(), config);
     let clocks = rcc.freeze();
     set_freqs(clocks);
diff --git a/embassy-stm32/src/rcc/f1/mod.rs b/embassy-stm32/src/rcc/f1.rs
similarity index 99%
rename from embassy-stm32/src/rcc/f1/mod.rs
rename to embassy-stm32/src/rcc/f1.rs
index d613f5a2f..c9d09ee33 100644
--- a/embassy-stm32/src/rcc/f1/mod.rs
+++ b/embassy-stm32/src/rcc/f1.rs
@@ -207,7 +207,7 @@ impl<'d> Rcc<'d> {
     }
 }
 
-pub unsafe fn init(config: Config) {
+pub(crate) unsafe fn init(config: Config) {
     let rcc = Rcc::new(<peripherals::RCC as embassy::util::Steal>::steal(), config);
     let clocks = rcc.freeze();
     set_freqs(clocks);
diff --git a/embassy-stm32/src/rcc/f3/mod.rs b/embassy-stm32/src/rcc/f3.rs
similarity index 99%
rename from embassy-stm32/src/rcc/f3/mod.rs
rename to embassy-stm32/src/rcc/f3.rs
index ab1bd7607..7b5e0cce7 100644
--- a/embassy-stm32/src/rcc/f3/mod.rs
+++ b/embassy-stm32/src/rcc/f3.rs
@@ -54,7 +54,7 @@ struct PllConfig {
 }
 
 /// Initialize and Set the clock frequencies
-pub unsafe fn init(config: Config) {
+pub(crate) unsafe fn init(config: Config) {
     let r = <peripherals::RCC as embassy::util::Steal>::steal();
     let clocks = Rcc::new(r, config).freeze();
     set_freqs(clocks);
diff --git a/embassy-stm32/src/rcc/f4/mod.rs b/embassy-stm32/src/rcc/f4.rs
similarity index 89%
rename from embassy-stm32/src/rcc/f4/mod.rs
rename to embassy-stm32/src/rcc/f4.rs
index 04083dfa1..08a9bc9b4 100644
--- a/embassy-stm32/src/rcc/f4/mod.rs
+++ b/embassy-stm32/src/rcc/f4.rs
@@ -5,9 +5,6 @@ use crate::time::Hertz;
 use core::marker::PhantomData;
 use embassy::util::Unborrow;
 
-mod max;
-use max::{PCLK1_MAX, PCLK2_MAX};
-
 const HSI: u32 = 16_000_000;
 
 /// Clocks configutation
@@ -88,7 +85,7 @@ impl<'d> Rcc<'d> {
             .config
             .pclk1
             .map(|p| p.0)
-            .unwrap_or_else(|| core::cmp::min(PCLK1_MAX, hclk));
+            .unwrap_or_else(|| core::cmp::min(max::PCLK1_MAX, hclk));
         let (ppre1_bits, ppre1) = match (hclk + pclk1 - 1) / pclk1 {
             0 => unreachable!(),
             1 => (0b000, 1),
@@ -101,13 +98,13 @@ impl<'d> Rcc<'d> {
 
         // Calculate real APB1 clock
         let pclk1 = hclk / ppre1;
-        assert!(pclk1 <= PCLK1_MAX);
+        assert!(pclk1 <= max::PCLK1_MAX);
 
         let pclk2 = self
             .config
             .pclk2
             .map(|p| p.0)
-            .unwrap_or_else(|| core::cmp::min(PCLK2_MAX, hclk));
+            .unwrap_or_else(|| core::cmp::min(max::PCLK2_MAX, hclk));
         let (ppre2_bits, ppre2) = match (hclk + pclk2 - 1) / pclk2 {
             0 => unreachable!(),
             1 => (0b000, 1),
@@ -120,7 +117,7 @@ impl<'d> Rcc<'d> {
 
         // Calculate real APB2 clock
         let pclk2 = hclk / ppre2;
-        assert!(pclk2 <= PCLK2_MAX);
+        assert!(pclk2 <= max::PCLK2_MAX);
 
         Self::flash_setup(sysclk);
 
@@ -298,7 +295,7 @@ impl<'d> Rcc<'d> {
     }
 }
 
-pub unsafe fn init(config: Config) {
+pub(crate) unsafe fn init(config: Config) {
     let r = <peripherals::RCC as embassy::util::Steal>::steal();
     let clocks = Rcc::new(r, config).freeze();
     set_freqs(clocks);
@@ -309,3 +306,27 @@ struct PllResults {
     pllsysclk: Option<u32>,
     pll48clk: Option<u32>,
 }
+
+mod max {
+    #[cfg(stm32f401)]
+    pub(crate) const SYSCLK_MAX: u32 = 84_000_000;
+
+    #[cfg(any(stm32f405, stm32f407, stm32f415, stm32f417,))]
+    pub(crate) const SYSCLK_MAX: u32 = 168_000_000;
+
+    #[cfg(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423,))]
+    pub(crate) const SYSCLK_MAX: u32 = 100_000_000;
+
+    #[cfg(any(
+        stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479,
+    ))]
+    pub(crate) const SYSCLK_MAX: u32 = 180_000_000;
+
+    #[cfg(any(stm32f401, stm32f410, stm32f411, stm32f412, stm32f413, stm32f423,))]
+    pub(crate) const PCLK2_MAX: u32 = SYSCLK_MAX;
+
+    #[cfg(not(any(stm32f401, stm32f410, stm32f411, stm32f412, stm32f413, stm32f423,)))]
+    pub(crate) const PCLK2_MAX: u32 = SYSCLK_MAX / 2;
+
+    pub(crate) const PCLK1_MAX: u32 = PCLK2_MAX / 2;
+}
diff --git a/embassy-stm32/src/rcc/f4/max.rs b/embassy-stm32/src/rcc/f4/max.rs
deleted file mode 100644
index dd8de3da9..000000000
--- a/embassy-stm32/src/rcc/f4/max.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-#[cfg(stm32f401)]
-pub(crate) const SYSCLK_MAX: u32 = 84_000_000;
-
-#[cfg(any(stm32f405, stm32f407, stm32f415, stm32f417,))]
-pub(crate) const SYSCLK_MAX: u32 = 168_000_000;
-
-#[cfg(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423,))]
-pub(crate) const SYSCLK_MAX: u32 = 100_000_000;
-
-#[cfg(any(
-    stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479,
-))]
-pub(crate) const SYSCLK_MAX: u32 = 180_000_000;
-
-#[cfg(any(stm32f401, stm32f410, stm32f411, stm32f412, stm32f413, stm32f423,))]
-pub(crate) const PCLK2_MAX: u32 = SYSCLK_MAX;
-
-#[cfg(not(any(stm32f401, stm32f410, stm32f411, stm32f412, stm32f413, stm32f423,)))]
-pub(crate) const PCLK2_MAX: u32 = SYSCLK_MAX / 2;
-
-pub(crate) const PCLK1_MAX: u32 = PCLK2_MAX / 2;
diff --git a/embassy-stm32/src/rcc/f7/mod.rs b/embassy-stm32/src/rcc/f7.rs
similarity index 92%
rename from embassy-stm32/src/rcc/f7/mod.rs
rename to embassy-stm32/src/rcc/f7.rs
index c13e20167..25f78c701 100644
--- a/embassy-stm32/src/rcc/f7/mod.rs
+++ b/embassy-stm32/src/rcc/f7.rs
@@ -1,5 +1,3 @@
-mod max;
-
 use crate::pac::{FLASH, PWR, RCC};
 use crate::peripherals;
 use crate::rcc::{get_freqs, set_freqs, Clocks};
@@ -334,7 +332,7 @@ impl<'d> Rcc<'d> {
     }
 }
 
-pub unsafe fn init(config: Config) {
+pub(crate) unsafe fn init(config: Config) {
     let r = <peripherals::RCC as embassy::util::Steal>::steal();
     let clocks = Rcc::new(r, config).freeze();
     set_freqs(clocks);
@@ -345,3 +343,25 @@ struct PllResults {
     pllsysclk: Option<u32>,
     pll48clk: Option<u32>,
 }
+
+mod max {
+    pub(crate) const HSE_OSC_MIN: u32 = 4_000_000;
+    pub(crate) const HSE_OSC_MAX: u32 = 26_000_000;
+    pub(crate) const HSE_BYPASS_MIN: u32 = 1_000_000;
+    pub(crate) const HSE_BYPASS_MAX: u32 = 50_000_000;
+
+    pub(crate) const HCLK_MAX: u32 = 216_000_000;
+    pub(crate) const HCLK_OVERDRIVE_FREQUENCY: u32 = 180_000_000;
+
+    pub(crate) const SYSCLK_MIN: u32 = 12_500_000;
+    pub(crate) const SYSCLK_MAX: u32 = 216_000_000;
+
+    pub(crate) const PCLK1_MIN: u32 = SYSCLK_MIN;
+    pub(crate) const PCLK1_MAX: u32 = SYSCLK_MAX / 4;
+
+    pub(crate) const PCLK2_MIN: u32 = SYSCLK_MIN;
+    pub(crate) const PCLK2_MAX: u32 = SYSCLK_MAX / 2;
+
+    pub(crate) const PLL_48_CLK: u32 = 48_000_000;
+    pub(crate) const PLL_48_TOLERANCE: u32 = 120_000;
+}
diff --git a/embassy-stm32/src/rcc/f7/max.rs b/embassy-stm32/src/rcc/f7/max.rs
deleted file mode 100644
index db00fdf3e..000000000
--- a/embassy-stm32/src/rcc/f7/max.rs
+++ /dev/null
@@ -1,19 +0,0 @@
-pub(crate) const HSE_OSC_MIN: u32 = 4_000_000;
-pub(crate) const HSE_OSC_MAX: u32 = 26_000_000;
-pub(crate) const HSE_BYPASS_MIN: u32 = 1_000_000;
-pub(crate) const HSE_BYPASS_MAX: u32 = 50_000_000;
-
-pub(crate) const HCLK_MAX: u32 = 216_000_000;
-pub(crate) const HCLK_OVERDRIVE_FREQUENCY: u32 = 180_000_000;
-
-pub(crate) const SYSCLK_MIN: u32 = 12_500_000;
-pub(crate) const SYSCLK_MAX: u32 = 216_000_000;
-
-pub(crate) const PCLK1_MIN: u32 = SYSCLK_MIN;
-pub(crate) const PCLK1_MAX: u32 = SYSCLK_MAX / 4;
-
-pub(crate) const PCLK2_MIN: u32 = SYSCLK_MIN;
-pub(crate) const PCLK2_MAX: u32 = SYSCLK_MAX / 2;
-
-pub(crate) const PLL_48_CLK: u32 = 48_000_000;
-pub(crate) const PLL_48_TOLERANCE: u32 = 120_000;
diff --git a/embassy-stm32/src/rcc/g0/mod.rs b/embassy-stm32/src/rcc/g0.rs
similarity index 99%
rename from embassy-stm32/src/rcc/g0/mod.rs
rename to embassy-stm32/src/rcc/g0.rs
index 7f7af2fc9..df11ff36d 100644
--- a/embassy-stm32/src/rcc/g0/mod.rs
+++ b/embassy-stm32/src/rcc/g0.rs
@@ -227,7 +227,7 @@ impl RccExt for RCC {
     }
 }
 
-pub unsafe fn init(config: Config) {
+pub(crate) unsafe fn init(config: Config) {
     let r = <peripherals::RCC as embassy::util::Steal>::steal();
     let clocks = r.freeze(config);
     set_freqs(clocks);
diff --git a/embassy-stm32/src/rcc/g4/mod.rs b/embassy-stm32/src/rcc/g4.rs
similarity index 99%
rename from embassy-stm32/src/rcc/g4/mod.rs
rename to embassy-stm32/src/rcc/g4.rs
index 8a75b2e03..ee49e2ece 100644
--- a/embassy-stm32/src/rcc/g4/mod.rs
+++ b/embassy-stm32/src/rcc/g4.rs
@@ -203,7 +203,7 @@ impl RccExt for RCC {
     }
 }
 
-pub unsafe fn init(config: Config) {
+pub(crate) unsafe fn init(config: Config) {
     let r = <peripherals::RCC as embassy::util::Steal>::steal();
     let clocks = r.freeze(config);
     set_freqs(clocks);
diff --git a/embassy-stm32/src/rcc/h7/mod.rs b/embassy-stm32/src/rcc/h7.rs
similarity index 81%
rename from embassy-stm32/src/rcc/h7/mod.rs
rename to embassy-stm32/src/rcc/h7.rs
index cd493a80a..ac4d033ba 100644
--- a/embassy-stm32/src/rcc/h7/mod.rs
+++ b/embassy-stm32/src/rcc/h7.rs
@@ -13,8 +13,6 @@ use crate::pwr::{Power, VoltageScale};
 use crate::rcc::{set_freqs, Clocks};
 use crate::time::Hertz;
 
-mod pll;
-use pll::pll_setup;
 pub use pll::PllConfig;
 
 const HSI: Hertz = Hertz(64_000_000);
@@ -116,11 +114,11 @@ impl<'d> Rcc<'d> {
 
         // NOTE(unsafe) We have exclusive access to the RCC
         let (pll1_p_ck, pll1_q_ck, pll1_r_ck) =
-            unsafe { pll_setup(srcclk.0, &self.config.pll1, 0) };
+            unsafe { pll::pll_setup(srcclk.0, &self.config.pll1, 0) };
         let (pll2_p_ck, pll2_q_ck, pll2_r_ck) =
-            unsafe { pll_setup(srcclk.0, &self.config.pll2, 1) };
+            unsafe { pll::pll_setup(srcclk.0, &self.config.pll2, 1) };
         let (pll3_p_ck, pll3_q_ck, pll3_r_ck) =
-            unsafe { pll_setup(srcclk.0, &self.config.pll3, 2) };
+            unsafe { pll::pll_setup(srcclk.0, &self.config.pll3, 2) };
 
         let sys_ck = if sys_use_pll1_p {
             Hertz(unwrap!(pll1_p_ck)) // Must have been set by sys_ck_setup
@@ -683,7 +681,7 @@ impl<'d, T: McoInstance> Mco<'d, T> {
     }
 }
 
-pub unsafe fn init(config: Config) {
+pub(crate) unsafe fn init(config: Config) {
     let mut power = Power::new(<peripherals::PWR as embassy::util::Steal>::steal(), false);
     let rcc = Rcc::new(<peripherals::RCC as embassy::util::Steal>::steal(), config);
     let core_clocks = rcc.freeze(&mut power);
@@ -700,3 +698,151 @@ pub unsafe fn init(config: Config) {
         apb2_tim: core_clocks.timy_ker_ck.unwrap_or(core_clocks.pclk2),
     });
 }
+
+mod pll {
+    use super::{Hertz, RCC};
+
+    const VCO_MIN: u32 = 150_000_000;
+    const VCO_MAX: u32 = 420_000_000;
+
+    #[derive(Default)]
+    pub struct PllConfig {
+        pub p_ck: Option<Hertz>,
+        pub q_ck: Option<Hertz>,
+        pub r_ck: Option<Hertz>,
+    }
+
+    pub(super) struct PllConfigResults {
+        pub ref_x_ck: u32,
+        pub pll_x_m: u32,
+        pub pll_x_p: u32,
+        pub vco_ck_target: u32,
+    }
+
+    fn vco_output_divider_setup(output: u32, plln: usize) -> (u32, u32) {
+        let pll_x_p = if plln == 0 {
+            if output > VCO_MAX / 2 {
+                1
+            } else {
+                ((VCO_MAX / output) | 1) - 1 // Must be even or unity
+            }
+        } else {
+            // Specific to PLL2/3, will subtract 1 later
+            if output > VCO_MAX / 2 {
+                1
+            } else {
+                VCO_MAX / output
+            }
+        };
+
+        let vco_ck = output + pll_x_p;
+
+        assert!(pll_x_p < 128);
+        assert!(vco_ck >= VCO_MIN);
+        assert!(vco_ck <= VCO_MAX);
+
+        (vco_ck, pll_x_p)
+    }
+
+    /// # Safety
+    ///
+    /// Must have exclusive access to the RCC register block
+    unsafe fn vco_setup(pll_src: u32, requested_output: u32, plln: usize) -> PllConfigResults {
+        use crate::pac::rcc::vals::{Pllrge, Pllvcosel};
+
+        let (vco_ck_target, pll_x_p) = vco_output_divider_setup(requested_output, plln);
+
+        // Input divisor, resulting in a reference clock in the range
+        // 1 to 2 MHz. Choose the highest reference clock (lowest m)
+        let pll_x_m = (pll_src + 1_999_999) / 2_000_000;
+        assert!(pll_x_m < 64);
+
+        // Calculate resulting reference clock
+        let ref_x_ck = pll_src / pll_x_m;
+        assert!((1_000_000..=2_000_000).contains(&ref_x_ck));
+
+        RCC.pllcfgr().modify(|w| {
+            w.set_pllvcosel(plln, Pllvcosel::MEDIUMVCO);
+            w.set_pllrge(plln, Pllrge::RANGE1);
+        });
+        PllConfigResults {
+            ref_x_ck,
+            pll_x_m,
+            pll_x_p,
+            vco_ck_target,
+        }
+    }
+
+    /// # Safety
+    ///
+    /// Must have exclusive access to the RCC register block
+    pub(super) unsafe fn pll_setup(
+        pll_src: u32,
+        config: &PllConfig,
+        plln: usize,
+    ) -> (Option<u32>, Option<u32>, Option<u32>) {
+        use crate::pac::rcc::vals::Divp;
+
+        match config.p_ck {
+            Some(requested_output) => {
+                let config_results = vco_setup(pll_src, requested_output.0, plln);
+                let PllConfigResults {
+                    ref_x_ck,
+                    pll_x_m,
+                    pll_x_p,
+                    vco_ck_target,
+                } = config_results;
+
+                RCC.pllckselr().modify(|w| w.set_divm(plln, pll_x_m as u8));
+
+                // Feedback divider. Integer only
+                let pll_x_n = vco_ck_target / ref_x_ck;
+                assert!(pll_x_n >= 4);
+                assert!(pll_x_n <= 512);
+                RCC.plldivr(plln)
+                    .modify(|w| w.set_divn1((pll_x_n - 1) as u16));
+
+                // No FRACN
+                RCC.pllcfgr().modify(|w| w.set_pllfracen(plln, false));
+                let vco_ck = ref_x_ck * pll_x_n;
+
+                RCC.plldivr(plln)
+                    .modify(|w| w.set_divp1(Divp((pll_x_p - 1) as u8)));
+                RCC.pllcfgr().modify(|w| w.set_divpen(plln, true));
+
+                // Calulate additional output dividers
+                let q_ck = match config.q_ck {
+                    Some(Hertz(ck)) if ck > 0 => {
+                        let div = (vco_ck + ck - 1) / ck;
+                        RCC.plldivr(plln).modify(|w| w.set_divq1((div - 1) as u8));
+                        RCC.pllcfgr().modify(|w| w.set_divqen(plln, true));
+                        Some(vco_ck / div)
+                    }
+                    _ => None,
+                };
+                let r_ck = match config.r_ck {
+                    Some(Hertz(ck)) if ck > 0 => {
+                        let div = (vco_ck + ck - 1) / ck;
+                        RCC.plldivr(plln).modify(|w| w.set_divr1((div - 1) as u8));
+                        RCC.pllcfgr().modify(|w| w.set_divren(plln, true));
+                        Some(vco_ck / div)
+                    }
+                    _ => None,
+                };
+
+                (Some(vco_ck / pll_x_p), q_ck, r_ck)
+            }
+            None => {
+                assert!(
+                    config.q_ck.is_none(),
+                    "Must set PLL P clock for Q clock to take effect!"
+                );
+                assert!(
+                    config.r_ck.is_none(),
+                    "Must set PLL P clock for R clock to take effect!"
+                );
+                (None, None, None)
+            }
+        }
+    }
+}
diff --git a/embassy-stm32/src/rcc/h7/pll.rs b/embassy-stm32/src/rcc/h7/pll.rs
deleted file mode 100644
index d3709378b..000000000
--- a/embassy-stm32/src/rcc/h7/pll.rs
+++ /dev/null
@@ -1,145 +0,0 @@
-use super::{Hertz, RCC};
-
-const VCO_MIN: u32 = 150_000_000;
-const VCO_MAX: u32 = 420_000_000;
-
-#[derive(Default)]
-pub struct PllConfig {
-    pub p_ck: Option<Hertz>,
-    pub q_ck: Option<Hertz>,
-    pub r_ck: Option<Hertz>,
-}
-
-pub(super) struct PllConfigResults {
-    pub ref_x_ck: u32,
-    pub pll_x_m: u32,
-    pub pll_x_p: u32,
-    pub vco_ck_target: u32,
-}
-
-fn vco_output_divider_setup(output: u32, plln: usize) -> (u32, u32) {
-    let pll_x_p = if plln == 0 {
-        if output > VCO_MAX / 2 {
-            1
-        } else {
-            ((VCO_MAX / output) | 1) - 1 // Must be even or unity
-        }
-    } else {
-        // Specific to PLL2/3, will subtract 1 later
-        if output > VCO_MAX / 2 {
-            1
-        } else {
-            VCO_MAX / output
-        }
-    };
-
-    let vco_ck = output + pll_x_p;
-
-    assert!(pll_x_p < 128);
-    assert!(vco_ck >= VCO_MIN);
-    assert!(vco_ck <= VCO_MAX);
-
-    (vco_ck, pll_x_p)
-}
-
-/// # Safety
-///
-/// Must have exclusive access to the RCC register block
-unsafe fn vco_setup(pll_src: u32, requested_output: u32, plln: usize) -> PllConfigResults {
-    use crate::pac::rcc::vals::{Pllrge, Pllvcosel};
-
-    let (vco_ck_target, pll_x_p) = vco_output_divider_setup(requested_output, plln);
-
-    // Input divisor, resulting in a reference clock in the range
-    // 1 to 2 MHz. Choose the highest reference clock (lowest m)
-    let pll_x_m = (pll_src + 1_999_999) / 2_000_000;
-    assert!(pll_x_m < 64);
-
-    // Calculate resulting reference clock
-    let ref_x_ck = pll_src / pll_x_m;
-    assert!((1_000_000..=2_000_000).contains(&ref_x_ck));
-
-    RCC.pllcfgr().modify(|w| {
-        w.set_pllvcosel(plln, Pllvcosel::MEDIUMVCO);
-        w.set_pllrge(plln, Pllrge::RANGE1);
-    });
-    PllConfigResults {
-        ref_x_ck,
-        pll_x_m,
-        pll_x_p,
-        vco_ck_target,
-    }
-}
-
-/// # Safety
-///
-/// Must have exclusive access to the RCC register block
-pub(super) unsafe fn pll_setup(
-    pll_src: u32,
-    config: &PllConfig,
-    plln: usize,
-) -> (Option<u32>, Option<u32>, Option<u32>) {
-    use crate::pac::rcc::vals::Divp;
-
-    match config.p_ck {
-        Some(requested_output) => {
-            let config_results = vco_setup(pll_src, requested_output.0, plln);
-            let PllConfigResults {
-                ref_x_ck,
-                pll_x_m,
-                pll_x_p,
-                vco_ck_target,
-            } = config_results;
-
-            RCC.pllckselr().modify(|w| w.set_divm(plln, pll_x_m as u8));
-
-            // Feedback divider. Integer only
-            let pll_x_n = vco_ck_target / ref_x_ck;
-            assert!(pll_x_n >= 4);
-            assert!(pll_x_n <= 512);
-            RCC.plldivr(plln)
-                .modify(|w| w.set_divn1((pll_x_n - 1) as u16));
-
-            // No FRACN
-            RCC.pllcfgr().modify(|w| w.set_pllfracen(plln, false));
-            let vco_ck = ref_x_ck * pll_x_n;
-
-            RCC.plldivr(plln)
-                .modify(|w| w.set_divp1(Divp((pll_x_p - 1) as u8)));
-            RCC.pllcfgr().modify(|w| w.set_divpen(plln, true));
-
-            // Calulate additional output dividers
-            let q_ck = match config.q_ck {
-                Some(Hertz(ck)) if ck > 0 => {
-                    let div = (vco_ck + ck - 1) / ck;
-                    RCC.plldivr(plln).modify(|w| w.set_divq1((div - 1) as u8));
-                    RCC.pllcfgr().modify(|w| w.set_divqen(plln, true));
-                    Some(vco_ck / div)
-                }
-                _ => None,
-            };
-            let r_ck = match config.r_ck {
-                Some(Hertz(ck)) if ck > 0 => {
-                    let div = (vco_ck + ck - 1) / ck;
-                    RCC.plldivr(plln).modify(|w| w.set_divr1((div - 1) as u8));
-                    RCC.pllcfgr().modify(|w| w.set_divren(plln, true));
-                    Some(vco_ck / div)
-                }
-                _ => None,
-            };
-
-            (Some(vco_ck / pll_x_p), q_ck, r_ck)
-        }
-        None => {
-            assert!(
-                config.q_ck.is_none(),
-                "Must set PLL P clock for Q clock to take effect!"
-            );
-            assert!(
-                config.r_ck.is_none(),
-                "Must set PLL P clock for R clock to take effect!"
-            );
-            (None, None, None)
-        }
-    }
-}
diff --git a/embassy-stm32/src/rcc/l0/mod.rs b/embassy-stm32/src/rcc/l0.rs
similarity index 99%
rename from embassy-stm32/src/rcc/l0/mod.rs
rename to embassy-stm32/src/rcc/l0.rs
index fd84f09c5..fc70ef0ac 100644
--- a/embassy-stm32/src/rcc/l0/mod.rs
+++ b/embassy-stm32/src/rcc/l0.rs
@@ -430,7 +430,7 @@ impl RccExt for RCC {
 #[derive(Clone, Copy)]
 pub struct HSI48(());
 
-pub unsafe fn init(config: Config) {
+pub(crate) unsafe fn init(config: Config) {
     let r = <peripherals::RCC as embassy::util::Steal>::steal();
     let clocks = r.freeze(config);
     set_freqs(clocks);
diff --git a/embassy-stm32/src/rcc/l1/mod.rs b/embassy-stm32/src/rcc/l1.rs
similarity index 99%
rename from embassy-stm32/src/rcc/l1/mod.rs
rename to embassy-stm32/src/rcc/l1.rs
index e46bee323..746433c12 100644
--- a/embassy-stm32/src/rcc/l1/mod.rs
+++ b/embassy-stm32/src/rcc/l1.rs
@@ -254,7 +254,7 @@ impl RccExt for RCC {
     }
 }
 
-pub unsafe fn init(config: Config) {
+pub(crate) unsafe fn init(config: Config) {
     let r = <peripherals::RCC as embassy::util::Steal>::steal();
     let clocks = r.freeze(config);
     set_freqs(clocks);
diff --git a/embassy-stm32/src/rcc/l4/mod.rs b/embassy-stm32/src/rcc/l4.rs
similarity index 99%
rename from embassy-stm32/src/rcc/l4/mod.rs
rename to embassy-stm32/src/rcc/l4.rs
index a0eedf0b6..510cbddfa 100644
--- a/embassy-stm32/src/rcc/l4/mod.rs
+++ b/embassy-stm32/src/rcc/l4.rs
@@ -482,7 +482,7 @@ impl RccExt for RCC {
     }
 }
 
-pub unsafe fn init(config: Config) {
+pub(crate) unsafe fn init(config: Config) {
     let r = <peripherals::RCC as embassy::util::Steal>::steal();
     let clocks = r.freeze(config);
     set_freqs(clocks);
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs
index 0a7edb37a..bf612464f 100644
--- a/embassy-stm32/src/rcc/mod.rs
+++ b/embassy-stm32/src/rcc/mod.rs
@@ -4,6 +4,23 @@ use crate::peripherals;
 use crate::time::Hertz;
 use core::mem::MaybeUninit;
 
+#[cfg_attr(any(rcc_f0, rcc_f0x0), path = "f0.rs")]
+#[cfg_attr(rcc_f1, path = "f1.rs")]
+#[cfg_attr(rcc_f3, path = "f3.rs")]
+#[cfg_attr(any(rcc_f4, rcc_f410), path = "f4.rs")]
+#[cfg_attr(rcc_f7, path = "f7.rs")]
+#[cfg_attr(rcc_g0, path = "g0.rs")]
+#[cfg_attr(rcc_g4, path = "g4.rs")]
+#[cfg_attr(any(rcc_h7, rcc_h7ab), path = "h7.rs")]
+#[cfg_attr(rcc_l0, path = "l0.rs")]
+#[cfg_attr(rcc_l1, path = "l1.rs")]
+#[cfg_attr(rcc_l4, path = "l4.rs")]
+#[cfg_attr(rcc_u5, path = "u5.rs")]
+#[cfg_attr(rcc_wb, path = "wb.rs")]
+#[cfg_attr(rcc_wl5, path = "wl5.rs")]
+mod _version;
+pub use _version::*;
+
 #[derive(Clone, Copy)]
 pub struct Clocks {
     pub sys: Hertz,
@@ -59,61 +76,15 @@ static mut CLOCK_FREQS: MaybeUninit<Clocks> = MaybeUninit::uninit();
 /// Sets the clock frequencies
 ///
 /// Safety: Sets a mutable global.
-pub unsafe fn set_freqs(freqs: Clocks) {
+pub(crate) unsafe fn set_freqs(freqs: Clocks) {
     CLOCK_FREQS.as_mut_ptr().write(freqs);
 }
 
 /// Safety: Reads a mutable global.
-pub unsafe fn get_freqs() -> &'static Clocks {
+pub(crate) unsafe fn get_freqs() -> &'static Clocks {
     &*CLOCK_FREQS.as_ptr()
 }
 
-cfg_if::cfg_if! {
-    if #[cfg(rcc_h7)] {
-        mod h7;
-        pub use h7::*;
-    } else if #[cfg(rcc_l0)] {
-        mod l0;
-        pub use l0::*;
-    } else if #[cfg(rcc_l1)] {
-        mod l1;
-        pub use l1::*;
-    } else if #[cfg(rcc_l4)] {
-        mod l4;
-        pub use l4::*;
-    } else if #[cfg(rcc_f1)] {
-        mod f1;
-        pub use f1::*;
-    } else if #[cfg(rcc_f3)] {
-        mod f3;
-        pub use f3::*;
-    } else if #[cfg(rcc_f4)] {
-        mod f4;
-        pub use f4::*;
-    } else if #[cfg(rcc_f7)] {
-        mod f7;
-        pub use f7::*;
-    } else if #[cfg(rcc_wb)] {
-        mod wb;
-        pub use wb::*;
-    } else if #[cfg(rcc_wl5)] {
-        mod wl5x;
-        pub use wl5x::*;
-    } else if #[cfg(any(rcc_f0, rcc_f0x0))] {
-        mod f0;
-        pub use f0::*;
-    } else if #[cfg(any(rcc_g0))] {
-        mod g0;
-        pub use g0::*;
-    } else if #[cfg(any(rcc_g4))] {
-        mod g4;
-        pub use g4::*;
-    } else if #[cfg(any(rcc_u5))] {
-        mod u5;
-        pub use u5::*;
-    }
-}
-
 pub(crate) mod sealed {
     pub trait RccPeripheral {
         fn frequency() -> crate::time::Hertz;
diff --git a/embassy-stm32/src/rcc/u5/mod.rs b/embassy-stm32/src/rcc/u5.rs
similarity index 99%
rename from embassy-stm32/src/rcc/u5/mod.rs
rename to embassy-stm32/src/rcc/u5.rs
index a3df3a02d..e8bd82718 100644
--- a/embassy-stm32/src/rcc/u5/mod.rs
+++ b/embassy-stm32/src/rcc/u5.rs
@@ -502,7 +502,7 @@ impl RccExt for RCC {
     }
 }
 
-pub unsafe fn init(config: Config) {
+pub(crate) unsafe fn init(config: Config) {
     let r = <peripherals::RCC as embassy::util::Steal>::steal();
     let power = Power::new(<peripherals::PWR as embassy::util::Steal>::steal());
     let clocks = r.freeze(config, &power);
diff --git a/embassy-stm32/src/rcc/wb/mod.rs b/embassy-stm32/src/rcc/wb.rs
similarity index 99%
rename from embassy-stm32/src/rcc/wb/mod.rs
rename to embassy-stm32/src/rcc/wb.rs
index 73835cacd..58146d4bd 100644
--- a/embassy-stm32/src/rcc/wb/mod.rs
+++ b/embassy-stm32/src/rcc/wb.rs
@@ -206,7 +206,7 @@ impl RccExt for RCC {
     }
 }
 
-pub unsafe fn init(config: Config) {
+pub(crate) unsafe fn init(config: Config) {
     let r = <peripherals::RCC as embassy::util::Steal>::steal();
     let clocks = r.freeze(config);
     set_freqs(clocks);
diff --git a/embassy-stm32/src/rcc/wl5x/mod.rs b/embassy-stm32/src/rcc/wl5.rs
similarity index 99%
rename from embassy-stm32/src/rcc/wl5x/mod.rs
rename to embassy-stm32/src/rcc/wl5.rs
index edf603ee6..00b91dfec 100644
--- a/embassy-stm32/src/rcc/wl5x/mod.rs
+++ b/embassy-stm32/src/rcc/wl5.rs
@@ -229,7 +229,7 @@ impl RccExt for RCC {
     }
 }
 
-pub unsafe fn init(config: Config) {
+pub(crate) unsafe fn init(config: Config) {
     let r = <peripherals::RCC as embassy::util::Steal>::steal();
     let clocks = r.freeze(config);
     set_freqs(clocks);

From c3fd9a0f44ae898c5cf1272dab6b8f46e119fab3 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis <dirbaio@dirbaio.net>
Date: Tue, 4 Jan 2022 21:17:17 +0100
Subject: [PATCH 2/6] stm32/rcc: f4/f7 cleanup and make a bit more consistent.

---
 embassy-stm32/src/pwr/mod.rs  |  1 +
 embassy-stm32/src/pwr/wb55.rs |  0
 embassy-stm32/src/rcc/f4.rs   | 43 ++++++++++++++++++-----------------
 embassy-stm32/src/rcc/f7.rs   | 28 +++++++++++------------
 embassy-stm32/src/rcc/mod.rs  |  2 +-
 stm32-data                    |  2 +-
 6 files changed, 38 insertions(+), 38 deletions(-)
 create mode 100644 embassy-stm32/src/pwr/wb55.rs

diff --git a/embassy-stm32/src/pwr/mod.rs b/embassy-stm32/src/pwr/mod.rs
index 18f462bd2..d948c398d 100644
--- a/embassy-stm32/src/pwr/mod.rs
+++ b/embassy-stm32/src/pwr/mod.rs
@@ -7,6 +7,7 @@
 #[cfg_attr(pwr_g4, path = "g4.rs")]
 #[cfg_attr(pwr_l1, path = "l1.rs")]
 #[cfg_attr(pwr_u5, path = "u5.rs")]
+#[cfg_attr(pwr_wb55, path = "wb55.rs")]
 mod _version;
 
 pub use _version::*;
diff --git a/embassy-stm32/src/pwr/wb55.rs b/embassy-stm32/src/pwr/wb55.rs
new file mode 100644
index 000000000..e69de29bb
diff --git a/embassy-stm32/src/rcc/f4.rs b/embassy-stm32/src/rcc/f4.rs
index 08a9bc9b4..58a08adbf 100644
--- a/embassy-stm32/src/rcc/f4.rs
+++ b/embassy-stm32/src/rcc/f4.rs
@@ -7,17 +7,18 @@ use embassy::util::Unborrow;
 
 const HSI: u32 = 16_000_000;
 
-/// Clocks configutation
+/// Clocks configuration
 #[non_exhaustive]
 #[derive(Default)]
 pub struct Config {
     pub hse: Option<Hertz>,
     pub bypass_hse: bool,
-    pub pll48: bool,
-    pub sys_ck: Option<Hertz>,
     pub hclk: Option<Hertz>,
+    pub sys_ck: Option<Hertz>,
     pub pclk1: Option<Hertz>,
     pub pclk2: Option<Hertz>,
+
+    pub pll48: bool,
 }
 
 /// RCC peripheral
@@ -38,6 +39,8 @@ impl<'d> Rcc<'d> {
         use super::sealed::RccPeripheral;
         use crate::pac::rcc::vals::{Hpre, Hsebyp, Ppre, Sw};
 
+        peripherals::PWR::enable();
+
         let pllsrcclk = self.config.hse.map(|hse| hse.0).unwrap_or(HSI);
         let sysclk = self.config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk);
         let sysclk_on_pll = sysclk != pllsrcclk;
@@ -50,12 +53,9 @@ impl<'d> Rcc<'d> {
         );
 
         if self.config.pll48 {
-            assert!(
-                // USB specification allows +-0.25%
-                plls.pll48clk
-                    .map(|freq| (48_000_000 - freq as i32).abs() <= 120_000)
-                    .unwrap_or(false)
-            );
+            let freq = unwrap!(plls.pll48clk);
+
+            assert!((max::PLL_48_CLK as i32 - freq as i32).abs() <= max::PLL_48_TOLERANCE as i32);
         }
 
         let sysclk = if sysclk_on_pll {
@@ -64,6 +64,7 @@ impl<'d> Rcc<'d> {
             sysclk
         };
 
+        // AHB prescaler
         let hclk = self.config.hclk.map(|h| h.0).unwrap_or(sysclk);
         let (hpre_bits, hpre_div) = match (sysclk + hclk - 1) / hclk {
             0 => unreachable!(),
@@ -86,6 +87,7 @@ impl<'d> Rcc<'d> {
             .pclk1
             .map(|p| p.0)
             .unwrap_or_else(|| core::cmp::min(max::PCLK1_MAX, hclk));
+
         let (ppre1_bits, ppre1) = match (hclk + pclk1 - 1) / pclk1 {
             0 => unreachable!(),
             1 => (0b000, 1),
@@ -136,14 +138,12 @@ impl<'d> Rcc<'d> {
             unsafe {
                 RCC.cr().modify(|w| w.set_pllon(true));
 
-                if hclk > 168_000_000 {
-                    peripherals::PWR::enable();
+                if hclk > max::HCLK_OVERDRIVE_FREQUENCY {
+                    PWR.cr1().modify(|w| w.set_oden(true));
+                    while !PWR.csr1().read().odrdy() {}
 
-                    PWR.cr().modify(|w| w.set_oden(true));
-                    while !PWR.csr().read().odrdy() {}
-
-                    PWR.cr().modify(|w| w.set_odswen(true));
-                    while !PWR.csr().read().odswrdy() {}
+                    PWR.cr1().modify(|w| w.set_odswen(true));
+                    while !PWR.csr1().read().odswrdy() {}
                 }
 
                 while !RCC.cr().read().pllrdy() {}
@@ -310,23 +310,24 @@ struct PllResults {
 mod max {
     #[cfg(stm32f401)]
     pub(crate) const SYSCLK_MAX: u32 = 84_000_000;
-
     #[cfg(any(stm32f405, stm32f407, stm32f415, stm32f417,))]
     pub(crate) const SYSCLK_MAX: u32 = 168_000_000;
-
     #[cfg(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423,))]
     pub(crate) const SYSCLK_MAX: u32 = 100_000_000;
-
     #[cfg(any(
         stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479,
     ))]
     pub(crate) const SYSCLK_MAX: u32 = 180_000_000;
 
+    pub(crate) const HCLK_OVERDRIVE_FREQUENCY: u32 = 168_000_000;
+
+    pub(crate) const PCLK1_MAX: u32 = PCLK2_MAX / 2;
+
     #[cfg(any(stm32f401, stm32f410, stm32f411, stm32f412, stm32f413, stm32f423,))]
     pub(crate) const PCLK2_MAX: u32 = SYSCLK_MAX;
-
     #[cfg(not(any(stm32f401, stm32f410, stm32f411, stm32f412, stm32f413, stm32f423,)))]
     pub(crate) const PCLK2_MAX: u32 = SYSCLK_MAX / 2;
 
-    pub(crate) const PCLK1_MAX: u32 = PCLK2_MAX / 2;
+    pub(crate) const PLL_48_CLK: u32 = 48_000_000;
+    pub(crate) const PLL_48_TOLERANCE: u32 = 120_000;
 }
diff --git a/embassy-stm32/src/rcc/f7.rs b/embassy-stm32/src/rcc/f7.rs
index 25f78c701..d29ba31f0 100644
--- a/embassy-stm32/src/rcc/f7.rs
+++ b/embassy-stm32/src/rcc/f7.rs
@@ -7,6 +7,7 @@ use embassy::util::Unborrow;
 
 const HSI: u32 = 16_000_000;
 
+/// Clocks configuration
 #[non_exhaustive]
 #[derive(Default)]
 pub struct Config {
@@ -46,27 +47,25 @@ impl<'d> Rcc<'d> {
         use crate::pac::pwr::vals::Vos;
         use crate::pac::rcc::vals::{Hpre, Hsebyp, Ppre, Sw};
 
-        let base_clock = self.config.hse.map(|hse| hse.0).unwrap_or(HSI);
-        let sysclk = self.config.sys_ck.map(|sys| sys.0).unwrap_or(base_clock);
-        let sysclk_on_pll = sysclk != base_clock;
+        peripherals::PWR::enable();
+
+        let pllsrcclk = self.config.hse.map(|hse| hse.0).unwrap_or(HSI);
+        let sysclk = self.config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk);
+        let sysclk_on_pll = sysclk != pllsrcclk;
 
         assert!((max::SYSCLK_MIN..=max::SYSCLK_MAX).contains(&sysclk));
 
         let plls = self.setup_pll(
-            base_clock,
+            pllsrcclk,
             self.config.hse.is_some(),
             if sysclk_on_pll { Some(sysclk) } else { None },
             self.config.pll48,
         );
 
         if self.config.pll48 {
-            assert!(
-                // USB specification allows +-0.25%
-                plls.pll48clk
-                    .map(|freq| (max::PLL_48_CLK as i32 - freq as i32).abs()
-                        <= max::PLL_48_TOLERANCE as i32)
-                    .unwrap_or(false)
-            );
+            let freq = unwrap!(plls.pll48clk);
+
+            assert!((max::PLL_48_CLK as i32 - freq as i32).abs() <= max::PLL_48_TOLERANCE as i32);
         }
 
         let sysclk = if sysclk_on_pll {
@@ -173,11 +172,7 @@ impl<'d> Rcc<'d> {
 
                 RCC.cr().modify(|w| w.set_pllon(true));
 
-                while !RCC.cr().read().pllrdy() {}
-
                 if hclk > max::HCLK_OVERDRIVE_FREQUENCY {
-                    peripherals::PWR::enable();
-
                     PWR.cr1().modify(|w| w.set_oden(true));
                     while !PWR.csr1().read().odrdy() {}
 
@@ -222,6 +217,8 @@ impl<'d> Rcc<'d> {
             ahb1: Hertz(hclk),
             ahb2: Hertz(hclk),
             ahb3: Hertz(hclk),
+
+            pll48: plls.pll48clk.map(Hertz),
         }
     }
 
@@ -362,6 +359,7 @@ mod max {
     pub(crate) const PCLK2_MIN: u32 = SYSCLK_MIN;
     pub(crate) const PCLK2_MAX: u32 = SYSCLK_MAX / 2;
 
+    // USB specification allows +-0.25%
     pub(crate) const PLL_48_CLK: u32 = 48_000_000;
     pub(crate) const PLL_48_TOLERANCE: u32 = 120_000;
 }
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs
index bf612464f..d0b6e5a18 100644
--- a/embassy-stm32/src/rcc/mod.rs
+++ b/embassy-stm32/src/rcc/mod.rs
@@ -61,7 +61,7 @@ pub struct Clocks {
     #[cfg(any(rcc_h7))]
     pub apb4: Hertz,
 
-    #[cfg(rcc_f4)]
+    #[cfg(any(rcc_f4, rcc_f7))]
     pub pll48: Option<Hertz>,
 
     #[cfg(rcc_f1)]
diff --git a/stm32-data b/stm32-data
index 27f9d6dc2..8530a19ff 160000
--- a/stm32-data
+++ b/stm32-data
@@ -1 +1 @@
-Subproject commit 27f9d6dc2c5afaa5003ce9afc06def9b16d30adb
+Subproject commit 8530a19ffdcdcbc608a97b40895827d09e670eb7

From 2eb0cc5df78b2abd38228ee1f07b7c446e17d362 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis <dirbaio@dirbaio.net>
Date: Tue, 4 Jan 2022 23:58:13 +0100
Subject: [PATCH 3/6] stm32/rcc: remove Rcc struct, RccExt trait.

All the RCC configuration is executed in init().
---
 embassy-stm32/src/lib.rs                |   2 -
 embassy-stm32/src/pwr/f3.rs             |   1 -
 embassy-stm32/src/pwr/f4.rs             |   1 -
 embassy-stm32/src/pwr/f7.rs             |   1 -
 embassy-stm32/src/pwr/g0.rs             |   1 -
 embassy-stm32/src/pwr/g4.rs             |   1 -
 embassy-stm32/src/pwr/h7.rs             |  78 ---
 embassy-stm32/src/pwr/l1.rs             |   1 -
 embassy-stm32/src/pwr/mod.rs            |  13 -
 embassy-stm32/src/pwr/u5.rs             |  32 -
 embassy-stm32/src/pwr/wb55.rs           |   0
 embassy-stm32/src/pwr/wl5.rs            |   1 -
 embassy-stm32/src/rcc/f0.rs             | 328 ++++-----
 embassy-stm32/src/rcc/f1.rs             | 349 +++++-----
 embassy-stm32/src/rcc/f3.rs             | 475 ++++++-------
 embassy-stm32/src/rcc/f4.rs             | 505 ++++++--------
 embassy-stm32/src/rcc/f7.rs             | 574 +++++++--------
 embassy-stm32/src/rcc/g0.rs             | 181 ++---
 embassy-stm32/src/rcc/g4.rs             | 187 ++---
 embassy-stm32/src/rcc/h7.rs             | 883 ++++++++++++------------
 embassy-stm32/src/rcc/l0.rs             | 449 +++++-------
 embassy-stm32/src/rcc/l1.rs             | 382 +++++-----
 embassy-stm32/src/rcc/l4.rs             | 482 ++++++-------
 embassy-stm32/src/rcc/u5.rs             | 414 ++++++-----
 embassy-stm32/src/rcc/wb.rs             | 176 ++---
 embassy-stm32/src/rcc/wl5.rs            | 219 +++---
 examples/stm32l0/src/bin/button_exti.rs |  14 +-
 examples/stm32l0/src/bin/lorawan.rs     |  12 +-
 examples/stm32wl55/src/bin/lorawan.rs   |  13 +-
 examples/stm32wl55/src/bin/subghz.rs    |   5 -
 stm32-data                              |   2 +-
 31 files changed, 2586 insertions(+), 3196 deletions(-)
 delete mode 100644 embassy-stm32/src/pwr/f3.rs
 delete mode 100644 embassy-stm32/src/pwr/f4.rs
 delete mode 100644 embassy-stm32/src/pwr/f7.rs
 delete mode 100644 embassy-stm32/src/pwr/g0.rs
 delete mode 100644 embassy-stm32/src/pwr/g4.rs
 delete mode 100644 embassy-stm32/src/pwr/h7.rs
 delete mode 100644 embassy-stm32/src/pwr/l1.rs
 delete mode 100644 embassy-stm32/src/pwr/mod.rs
 delete mode 100644 embassy-stm32/src/pwr/u5.rs
 delete mode 100644 embassy-stm32/src/pwr/wb55.rs
 delete mode 100644 embassy-stm32/src/pwr/wl5.rs

diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index c8a0e1705..117f3ed2a 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -43,8 +43,6 @@ pub mod i2c;
 #[cfg(crc)]
 pub mod crc;
 pub mod pwm;
-#[cfg(pwr)]
-pub mod pwr;
 #[cfg(rng)]
 pub mod rng;
 #[cfg(sdmmc)]
diff --git a/embassy-stm32/src/pwr/f3.rs b/embassy-stm32/src/pwr/f3.rs
deleted file mode 100644
index 8b1378917..000000000
--- a/embassy-stm32/src/pwr/f3.rs
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/embassy-stm32/src/pwr/f4.rs b/embassy-stm32/src/pwr/f4.rs
deleted file mode 100644
index 8b1378917..000000000
--- a/embassy-stm32/src/pwr/f4.rs
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/embassy-stm32/src/pwr/f7.rs b/embassy-stm32/src/pwr/f7.rs
deleted file mode 100644
index 8b1378917..000000000
--- a/embassy-stm32/src/pwr/f7.rs
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/embassy-stm32/src/pwr/g0.rs b/embassy-stm32/src/pwr/g0.rs
deleted file mode 100644
index 8b1378917..000000000
--- a/embassy-stm32/src/pwr/g0.rs
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/embassy-stm32/src/pwr/g4.rs b/embassy-stm32/src/pwr/g4.rs
deleted file mode 100644
index 8b1378917..000000000
--- a/embassy-stm32/src/pwr/g4.rs
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/embassy-stm32/src/pwr/h7.rs b/embassy-stm32/src/pwr/h7.rs
deleted file mode 100644
index 37b049a85..000000000
--- a/embassy-stm32/src/pwr/h7.rs
+++ /dev/null
@@ -1,78 +0,0 @@
-use crate::pac::{PWR, RCC, SYSCFG};
-use crate::peripherals;
-
-/// Voltage Scale
-///
-/// Represents the voltage range feeding the CPU core. The maximum core
-/// clock frequency depends on this value.
-#[derive(Copy, Clone, PartialEq)]
-pub enum VoltageScale {
-    /// VOS 0 range VCORE 1.26V - 1.40V
-    Scale0,
-    /// VOS 1 range VCORE 1.15V - 1.26V
-    Scale1,
-    /// VOS 2 range VCORE 1.05V - 1.15V
-    Scale2,
-    /// VOS 3 range VCORE 0.95V - 1.05V
-    Scale3,
-}
-
-/// Power Configuration
-///
-/// Generated when the PWR peripheral is frozen. The existence of this
-/// value indicates that the voltage scaling configuration can no
-/// longer be changed.
-pub struct Power {
-    pub(crate) vos: VoltageScale,
-}
-
-impl Power {
-    pub fn new(_peri: peripherals::PWR, enable_overdrive: bool) -> Self {
-        // NOTE(unsafe) we have the PWR singleton
-        unsafe {
-            // NB. The lower bytes of CR3 can only be written once after
-            // POR, and must be written with a valid combination. Refer to
-            // RM0433 Rev 7 6.8.4. This is partially enforced by dropping
-            // `self` at the end of this method, but of course we cannot
-            // know what happened between the previous POR and here.
-            #[cfg(pwr_h7)]
-            PWR.cr3().modify(|w| {
-                w.set_scuen(true);
-                w.set_ldoen(true);
-                w.set_bypass(false);
-            });
-
-            #[cfg(pwr_h7smps)]
-            PWR.cr3().modify(|w| {
-                // hardcode "Direct SPMS" for now, this is what works on nucleos with the
-                // default solderbridge configuration.
-                w.set_sden(true);
-                w.set_ldoen(false);
-            });
-
-            // Validate the supply configuration. If you are stuck here, it is
-            // because the voltages on your board do not match those specified
-            // in the D3CR.VOS and CR3.SDLEVEL fields. By default after reset
-            // VOS = Scale 3, so check that the voltage on the VCAP pins =
-            // 1.0V.
-            while !PWR.csr1().read().actvosrdy() {}
-
-            // Go to Scale 1
-            PWR.d3cr().modify(|w| w.set_vos(0b11));
-            while !PWR.d3cr().read().vosrdy() {}
-
-            let vos = if !enable_overdrive {
-                VoltageScale::Scale1
-            } else {
-                critical_section::with(|_| {
-                    RCC.apb4enr().modify(|w| w.set_syscfgen(true));
-
-                    SYSCFG.pwrcr().modify(|w| w.set_oden(1));
-                });
-                while !PWR.d3cr().read().vosrdy() {}
-                VoltageScale::Scale0
-            };
-            Self { vos }
-        }
-    }
-}
diff --git a/embassy-stm32/src/pwr/l1.rs b/embassy-stm32/src/pwr/l1.rs
deleted file mode 100644
index 8b1378917..000000000
--- a/embassy-stm32/src/pwr/l1.rs
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/embassy-stm32/src/pwr/mod.rs b/embassy-stm32/src/pwr/mod.rs
deleted file mode 100644
index d948c398d..000000000
--- a/embassy-stm32/src/pwr/mod.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-#[cfg_attr(any(pwr_h7, pwr_h7smps), path = "h7.rs")]
-#[cfg_attr(pwr_f3, path = "f3.rs")]
-#[cfg_attr(pwr_f4, path = "f4.rs")]
-#[cfg_attr(pwr_f7, path = "f7.rs")]
-#[cfg_attr(pwr_wl5, path = "wl5.rs")]
-#[cfg_attr(pwr_g0, path = "g0.rs")]
-#[cfg_attr(pwr_g4, path = "g4.rs")]
-#[cfg_attr(pwr_l1, path = "l1.rs")]
-#[cfg_attr(pwr_u5, path = "u5.rs")]
-#[cfg_attr(pwr_wb55, path = "wb55.rs")]
-mod _version;
-
-pub use _version::*;
diff --git a/embassy-stm32/src/pwr/u5.rs b/embassy-stm32/src/pwr/u5.rs
deleted file mode 100644
index a90659d9c..000000000
--- a/embassy-stm32/src/pwr/u5.rs
+++ /dev/null
@@ -1,32 +0,0 @@
-use crate::peripherals;
-
-/// Voltage Scale
-///
-/// Represents the voltage range feeding the CPU core. The maximum core
-/// clock frequency depends on this value.
-#[derive(Copy, Clone, PartialEq)]
-pub enum VoltageScale {
-    // Highest frequency
-    Range1,
-    Range2,
-    Range3,
-    // Lowest power
-    Range4,
-}
-
-/// Power Configuration
-///
-/// Generated when the PWR peripheral is frozen. The existence of this
-/// value indicates that the voltage scaling configuration can no
-/// longer be changed.
-pub struct Power {
-    pub(crate) vos: VoltageScale,
-}
-
-impl Power {
-    pub fn new(_peri: peripherals::PWR) -> Self {
-        Self {
-            vos: VoltageScale::Range4,
-        }
-    }
-}
diff --git a/embassy-stm32/src/pwr/wb55.rs b/embassy-stm32/src/pwr/wb55.rs
deleted file mode 100644
index e69de29bb..000000000
diff --git a/embassy-stm32/src/pwr/wl5.rs b/embassy-stm32/src/pwr/wl5.rs
deleted file mode 100644
index 8b1378917..000000000
--- a/embassy-stm32/src/pwr/wl5.rs
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/embassy-stm32/src/rcc/f0.rs b/embassy-stm32/src/rcc/f0.rs
index 07a28cc3e..1527afa05 100644
--- a/embassy-stm32/src/rcc/f0.rs
+++ b/embassy-stm32/src/rcc/f0.rs
@@ -1,9 +1,5 @@
-use core::marker::PhantomData;
-
-use embassy::util::Unborrow;
-
+use crate::pac::rcc::vals::{Hpre, Hsebyp, Pllmul, Pllsrc, Ppre, Sw, Usbsw};
 use crate::pac::{FLASH, RCC};
-use crate::peripherals;
 use crate::time::Hertz;
 
 use super::{set_freqs, Clocks};
@@ -28,181 +24,151 @@ pub struct Config {
     pub pclk: Option<Hertz>,
 }
 
-pub struct Rcc<'d> {
-    inner: PhantomData<&'d ()>,
-    config: Config,
-}
-
-impl<'d> Rcc<'d> {
-    pub fn new(_rcc: impl Unborrow<Target = peripherals::RCC> + 'd, config: Config) -> Self {
-        Self {
-            inner: PhantomData,
-            config,
-        }
-    }
-
-    pub fn freeze(self) -> Clocks {
-        use crate::pac::rcc::vals::{Hpre, Hsebyp, Pllmul, Pllsrc, Ppre, Sw, Usbsw};
-
-        let sysclk = self.config.sys_ck.map(|v| v.0).unwrap_or(HSI);
-
-        let (src_clk, use_hsi48) = self.config.hse.map(|v| (v.0, false)).unwrap_or_else(|| {
-            #[cfg(rcc_f0)]
-            if self.config.hsi48 {
-                return (48_000_000, true);
-            }
-            (HSI, false)
-        });
-
-        let (pllmul_bits, real_sysclk) = if sysclk == src_clk {
-            (None, sysclk)
-        } else {
-            let prediv = if self.config.hse.is_some() { 1 } else { 2 };
-            let pllmul = (2 * prediv * sysclk + src_clk) / src_clk / 2;
-            let pllmul = pllmul.max(2).min(16);
-
-            let pllmul_bits = pllmul as u8 - 2;
-            let real_sysclk = pllmul * src_clk / prediv;
-            (Some(pllmul_bits), real_sysclk)
-        };
-
-        let hpre_bits = self
-            .config
-            .hclk
-            .map(|hclk| match real_sysclk / hclk.0 {
-                0 => unreachable!(),
-                1 => 0b0111,
-                2 => 0b1000,
-                3..=5 => 0b1001,
-                6..=11 => 0b1010,
-                12..=39 => 0b1011,
-                40..=95 => 0b1100,
-                96..=191 => 0b1101,
-                192..=383 => 0b1110,
-                _ => 0b1111,
-            })
-            .unwrap_or(0b0111);
-        let hclk = real_sysclk / (1 << (hpre_bits - 0b0111));
-
-        let ppre_bits = self
-            .config
-            .pclk
-            .map(|pclk| match hclk / pclk.0 {
-                0 => unreachable!(),
-                1 => 0b011,
-                2 => 0b100,
-                3..=5 => 0b101,
-                6..=11 => 0b110,
-                _ => 0b111,
-            })
-            .unwrap_or(0b011);
-
-        let ppre: u8 = 1 << (ppre_bits - 0b011);
-        let pclk = hclk / u32::from(ppre);
-
-        let timer_mul = if ppre == 1 { 1 } else { 2 };
-
-        // NOTE(safety) Atomic write
-        unsafe {
-            FLASH.acr().write(|w| {
-                let latency = if real_sysclk <= 24_000_000 {
-                    0
-                } else if real_sysclk <= 48_000_000 {
-                    1
-                } else {
-                    2
-                };
-                w.latency().0 = latency;
-            });
-        }
-
-        // NOTE(unsafe) We have exclusive access to the RCC
-        unsafe {
-            match (self.config.hse.is_some(), use_hsi48) {
-                (true, _) => {
-                    RCC.cr().modify(|w| {
-                        w.set_csson(true);
-                        w.set_hseon(true);
-
-                        if self.config.bypass_hse {
-                            w.set_hsebyp(Hsebyp::BYPASSED);
-                        }
-                    });
-                    while !RCC.cr().read().hserdy() {}
-
-                    if pllmul_bits.is_some() {
-                        RCC.cfgr().modify(|w| w.set_pllsrc(Pllsrc::HSE_DIV_PREDIV))
-                    }
-                }
-                (false, true) => {
-                    // use_hsi48 will always be false for rcc_f0x0
-                    #[cfg(rcc_f0)]
-                    RCC.cr2().modify(|w| w.set_hsi48on(true));
-                    #[cfg(rcc_f0)]
-                    while !RCC.cr2().read().hsi48rdy() {}
-
-                    #[cfg(rcc_f0)]
-                    if pllmul_bits.is_some() {
-                        RCC.cfgr()
-                            .modify(|w| w.set_pllsrc(Pllsrc::HSI48_DIV_PREDIV))
-                    }
-                }
-                _ => {
-                    RCC.cr().modify(|w| w.set_hsion(true));
-                    while !RCC.cr().read().hsirdy() {}
-
-                    if pllmul_bits.is_some() {
-                        RCC.cfgr().modify(|w| w.set_pllsrc(Pllsrc::HSI_DIV2))
-                    }
-                }
-            }
-
-            if self.config.usb_pll {
-                RCC.cfgr3().modify(|w| w.set_usbsw(Usbsw::PLLCLK));
-            }
-            // TODO: Option to use CRS (Clock Recovery)
-
-            if let Some(pllmul_bits) = pllmul_bits {
-                RCC.cfgr().modify(|w| w.set_pllmul(Pllmul(pllmul_bits)));
-
-                RCC.cr().modify(|w| w.set_pllon(true));
-                while !RCC.cr().read().pllrdy() {}
-
-                RCC.cfgr().modify(|w| {
-                    w.set_ppre(Ppre(ppre_bits));
-                    w.set_hpre(Hpre(hpre_bits));
-                    w.set_sw(Sw::PLL)
-                });
-            } else {
-                RCC.cfgr().modify(|w| {
-                    w.set_ppre(Ppre(ppre_bits));
-                    w.set_hpre(Hpre(hpre_bits));
-
-                    if self.config.hse.is_some() {
-                        w.set_sw(Sw::HSE);
-                    } else if use_hsi48 {
-                        #[cfg(rcc_f0)]
-                        w.set_sw(Sw::HSI48);
-                    } else {
-                        w.set_sw(Sw::HSI)
-                    }
-                })
-            }
-        }
-
-        Clocks {
-            sys: Hertz(real_sysclk),
-            apb1: Hertz(pclk),
-            apb2: Hertz(pclk),
-            apb1_tim: Hertz(pclk * timer_mul),
-            apb2_tim: Hertz(pclk * timer_mul),
-            ahb: Hertz(hclk),
-        }
-    }
-}
-
 pub(crate) unsafe fn init(config: Config) {
-    let rcc = Rcc::new(<peripherals::RCC as embassy::util::Steal>::steal(), config);
-    let clocks = rcc.freeze();
-    set_freqs(clocks);
+    let sysclk = config.sys_ck.map(|v| v.0).unwrap_or(HSI);
+
+    let (src_clk, use_hsi48) = config.hse.map(|v| (v.0, false)).unwrap_or_else(|| {
+        #[cfg(rcc_f0)]
+        if config.hsi48 {
+            return (48_000_000, true);
+        }
+        (HSI, false)
+    });
+
+    let (pllmul_bits, real_sysclk) = if sysclk == src_clk {
+        (None, sysclk)
+    } else {
+        let prediv = if config.hse.is_some() { 1 } else { 2 };
+        let pllmul = (2 * prediv * sysclk + src_clk) / src_clk / 2;
+        let pllmul = pllmul.max(2).min(16);
+
+        let pllmul_bits = pllmul as u8 - 2;
+        let real_sysclk = pllmul * src_clk / prediv;
+        (Some(pllmul_bits), real_sysclk)
+    };
+
+    let hpre_bits = config
+        .hclk
+        .map(|hclk| match real_sysclk / hclk.0 {
+            0 => unreachable!(),
+            1 => 0b0111,
+            2 => 0b1000,
+            3..=5 => 0b1001,
+            6..=11 => 0b1010,
+            12..=39 => 0b1011,
+            40..=95 => 0b1100,
+            96..=191 => 0b1101,
+            192..=383 => 0b1110,
+            _ => 0b1111,
+        })
+        .unwrap_or(0b0111);
+    let hclk = real_sysclk / (1 << (hpre_bits - 0b0111));
+
+    let ppre_bits = config
+        .pclk
+        .map(|pclk| match hclk / pclk.0 {
+            0 => unreachable!(),
+            1 => 0b011,
+            2 => 0b100,
+            3..=5 => 0b101,
+            6..=11 => 0b110,
+            _ => 0b111,
+        })
+        .unwrap_or(0b011);
+
+    let ppre: u8 = 1 << (ppre_bits - 0b011);
+    let pclk = hclk / u32::from(ppre);
+
+    let timer_mul = if ppre == 1 { 1 } else { 2 };
+
+    FLASH.acr().write(|w| {
+        let latency = if real_sysclk <= 24_000_000 {
+            0
+        } else if real_sysclk <= 48_000_000 {
+            1
+        } else {
+            2
+        };
+        w.latency().0 = latency;
+    });
+
+    match (config.hse.is_some(), use_hsi48) {
+        (true, _) => {
+            RCC.cr().modify(|w| {
+                w.set_csson(true);
+                w.set_hseon(true);
+
+                if config.bypass_hse {
+                    w.set_hsebyp(Hsebyp::BYPASSED);
+                }
+            });
+            while !RCC.cr().read().hserdy() {}
+
+            if pllmul_bits.is_some() {
+                RCC.cfgr().modify(|w| w.set_pllsrc(Pllsrc::HSE_DIV_PREDIV))
+            }
+        }
+        (false, true) => {
+            // use_hsi48 will always be false for rcc_f0x0
+            #[cfg(rcc_f0)]
+            RCC.cr2().modify(|w| w.set_hsi48on(true));
+            #[cfg(rcc_f0)]
+            while !RCC.cr2().read().hsi48rdy() {}
+
+            #[cfg(rcc_f0)]
+            if pllmul_bits.is_some() {
+                RCC.cfgr()
+                    .modify(|w| w.set_pllsrc(Pllsrc::HSI48_DIV_PREDIV))
+            }
+        }
+        _ => {
+            RCC.cr().modify(|w| w.set_hsion(true));
+            while !RCC.cr().read().hsirdy() {}
+
+            if pllmul_bits.is_some() {
+                RCC.cfgr().modify(|w| w.set_pllsrc(Pllsrc::HSI_DIV2))
+            }
+        }
+    }
+
+    if config.usb_pll {
+        RCC.cfgr3().modify(|w| w.set_usbsw(Usbsw::PLLCLK));
+    }
+    // TODO: Option to use CRS (Clock Recovery)
+
+    if let Some(pllmul_bits) = pllmul_bits {
+        RCC.cfgr().modify(|w| w.set_pllmul(Pllmul(pllmul_bits)));
+
+        RCC.cr().modify(|w| w.set_pllon(true));
+        while !RCC.cr().read().pllrdy() {}
+
+        RCC.cfgr().modify(|w| {
+            w.set_ppre(Ppre(ppre_bits));
+            w.set_hpre(Hpre(hpre_bits));
+            w.set_sw(Sw::PLL)
+        });
+    } else {
+        RCC.cfgr().modify(|w| {
+            w.set_ppre(Ppre(ppre_bits));
+            w.set_hpre(Hpre(hpre_bits));
+
+            if config.hse.is_some() {
+                w.set_sw(Sw::HSE);
+            } else if use_hsi48 {
+                #[cfg(rcc_f0)]
+                w.set_sw(Sw::HSI48);
+            } else {
+                w.set_sw(Sw::HSI)
+            }
+        })
+    }
+
+    set_freqs(Clocks {
+        sys: Hertz(real_sysclk),
+        apb1: Hertz(pclk),
+        apb2: Hertz(pclk),
+        apb1_tim: Hertz(pclk * timer_mul),
+        apb2_tim: Hertz(pclk * timer_mul),
+        ahb: Hertz(hclk),
+    });
 }
diff --git a/embassy-stm32/src/rcc/f1.rs b/embassy-stm32/src/rcc/f1.rs
index c9d09ee33..d44544d28 100644
--- a/embassy-stm32/src/rcc/f1.rs
+++ b/embassy-stm32/src/rcc/f1.rs
@@ -1,14 +1,10 @@
 use core::convert::TryFrom;
-use core::marker::PhantomData;
-
-use embassy::util::Unborrow;
-
-use crate::pac::flash::vals::Latency;
-use crate::pac::{FLASH, RCC};
-use crate::peripherals;
-use crate::time::Hertz;
 
 use super::{set_freqs, Clocks};
+use crate::pac::flash::vals::Latency;
+use crate::pac::rcc::vals::{Adcpre, Hpre, Pllmul, Pllsrc, Ppre1, Sw, Usbpre};
+use crate::pac::{FLASH, RCC};
+use crate::time::Hertz;
 
 const HSI: u32 = 8_000_000;
 
@@ -26,189 +22,158 @@ pub struct Config {
     pub adcclk: Option<Hertz>,
 }
 
-pub struct Rcc<'d> {
-    inner: PhantomData<&'d ()>,
-    config: Config,
-}
-
-impl<'d> Rcc<'d> {
-    pub fn new(_rcc: impl Unborrow<Target = peripherals::RCC> + 'd, config: Config) -> Self {
-        Self {
-            inner: PhantomData,
-            config,
-        }
-    }
-
-    pub fn freeze(self) -> Clocks {
-        use crate::pac::rcc::vals::{Adcpre, Hpre, Pllmul, Pllsrc, Ppre1, Sw, Usbpre};
-
-        let pllsrcclk = self.config.hse.map(|hse| hse.0).unwrap_or(HSI / 2);
-        let sysclk = self.config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk);
-        let pllmul = sysclk / pllsrcclk;
-
-        let (pllmul_bits, real_sysclk) = if pllmul == 1 {
-            (None, self.config.hse.map(|hse| hse.0).unwrap_or(HSI))
-        } else {
-            let pllmul = core::cmp::min(core::cmp::max(pllmul, 1), 16);
-            (Some(pllmul as u8 - 2), pllsrcclk * pllmul)
-        };
-
-        assert!(real_sysclk <= 72_000_000);
-
-        let hpre_bits = self
-            .config
-            .hclk
-            .map(|hclk| match real_sysclk / hclk.0 {
-                0 => unreachable!(),
-                1 => 0b0111,
-                2 => 0b1000,
-                3..=5 => 0b1001,
-                6..=11 => 0b1010,
-                12..=39 => 0b1011,
-                40..=95 => 0b1100,
-                96..=191 => 0b1101,
-                192..=383 => 0b1110,
-                _ => 0b1111,
-            })
-            .unwrap_or(0b0111);
-
-        let hclk = if hpre_bits >= 0b1100 {
-            real_sysclk / (1 << (hpre_bits - 0b0110))
-        } else {
-            real_sysclk / (1 << (hpre_bits - 0b0111))
-        };
-
-        assert!(hclk <= 72_000_000);
-
-        let ppre1_bits = self
-            .config
-            .pclk1
-            .map(|pclk1| match hclk / pclk1.0 {
-                0 => unreachable!(),
-                1 => 0b011,
-                2 => 0b100,
-                3..=5 => 0b101,
-                6..=11 => 0b110,
-                _ => 0b111,
-            })
-            .unwrap_or(0b011);
-
-        let ppre1 = 1 << (ppre1_bits - 0b011);
-        let pclk1 = hclk / u32::try_from(ppre1).unwrap();
-        let timer_mul1 = if ppre1 == 1 { 1 } else { 2 };
-
-        assert!(pclk1 <= 36_000_000);
-
-        let ppre2_bits = self
-            .config
-            .pclk2
-            .map(|pclk2| match hclk / pclk2.0 {
-                0 => unreachable!(),
-                1 => 0b011,
-                2 => 0b100,
-                3..=5 => 0b101,
-                6..=11 => 0b110,
-                _ => 0b111,
-            })
-            .unwrap_or(0b011);
-
-        let ppre2 = 1 << (ppre2_bits - 0b011);
-        let pclk2 = hclk / u32::try_from(ppre2).unwrap();
-        let timer_mul2 = if ppre2 == 1 { 1 } else { 2 };
-
-        assert!(pclk2 <= 72_000_000);
-
-        // Only needed for stm32f103?
-        // NOTE(safety) Atomic write
-        unsafe {
-            FLASH.acr().write(|w| {
-                w.set_latency(if real_sysclk <= 24_000_000 {
-                    Latency(0b000)
-                } else if real_sysclk <= 48_000_000 {
-                    Latency(0b001)
-                } else {
-                    Latency(0b010)
-                });
-            })
-        }
-
-        // the USB clock is only valid if an external crystal is used, the PLL is enabled, and the
-        // PLL output frequency is a supported one.
-        // usbpre == false: divide clock by 1.5, otherwise no division
-        let (usbpre, _usbclk_valid) = match (self.config.hse, pllmul_bits, real_sysclk) {
-            (Some(_), Some(_), 72_000_000) => (false, true),
-            (Some(_), Some(_), 48_000_000) => (true, true),
-            _ => (true, false),
-        };
-
-        let apre_bits: u8 = self
-            .config
-            .adcclk
-            .map(|adcclk| match pclk2 / adcclk.0 {
-                0..=2 => 0b00,
-                3..=4 => 0b01,
-                5..=7 => 0b10,
-                _ => 0b11,
-            })
-            .unwrap_or(0b11);
-
-        let apre = (apre_bits + 1) << 1;
-        let adcclk = pclk2 / unwrap!(u32::try_from(apre));
-
-        assert!(adcclk <= 14_000_000);
-
-        unsafe {
-            if self.config.hse.is_some() {
-                // enable HSE and wait for it to be ready
-                RCC.cr().modify(|w| w.set_hseon(true));
-                while !RCC.cr().read().hserdy() {}
-            }
-
-            if let Some(pllmul_bits) = pllmul_bits {
-                // enable PLL and wait for it to be ready
-                RCC.cfgr().modify(|w| {
-                    w.set_pllmul(Pllmul(pllmul_bits));
-                    w.set_pllsrc(Pllsrc(self.config.hse.is_some() as u8));
-                });
-
-                RCC.cr().modify(|w| w.set_pllon(true));
-                while !RCC.cr().read().pllrdy() {}
-            }
-
-            // Only needed for stm32f103?
-            RCC.cfgr().modify(|w| {
-                w.set_adcpre(Adcpre(apre_bits));
-                w.set_ppre2(Ppre1(ppre2_bits));
-                w.set_ppre1(Ppre1(ppre1_bits));
-                w.set_hpre(Hpre(hpre_bits));
-                w.set_usbpre(Usbpre(usbpre as u8));
-                w.set_sw(Sw(if pllmul_bits.is_some() {
-                    // PLL
-                    0b10
-                } else if self.config.hse.is_some() {
-                    // HSE
-                    0b1
-                } else {
-                    // HSI
-                    0b0
-                }));
-            });
-        }
-
-        Clocks {
-            sys: Hertz(real_sysclk),
-            apb1: Hertz(pclk1),
-            apb2: Hertz(pclk2),
-            apb1_tim: Hertz(pclk1 * timer_mul1),
-            apb2_tim: Hertz(pclk2 * timer_mul2),
-            ahb: Hertz(hclk),
-            adc: Hertz(adcclk),
-        }
-    }
-}
-
 pub(crate) unsafe fn init(config: Config) {
-    let rcc = Rcc::new(<peripherals::RCC as embassy::util::Steal>::steal(), config);
-    let clocks = rcc.freeze();
-    set_freqs(clocks);
+    let pllsrcclk = config.hse.map(|hse| hse.0).unwrap_or(HSI / 2);
+    let sysclk = config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk);
+    let pllmul = sysclk / pllsrcclk;
+
+    let (pllmul_bits, real_sysclk) = if pllmul == 1 {
+        (None, config.hse.map(|hse| hse.0).unwrap_or(HSI))
+    } else {
+        let pllmul = core::cmp::min(core::cmp::max(pllmul, 1), 16);
+        (Some(pllmul as u8 - 2), pllsrcclk * pllmul)
+    };
+
+    assert!(real_sysclk <= 72_000_000);
+
+    let hpre_bits = config
+        .hclk
+        .map(|hclk| match real_sysclk / hclk.0 {
+            0 => unreachable!(),
+            1 => 0b0111,
+            2 => 0b1000,
+            3..=5 => 0b1001,
+            6..=11 => 0b1010,
+            12..=39 => 0b1011,
+            40..=95 => 0b1100,
+            96..=191 => 0b1101,
+            192..=383 => 0b1110,
+            _ => 0b1111,
+        })
+        .unwrap_or(0b0111);
+
+    let hclk = if hpre_bits >= 0b1100 {
+        real_sysclk / (1 << (hpre_bits - 0b0110))
+    } else {
+        real_sysclk / (1 << (hpre_bits - 0b0111))
+    };
+
+    assert!(hclk <= 72_000_000);
+
+    let ppre1_bits = config
+        .pclk1
+        .map(|pclk1| match hclk / pclk1.0 {
+            0 => unreachable!(),
+            1 => 0b011,
+            2 => 0b100,
+            3..=5 => 0b101,
+            6..=11 => 0b110,
+            _ => 0b111,
+        })
+        .unwrap_or(0b011);
+
+    let ppre1 = 1 << (ppre1_bits - 0b011);
+    let pclk1 = hclk / u32::try_from(ppre1).unwrap();
+    let timer_mul1 = if ppre1 == 1 { 1 } else { 2 };
+
+    assert!(pclk1 <= 36_000_000);
+
+    let ppre2_bits = config
+        .pclk2
+        .map(|pclk2| match hclk / pclk2.0 {
+            0 => unreachable!(),
+            1 => 0b011,
+            2 => 0b100,
+            3..=5 => 0b101,
+            6..=11 => 0b110,
+            _ => 0b111,
+        })
+        .unwrap_or(0b011);
+
+    let ppre2 = 1 << (ppre2_bits - 0b011);
+    let pclk2 = hclk / u32::try_from(ppre2).unwrap();
+    let timer_mul2 = if ppre2 == 1 { 1 } else { 2 };
+
+    assert!(pclk2 <= 72_000_000);
+
+    // Only needed for stm32f103?
+    FLASH.acr().write(|w| {
+        w.set_latency(if real_sysclk <= 24_000_000 {
+            Latency(0b000)
+        } else if real_sysclk <= 48_000_000 {
+            Latency(0b001)
+        } else {
+            Latency(0b010)
+        });
+    });
+
+    // the USB clock is only valid if an external crystal is used, the PLL is enabled, and the
+    // PLL output frequency is a supported one.
+    // usbpre == false: divide clock by 1.5, otherwise no division
+    let (usbpre, _usbclk_valid) = match (config.hse, pllmul_bits, real_sysclk) {
+        (Some(_), Some(_), 72_000_000) => (false, true),
+        (Some(_), Some(_), 48_000_000) => (true, true),
+        _ => (true, false),
+    };
+
+    let apre_bits: u8 = config
+        .adcclk
+        .map(|adcclk| match pclk2 / adcclk.0 {
+            0..=2 => 0b00,
+            3..=4 => 0b01,
+            5..=7 => 0b10,
+            _ => 0b11,
+        })
+        .unwrap_or(0b11);
+
+    let apre = (apre_bits + 1) << 1;
+    let adcclk = pclk2 / unwrap!(u32::try_from(apre));
+
+    assert!(adcclk <= 14_000_000);
+
+    if config.hse.is_some() {
+        // enable HSE and wait for it to be ready
+        RCC.cr().modify(|w| w.set_hseon(true));
+        while !RCC.cr().read().hserdy() {}
+    }
+
+    if let Some(pllmul_bits) = pllmul_bits {
+        // enable PLL and wait for it to be ready
+        RCC.cfgr().modify(|w| {
+            w.set_pllmul(Pllmul(pllmul_bits));
+            w.set_pllsrc(Pllsrc(config.hse.is_some() as u8));
+        });
+
+        RCC.cr().modify(|w| w.set_pllon(true));
+        while !RCC.cr().read().pllrdy() {}
+    }
+
+    // Only needed for stm32f103?
+    RCC.cfgr().modify(|w| {
+        w.set_adcpre(Adcpre(apre_bits));
+        w.set_ppre2(Ppre1(ppre2_bits));
+        w.set_ppre1(Ppre1(ppre1_bits));
+        w.set_hpre(Hpre(hpre_bits));
+        w.set_usbpre(Usbpre(usbpre as u8));
+        w.set_sw(Sw(if pllmul_bits.is_some() {
+            // PLL
+            0b10
+        } else if config.hse.is_some() {
+            // HSE
+            0b1
+        } else {
+            // HSI
+            0b0
+        }));
+    });
+
+    set_freqs(Clocks {
+        sys: Hertz(real_sysclk),
+        apb1: Hertz(pclk1),
+        apb2: Hertz(pclk2),
+        apb1_tim: Hertz(pclk1 * timer_mul1),
+        apb2_tim: Hertz(pclk2 * timer_mul2),
+        ahb: Hertz(hclk),
+        adc: Hertz(adcclk),
+    });
 }
diff --git a/embassy-stm32/src/rcc/f3.rs b/embassy-stm32/src/rcc/f3.rs
index 7b5e0cce7..e16e1e499 100644
--- a/embassy-stm32/src/rcc/f3.rs
+++ b/embassy-stm32/src/rcc/f3.rs
@@ -1,23 +1,11 @@
-use core::marker::PhantomData;
-use embassy::util::Unborrow;
-
-use crate::pac::{
-    flash::vals::Latency,
-    rcc::vals::{Hpre, Hsebyp, Pllmul, Pllsrc, Ppre, Prediv, Sw, Usbpre},
-    FLASH, RCC,
-};
-use crate::peripherals;
+use crate::pac::flash::vals::Latency;
+use crate::pac::rcc::vals::{Hpre, Hsebyp, Pllmul, Pllsrc, Ppre, Prediv, Sw, Usbpre};
+use crate::pac::{FLASH, RCC};
 use crate::rcc::{set_freqs, Clocks};
 use crate::time::Hertz;
 
 const HSI: u32 = 8_000_000;
 
-/// RCC peripheral
-pub struct Rcc<'d> {
-    config: Config,
-    phantom: PhantomData<&'d mut peripherals::RCC>,
-}
-
 /// Clocks configutation
 #[non_exhaustive]
 #[derive(Default)]
@@ -55,259 +43,228 @@ struct PllConfig {
 
 /// Initialize and Set the clock frequencies
 pub(crate) unsafe fn init(config: Config) {
-    let r = <peripherals::RCC as embassy::util::Steal>::steal();
-    let clocks = Rcc::new(r, config).freeze();
-    set_freqs(clocks);
+    // Calculate the real System clock, and PLL configuration if applicable
+    let (Hertz(sysclk), pll_config) = get_sysclk(&config);
+    assert!(sysclk <= 72_000_000);
+
+    // Calculate real AHB clock
+    let hclk = config.hclk.map(|h| h.0).unwrap_or(sysclk);
+    let (hpre_bits, hpre_div) = match sysclk / hclk {
+        0 => unreachable!(),
+        1 => (Hpre::DIV1, 1),
+        2 => (Hpre::DIV2, 2),
+        3..=5 => (Hpre::DIV4, 4),
+        6..=11 => (Hpre::DIV8, 8),
+        12..=39 => (Hpre::DIV16, 16),
+        40..=95 => (Hpre::DIV64, 64),
+        96..=191 => (Hpre::DIV128, 128),
+        192..=383 => (Hpre::DIV256, 256),
+        _ => (Hpre::DIV512, 512),
+    };
+    let hclk = sysclk / hpre_div;
+    assert!(hclk <= 72_000_000);
+
+    // Calculate real APB1 clock
+    let pclk1 = config.pclk1.map(|p| p.0).unwrap_or(hclk);
+    let (ppre1_bits, ppre1) = match hclk / pclk1 {
+        0 => unreachable!(),
+        1 => (Ppre::DIV1, 1),
+        2 => (Ppre::DIV2, 2),
+        3..=5 => (Ppre::DIV4, 4),
+        6..=11 => (Ppre::DIV8, 8),
+        _ => (Ppre::DIV16, 16),
+    };
+    let timer_mul1 = if ppre1 == 1 { 1 } else { 2 };
+    let pclk1 = hclk / ppre1;
+    assert!(pclk1 <= 36_000_000);
+
+    // Calculate real APB2 clock
+    let pclk2 = config.pclk2.map(|p| p.0).unwrap_or(hclk);
+    let (ppre2_bits, ppre2) = match hclk / pclk2 {
+        0 => unreachable!(),
+        1 => (Ppre::DIV1, 1),
+        2 => (Ppre::DIV2, 2),
+        3..=5 => (Ppre::DIV4, 4),
+        6..=11 => (Ppre::DIV8, 8),
+        _ => (Ppre::DIV16, 16),
+    };
+    let timer_mul2 = if ppre2 == 1 { 1 } else { 2 };
+    let pclk2 = hclk / ppre2;
+    assert!(pclk2 <= 72_000_000);
+
+    // Set latency based on HCLK frquency
+    FLASH.acr().write(|w| {
+        w.set_latency(if hclk <= 24_000_000 {
+            Latency::WS0
+        } else if hclk <= 48_000_000 {
+            Latency::WS1
+        } else {
+            Latency::WS2
+        });
+    });
+
+    // Enable HSE
+    if config.hse.is_some() {
+        RCC.cr().write(|w| {
+            w.set_hsebyp(if config.bypass_hse {
+                Hsebyp::BYPASSED
+            } else {
+                Hsebyp::NOTBYPASSED
+            });
+            // We turn on clock security to switch to HSI when HSE fails
+            w.set_csson(true);
+            w.set_hseon(true);
+        });
+        while !RCC.cr().read().hserdy() {}
+    }
+
+    // Enable PLL
+    if let Some(ref pll_config) = pll_config {
+        RCC.cfgr().write(|w| {
+            w.set_pllmul(pll_config.pll_mul);
+            w.set_pllsrc(pll_config.pll_src);
+        });
+        if let Some(pll_div) = pll_config.pll_div {
+            RCC.cfgr2().write(|w| w.set_prediv(pll_div));
+        }
+        RCC.cr().modify(|w| w.set_pllon(true));
+        while !RCC.cr().read().pllrdy() {}
+    }
+
+    if config.pll48 {
+        let usb_pre = get_usb_pre(&config, sysclk, pclk1, &pll_config);
+        RCC.cfgr().write(|w| {
+            w.set_usbpre(usb_pre);
+        });
+    }
+
+    // Set prescalers
+    RCC.cfgr().write(|w| {
+        w.set_ppre2(ppre2_bits);
+        w.set_ppre1(ppre1_bits);
+        w.set_hpre(hpre_bits);
+    });
+
+    // Wait for the new prescalers to kick in
+    // "The clocks are divided with the new prescaler factor from
+    //  1 to 16 AHB cycles after write"
+    cortex_m::asm::delay(16);
+
+    RCC.cfgr().write(|w| {
+        w.set_sw(match (pll_config, config.hse) {
+            (Some(_), _) => Sw::PLL,
+            (None, Some(_)) => Sw::HSE,
+            (None, None) => Sw::HSI,
+        })
+    });
+
+    set_freqs(Clocks {
+        sys: Hertz(sysclk),
+        apb1: Hertz(pclk1),
+        apb2: Hertz(pclk2),
+        apb1_tim: Hertz(pclk1 * timer_mul1),
+        apb2_tim: Hertz(pclk2 * timer_mul2),
+        ahb: Hertz(hclk),
+    });
 }
 
-impl<'d> Rcc<'d> {
-    pub fn new(_rcc: impl Unborrow<Target = peripherals::RCC> + 'd, config: Config) -> Self {
-        Self {
-            config,
-            phantom: PhantomData,
+#[inline]
+fn get_sysclk(config: &Config) -> (Hertz, Option<PllConfig>) {
+    match (config.sysclk, config.hse) {
+        (Some(sysclk), Some(hse)) if sysclk == hse => (hse, None),
+        (Some(sysclk), None) if sysclk.0 == HSI => (Hertz(HSI), None),
+        // If the user selected System clock is different from HSI or HSE
+        // we will have to setup PLL clock source
+        (Some(sysclk), _) => {
+            let (sysclk, pll_config) = calc_pll(config, sysclk);
+            (sysclk, Some(pll_config))
         }
+        (None, Some(hse)) => (hse, None),
+        (None, None) => (Hertz(HSI), None),
     }
+}
 
-    fn freeze(self) -> Clocks {
-        // Calculate the real System clock, and PLL configuration if applicable
-        let (Hertz(sysclk), pll_config) = self.get_sysclk();
-        assert!(sysclk <= 72_000_000);
-
-        // Calculate real AHB clock
-        let hclk = self.config.hclk.map(|h| h.0).unwrap_or(sysclk);
-        let (hpre_bits, hpre_div) = match sysclk / hclk {
-            0 => unreachable!(),
-            1 => (Hpre::DIV1, 1),
-            2 => (Hpre::DIV2, 2),
-            3..=5 => (Hpre::DIV4, 4),
-            6..=11 => (Hpre::DIV8, 8),
-            12..=39 => (Hpre::DIV16, 16),
-            40..=95 => (Hpre::DIV64, 64),
-            96..=191 => (Hpre::DIV128, 128),
-            192..=383 => (Hpre::DIV256, 256),
-            _ => (Hpre::DIV512, 512),
-        };
-        let hclk = sysclk / hpre_div;
-        assert!(hclk <= 72_000_000);
-
-        // Calculate real APB1 clock
-        let pclk1 = self.config.pclk1.map(|p| p.0).unwrap_or(hclk);
-        let (ppre1_bits, ppre1) = match hclk / pclk1 {
-            0 => unreachable!(),
-            1 => (Ppre::DIV1, 1),
-            2 => (Ppre::DIV2, 2),
-            3..=5 => (Ppre::DIV4, 4),
-            6..=11 => (Ppre::DIV8, 8),
-            _ => (Ppre::DIV16, 16),
-        };
-        let timer_mul1 = if ppre1 == 1 { 1 } else { 2 };
-        let pclk1 = hclk / ppre1;
-        assert!(pclk1 <= 36_000_000);
-
-        // Calculate real APB2 clock
-        let pclk2 = self.config.pclk2.map(|p| p.0).unwrap_or(hclk);
-        let (ppre2_bits, ppre2) = match hclk / pclk2 {
-            0 => unreachable!(),
-            1 => (Ppre::DIV1, 1),
-            2 => (Ppre::DIV2, 2),
-            3..=5 => (Ppre::DIV4, 4),
-            6..=11 => (Ppre::DIV8, 8),
-            _ => (Ppre::DIV16, 16),
-        };
-        let timer_mul2 = if ppre2 == 1 { 1 } else { 2 };
-        let pclk2 = hclk / ppre2;
-        assert!(pclk2 <= 72_000_000);
-
-        // Set latency based on HCLK frquency
-        // NOTE(safety) Atomic write
-        unsafe {
-            FLASH.acr().write(|w| {
-                w.set_latency(if hclk <= 24_000_000 {
-                    Latency::WS0
-                } else if hclk <= 48_000_000 {
-                    Latency::WS1
+#[inline]
+fn calc_pll(config: &Config, Hertz(sysclk): Hertz) -> (Hertz, PllConfig) {
+    // Calculates the Multiplier and the Divisor to arrive at
+    // the required System clock from PLL source frequency
+    let get_mul_div = |sysclk, pllsrcclk| {
+        let common_div = gcd(sysclk, pllsrcclk);
+        let mut multiplier = sysclk / common_div;
+        let mut divisor = pllsrcclk / common_div;
+        // Minimum PLL multiplier is two
+        if multiplier == 1 {
+            multiplier *= 2;
+            divisor *= 2;
+        }
+        assert!(multiplier <= 16);
+        assert!(divisor <= 16);
+        (multiplier, divisor)
+    };
+    // Based on the source of Pll, we calculate the actual system clock
+    // frequency, PLL's source identifier, multiplier and divisor
+    let (act_sysclk, pll_src, pll_mul, pll_div) = match config.hse {
+        Some(Hertz(hse)) => {
+            let (multiplier, divisor) = get_mul_div(sysclk, hse);
+            (
+                Hertz((hse / divisor) * multiplier),
+                Pllsrc::HSE_DIV_PREDIV,
+                into_pll_mul(multiplier),
+                Some(into_pre_div(divisor)),
+            )
+        }
+        None => {
+            cfg_if::cfg_if! {
+                // For some chips PREDIV is always two, and cannot be changed
+                if #[cfg(any(
+                        feature="stm32f302xd", feature="stm32f302xe", feature="stm32f303xd",
+                        feature="stm32f303xe", feature="stm32f398xe"
+                    ))] {
+                    let (multiplier, divisor) = get_mul_div(sysclk, HSI);
+                    (
+                        Hertz((hse / divisor) * multiplier),
+                        Pllsrc::HSI_DIV_PREDIV,
+                        into_pll_mul(multiplier),
+                        Some(into_pre_div(divisor)),
+                    )
                 } else {
-                    Latency::WS2
-                });
-            })
-        }
-
-        // Enable HSE
-        if self.config.hse.is_some() {
-            // NOTE(unsafe) We own the peripheral block
-            unsafe {
-                RCC.cr().write(|w| {
-                    w.set_hsebyp(if self.config.bypass_hse {
-                        Hsebyp::BYPASSED
-                    } else {
-                        Hsebyp::NOTBYPASSED
-                    });
-                    // We turn on clock security to switch to HSI when HSE fails
-                    w.set_csson(true);
-                    w.set_hseon(true);
-                });
-                while !RCC.cr().read().hserdy() {}
-            }
-        }
-
-        // Enable PLL
-        if let Some(ref pll_config) = pll_config {
-            // NOTE(unsafe) We own the peripheral block
-            unsafe {
-                RCC.cfgr().write(|w| {
-                    w.set_pllmul(pll_config.pll_mul);
-                    w.set_pllsrc(pll_config.pll_src);
-                });
-                if let Some(pll_div) = pll_config.pll_div {
-                    RCC.cfgr2().write(|w| w.set_prediv(pll_div));
-                }
-                RCC.cr().modify(|w| w.set_pllon(true));
-                while !RCC.cr().read().pllrdy() {}
-            }
-        }
-
-        if self.config.pll48 {
-            let usb_pre = self.get_usb_pre(sysclk, pclk1, &pll_config);
-            // NOTE(unsafe) We own the peripheral block
-            unsafe {
-                RCC.cfgr().write(|w| {
-                    w.set_usbpre(usb_pre);
-                });
-            }
-        }
-
-        // Set prescalers
-        unsafe {
-            // NOTE(unsafe) We own the peripheral block
-            RCC.cfgr().write(|w| {
-                w.set_ppre2(ppre2_bits);
-                w.set_ppre1(ppre1_bits);
-                w.set_hpre(hpre_bits);
-            });
-
-            // Wait for the new prescalers to kick in
-            // "The clocks are divided with the new prescaler factor from
-            //  1 to 16 AHB cycles after write"
-            cortex_m::asm::delay(16);
-
-            // NOTE(unsafe) We own the peripheral block
-            RCC.cfgr().write(|w| {
-                w.set_sw(match (pll_config, self.config.hse) {
-                    (Some(_), _) => Sw::PLL,
-                    (None, Some(_)) => Sw::HSE,
-                    (None, None) => Sw::HSI,
-                })
-            });
-        }
-
-        Clocks {
-            sys: Hertz(sysclk),
-            apb1: Hertz(pclk1),
-            apb2: Hertz(pclk2),
-            apb1_tim: Hertz(pclk1 * timer_mul1),
-            apb2_tim: Hertz(pclk2 * timer_mul2),
-            ahb: Hertz(hclk),
-        }
-    }
-
-    #[inline]
-    fn get_sysclk(&self) -> (Hertz, Option<PllConfig>) {
-        match (self.config.sysclk, self.config.hse) {
-            (Some(sysclk), Some(hse)) if sysclk == hse => (hse, None),
-            (Some(sysclk), None) if sysclk.0 == HSI => (Hertz(HSI), None),
-            // If the user selected System clock is different from HSI or HSE
-            // we will have to setup PLL clock source
-            (Some(sysclk), _) => {
-                let (sysclk, pll_config) = self.calc_pll(sysclk);
-                (sysclk, Some(pll_config))
-            }
-            (None, Some(hse)) => (hse, None),
-            (None, None) => (Hertz(HSI), None),
-        }
-    }
-
-    #[inline]
-    fn calc_pll(&self, Hertz(sysclk): Hertz) -> (Hertz, PllConfig) {
-        // Calculates the Multiplier and the Divisor to arrive at
-        // the required System clock from PLL source frequency
-        let get_mul_div = |sysclk, pllsrcclk| {
-            let common_div = gcd(sysclk, pllsrcclk);
-            let mut multiplier = sysclk / common_div;
-            let mut divisor = pllsrcclk / common_div;
-            // Minimum PLL multiplier is two
-            if multiplier == 1 {
-                multiplier *= 2;
-                divisor *= 2;
-            }
-            assert!(multiplier <= 16);
-            assert!(divisor <= 16);
-            (multiplier, divisor)
-        };
-        // Based on the source of Pll, we calculate the actual system clock
-        // frequency, PLL's source identifier, multiplier and divisor
-        let (act_sysclk, pll_src, pll_mul, pll_div) = match self.config.hse {
-            Some(Hertz(hse)) => {
-                let (multiplier, divisor) = get_mul_div(sysclk, hse);
-                (
-                    Hertz((hse / divisor) * multiplier),
-                    Pllsrc::HSE_DIV_PREDIV,
-                    into_pll_mul(multiplier),
-                    Some(into_pre_div(divisor)),
-                )
-            }
-            None => {
-                cfg_if::cfg_if! {
-                    // For some chips PREDIV is always two, and cannot be changed
-                    if #[cfg(any(
-                            feature="stm32f302xd", feature="stm32f302xe", feature="stm32f303xd",
-                            feature="stm32f303xe", feature="stm32f398xe"
-                        ))] {
-                        let (multiplier, divisor) = get_mul_div(sysclk, HSI);
-                        (
-                            Hertz((hse / divisor) * multiplier),
-                            Pllsrc::HSI_DIV_PREDIV,
-                            into_pll_mul(multiplier),
-                            Some(into_pre_div(divisor)),
-                        )
-                    } else {
-                        let pllsrcclk = HSI / 2;
-                        let multiplier = sysclk / pllsrcclk;
-                        assert!(multiplier <= 16);
-                        (
-                            Hertz(pllsrcclk * multiplier),
-                            Pllsrc::HSI_DIV2,
-                            into_pll_mul(multiplier),
-                            None,
-                        )
-                    }
+                    let pllsrcclk = HSI / 2;
+                    let multiplier = sysclk / pllsrcclk;
+                    assert!(multiplier <= 16);
+                    (
+                        Hertz(pllsrcclk * multiplier),
+                        Pllsrc::HSI_DIV2,
+                        into_pll_mul(multiplier),
+                        None,
+                    )
                 }
             }
-        };
-        (
-            act_sysclk,
-            PllConfig {
-                pll_src,
-                pll_mul,
-                pll_div,
-            },
-        )
-    }
+        }
+    };
+    (
+        act_sysclk,
+        PllConfig {
+            pll_src,
+            pll_mul,
+            pll_div,
+        },
+    )
+}
 
-    #[inline]
-    fn get_usb_pre(&self, sysclk: u32, pclk1: u32, pll_config: &Option<PllConfig>) -> Usbpre {
-        cfg_if::cfg_if! {
-            // Some chips do not have USB
-            if #[cfg(any(stm32f301, stm32f318, stm32f334))] {
-                panic!("USB clock not supported by the chip");
-            } else {
-                let usb_ok = self.config.hse.is_some() && pll_config.is_some() && (pclk1 >= 10_000_000);
-                match (usb_ok, sysclk) {
-                    (true, 72_000_000) => Usbpre::DIV1_5,
-                    (true, 48_000_000) => Usbpre::DIV1,
-                    _ => panic!(
-                        "USB clock is only valid if the PLL output frequency is either 48MHz or 72MHz"
-                    ),
-                }
+#[inline]
+fn get_usb_pre(config: &Config, sysclk: u32, pclk1: u32, pll_config: &Option<PllConfig>) -> Usbpre {
+    cfg_if::cfg_if! {
+        // Some chips do not have USB
+        if #[cfg(any(stm32f301, stm32f318, stm32f334))] {
+            panic!("USB clock not supported by the chip");
+        } else {
+            let usb_ok = config.hse.is_some() && pll_config.is_some() && (pclk1 >= 10_000_000);
+            match (usb_ok, sysclk) {
+                (true, 72_000_000) => Usbpre::DIV1_5,
+                (true, 48_000_000) => Usbpre::DIV1,
+                _ => panic!(
+                    "USB clock is only valid if the PLL output frequency is either 48MHz or 72MHz"
+                ),
             }
         }
     }
diff --git a/embassy-stm32/src/rcc/f4.rs b/embassy-stm32/src/rcc/f4.rs
index 58a08adbf..aba8fc0ef 100644
--- a/embassy-stm32/src/rcc/f4.rs
+++ b/embassy-stm32/src/rcc/f4.rs
@@ -1,9 +1,8 @@
+use super::sealed::RccPeripheral;
+use crate::pac::rcc::vals::{Hpre, Hsebyp, Ppre, Sw};
 use crate::pac::{FLASH, PWR, RCC};
-use crate::peripherals;
-use crate::rcc::{get_freqs, set_freqs, Clocks};
+use crate::rcc::{set_freqs, Clocks};
 use crate::time::Hertz;
-use core::marker::PhantomData;
-use embassy::util::Unborrow;
 
 const HSI: u32 = 16_000_000;
 
@@ -21,284 +20,240 @@ pub struct Config {
     pub pll48: bool,
 }
 
-/// RCC peripheral
-pub struct Rcc<'d> {
-    config: Config,
-    phantom: PhantomData<&'d mut peripherals::RCC>,
+unsafe fn setup_pll(
+    pllsrcclk: u32,
+    use_hse: bool,
+    pllsysclk: Option<u32>,
+    pll48clk: bool,
+) -> PllResults {
+    use crate::pac::rcc::vals::{Pllp, Pllsrc};
+
+    let sysclk = pllsysclk.unwrap_or(pllsrcclk);
+    if pllsysclk.is_none() && !pll48clk {
+        RCC.pllcfgr()
+            .modify(|w| w.set_pllsrc(Pllsrc(use_hse as u8)));
+
+        return PllResults {
+            use_pll: false,
+            pllsysclk: None,
+            pll48clk: None,
+        };
+    }
+    // Input divisor from PLL source clock, must result to frequency in
+    // the range from 1 to 2 MHz
+    let pllm_min = (pllsrcclk + 1_999_999) / 2_000_000;
+    let pllm_max = pllsrcclk / 1_000_000;
+
+    // Sysclk output divisor must be one of 2, 4, 6 or 8
+    let sysclk_div = core::cmp::min(8, (432_000_000 / sysclk) & !1);
+
+    let target_freq = if pll48clk {
+        48_000_000
+    } else {
+        sysclk * sysclk_div
+    };
+
+    // Find the lowest pllm value that minimize the difference between
+    // target frequency and the real vco_out frequency.
+    let pllm = unwrap!((pllm_min..=pllm_max).min_by_key(|pllm| {
+        let vco_in = pllsrcclk / pllm;
+        let plln = target_freq / vco_in;
+        target_freq - vco_in * plln
+    }));
+
+    let vco_in = pllsrcclk / pllm;
+    assert!((1_000_000..=2_000_000).contains(&vco_in));
+
+    // Main scaler, must result in >= 100MHz (>= 192MHz for F401)
+    // and <= 432MHz, min 50, max 432
+    let plln = if pll48clk {
+        // try the different valid pllq according to the valid
+        // main scaller values, and take the best
+        let pllq = unwrap!((4..=9).min_by_key(|pllq| {
+            let plln = 48_000_000 * pllq / vco_in;
+            let pll48_diff = 48_000_000 - vco_in * plln / pllq;
+            let sysclk_diff = (sysclk as i32 - (vco_in * plln / sysclk_div) as i32).abs();
+            (pll48_diff, sysclk_diff)
+        }));
+        48_000_000 * pllq / vco_in
+    } else {
+        sysclk * sysclk_div / vco_in
+    };
+
+    let pllp = (sysclk_div / 2) - 1;
+
+    let pllq = (vco_in * plln + 47_999_999) / 48_000_000;
+    let real_pll48clk = vco_in * plln / pllq;
+
+    RCC.pllcfgr().modify(|w| {
+        w.set_pllm(pllm as u8);
+        w.set_plln(plln as u16);
+        w.set_pllp(Pllp(pllp as u8));
+        w.set_pllq(pllq as u8);
+        w.set_pllsrc(Pllsrc(use_hse as u8));
+    });
+
+    let real_pllsysclk = vco_in * plln / sysclk_div;
+
+    PllResults {
+        use_pll: true,
+        pllsysclk: Some(real_pllsysclk),
+        pll48clk: if pll48clk { Some(real_pll48clk) } else { None },
+    }
 }
 
-impl<'d> Rcc<'d> {
-    pub fn new(_rcc: impl Unborrow<Target = peripherals::RCC> + 'd, config: Config) -> Self {
-        Self {
-            config,
-            phantom: PhantomData,
-        }
-    }
+unsafe fn flash_setup(sysclk: u32) {
+    use crate::pac::flash::vals::Latency;
 
-    fn freeze(mut self) -> Clocks {
-        use super::sealed::RccPeripheral;
-        use crate::pac::rcc::vals::{Hpre, Hsebyp, Ppre, Sw};
+    // Be conservative with voltage ranges
+    const FLASH_LATENCY_STEP: u32 = 30_000_000;
 
-        peripherals::PWR::enable();
-
-        let pllsrcclk = self.config.hse.map(|hse| hse.0).unwrap_or(HSI);
-        let sysclk = self.config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk);
-        let sysclk_on_pll = sysclk != pllsrcclk;
-
-        let plls = self.setup_pll(
-            pllsrcclk,
-            self.config.hse.is_some(),
-            if sysclk_on_pll { Some(sysclk) } else { None },
-            self.config.pll48,
-        );
-
-        if self.config.pll48 {
-            let freq = unwrap!(plls.pll48clk);
-
-            assert!((max::PLL_48_CLK as i32 - freq as i32).abs() <= max::PLL_48_TOLERANCE as i32);
-        }
-
-        let sysclk = if sysclk_on_pll {
-            unwrap!(plls.pllsysclk)
-        } else {
-            sysclk
-        };
-
-        // AHB prescaler
-        let hclk = self.config.hclk.map(|h| h.0).unwrap_or(sysclk);
-        let (hpre_bits, hpre_div) = match (sysclk + hclk - 1) / hclk {
-            0 => unreachable!(),
-            1 => (Hpre::DIV1, 1),
-            2 => (Hpre::DIV2, 2),
-            3..=5 => (Hpre::DIV4, 4),
-            6..=11 => (Hpre::DIV8, 8),
-            12..=39 => (Hpre::DIV16, 16),
-            40..=95 => (Hpre::DIV64, 64),
-            96..=191 => (Hpre::DIV128, 128),
-            192..=383 => (Hpre::DIV256, 256),
-            _ => (Hpre::DIV512, 512),
-        };
-
-        // Calculate real AHB clock
-        let hclk = sysclk / hpre_div;
-
-        let pclk1 = self
-            .config
-            .pclk1
-            .map(|p| p.0)
-            .unwrap_or_else(|| core::cmp::min(max::PCLK1_MAX, hclk));
-
-        let (ppre1_bits, ppre1) = match (hclk + pclk1 - 1) / pclk1 {
-            0 => unreachable!(),
-            1 => (0b000, 1),
-            2 => (0b100, 2),
-            3..=5 => (0b101, 4),
-            6..=11 => (0b110, 8),
-            _ => (0b111, 16),
-        };
-        let timer_mul1 = if ppre1 == 1 { 1 } else { 2 };
-
-        // Calculate real APB1 clock
-        let pclk1 = hclk / ppre1;
-        assert!(pclk1 <= max::PCLK1_MAX);
-
-        let pclk2 = self
-            .config
-            .pclk2
-            .map(|p| p.0)
-            .unwrap_or_else(|| core::cmp::min(max::PCLK2_MAX, hclk));
-        let (ppre2_bits, ppre2) = match (hclk + pclk2 - 1) / pclk2 {
-            0 => unreachable!(),
-            1 => (0b000, 1),
-            2 => (0b100, 2),
-            3..=5 => (0b101, 4),
-            6..=11 => (0b110, 8),
-            _ => (0b111, 16),
-        };
-        let timer_mul2 = if ppre2 == 1 { 1 } else { 2 };
-
-        // Calculate real APB2 clock
-        let pclk2 = hclk / ppre2;
-        assert!(pclk2 <= max::PCLK2_MAX);
-
-        Self::flash_setup(sysclk);
-
-        if self.config.hse.is_some() {
-            // NOTE(unsafe) We own the peripheral block
-            unsafe {
-                RCC.cr().modify(|w| {
-                    w.set_hsebyp(Hsebyp(self.config.bypass_hse as u8));
-                    w.set_hseon(true);
-                });
-                while !RCC.cr().read().hserdy() {}
-            }
-        }
-
-        if plls.use_pll {
-            unsafe {
-                RCC.cr().modify(|w| w.set_pllon(true));
-
-                if hclk > max::HCLK_OVERDRIVE_FREQUENCY {
-                    PWR.cr1().modify(|w| w.set_oden(true));
-                    while !PWR.csr1().read().odrdy() {}
-
-                    PWR.cr1().modify(|w| w.set_odswen(true));
-                    while !PWR.csr1().read().odswrdy() {}
-                }
-
-                while !RCC.cr().read().pllrdy() {}
-            }
-        }
-
-        unsafe {
-            RCC.cfgr().modify(|w| {
-                w.set_ppre2(Ppre(ppre2_bits));
-                w.set_ppre1(Ppre(ppre1_bits));
-                w.set_hpre(hpre_bits);
-            });
-
-            // Wait for the new prescalers to kick in
-            // "The clocks are divided with the new prescaler factor from 1 to 16 AHB cycles after write"
-            cortex_m::asm::delay(16);
-
-            RCC.cfgr().modify(|w| {
-                w.set_sw(if sysclk_on_pll {
-                    Sw::PLL
-                } else if self.config.hse.is_some() {
-                    Sw::HSE
-                } else {
-                    Sw::HSI
-                })
-            });
-        }
-
-        Clocks {
-            sys: Hertz(sysclk),
-            apb1: Hertz(pclk1),
-            apb2: Hertz(pclk2),
-
-            apb1_tim: Hertz(pclk1 * timer_mul1),
-            apb2_tim: Hertz(pclk2 * timer_mul2),
-
-            ahb1: Hertz(hclk),
-            ahb2: Hertz(hclk),
-            ahb3: Hertz(hclk),
-
-            pll48: plls.pll48clk.map(Hertz),
-        }
-    }
-
-    // Safety: RCC init must have been called
-    pub fn clocks(&self) -> &'static Clocks {
-        unsafe { get_freqs() }
-    }
-
-    fn setup_pll(
-        &mut self,
-        pllsrcclk: u32,
-        use_hse: bool,
-        pllsysclk: Option<u32>,
-        pll48clk: bool,
-    ) -> PllResults {
-        use crate::pac::rcc::vals::{Pllp, Pllsrc};
-
-        let sysclk = pllsysclk.unwrap_or(pllsrcclk);
-        if pllsysclk.is_none() && !pll48clk {
-            // NOTE(unsafe) We have a mutable borrow to the owner of the RegBlock
-            unsafe {
-                RCC.pllcfgr()
-                    .modify(|w| w.set_pllsrc(Pllsrc(use_hse as u8)));
-            }
-
-            return PllResults {
-                use_pll: false,
-                pllsysclk: None,
-                pll48clk: None,
-            };
-        }
-        // Input divisor from PLL source clock, must result to frequency in
-        // the range from 1 to 2 MHz
-        let pllm_min = (pllsrcclk + 1_999_999) / 2_000_000;
-        let pllm_max = pllsrcclk / 1_000_000;
-
-        // Sysclk output divisor must be one of 2, 4, 6 or 8
-        let sysclk_div = core::cmp::min(8, (432_000_000 / sysclk) & !1);
-
-        let target_freq = if pll48clk {
-            48_000_000
-        } else {
-            sysclk * sysclk_div
-        };
-
-        // Find the lowest pllm value that minimize the difference between
-        // target frequency and the real vco_out frequency.
-        let pllm = unwrap!((pllm_min..=pllm_max).min_by_key(|pllm| {
-            let vco_in = pllsrcclk / pllm;
-            let plln = target_freq / vco_in;
-            target_freq - vco_in * plln
-        }));
-
-        let vco_in = pllsrcclk / pllm;
-        assert!((1_000_000..=2_000_000).contains(&vco_in));
-
-        // Main scaler, must result in >= 100MHz (>= 192MHz for F401)
-        // and <= 432MHz, min 50, max 432
-        let plln = if pll48clk {
-            // try the different valid pllq according to the valid
-            // main scaller values, and take the best
-            let pllq = unwrap!((4..=9).min_by_key(|pllq| {
-                let plln = 48_000_000 * pllq / vco_in;
-                let pll48_diff = 48_000_000 - vco_in * plln / pllq;
-                let sysclk_diff = (sysclk as i32 - (vco_in * plln / sysclk_div) as i32).abs();
-                (pll48_diff, sysclk_diff)
-            }));
-            48_000_000 * pllq / vco_in
-        } else {
-            sysclk * sysclk_div / vco_in
-        };
-
-        let pllp = (sysclk_div / 2) - 1;
-
-        let pllq = (vco_in * plln + 47_999_999) / 48_000_000;
-        let real_pll48clk = vco_in * plln / pllq;
-
-        unsafe {
-            RCC.pllcfgr().modify(|w| {
-                w.set_pllm(pllm as u8);
-                w.set_plln(plln as u16);
-                w.set_pllp(Pllp(pllp as u8));
-                w.set_pllq(pllq as u8);
-                w.set_pllsrc(Pllsrc(use_hse as u8));
-            });
-        }
-
-        let real_pllsysclk = vco_in * plln / sysclk_div;
-
-        PllResults {
-            use_pll: true,
-            pllsysclk: Some(real_pllsysclk),
-            pll48clk: if pll48clk { Some(real_pll48clk) } else { None },
-        }
-    }
-
-    fn flash_setup(sysclk: u32) {
-        use crate::pac::flash::vals::Latency;
-
-        // Be conservative with voltage ranges
-        const FLASH_LATENCY_STEP: u32 = 30_000_000;
-
-        critical_section::with(|_| unsafe {
-            FLASH
-                .acr()
-                .modify(|w| w.set_latency(Latency(((sysclk - 1) / FLASH_LATENCY_STEP) as u8)));
-        });
-    }
+    critical_section::with(|_| {
+        FLASH
+            .acr()
+            .modify(|w| w.set_latency(Latency(((sysclk - 1) / FLASH_LATENCY_STEP) as u8)));
+    });
 }
 
 pub(crate) unsafe fn init(config: Config) {
-    let r = <peripherals::RCC as embassy::util::Steal>::steal();
-    let clocks = Rcc::new(r, config).freeze();
-    set_freqs(clocks);
+    crate::peripherals::PWR::enable();
+
+    let pllsrcclk = config.hse.map(|hse| hse.0).unwrap_or(HSI);
+    let sysclk = config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk);
+    let sysclk_on_pll = sysclk != pllsrcclk;
+
+    let plls = setup_pll(
+        pllsrcclk,
+        config.hse.is_some(),
+        if sysclk_on_pll { Some(sysclk) } else { None },
+        config.pll48,
+    );
+
+    if config.pll48 {
+        let freq = unwrap!(plls.pll48clk);
+
+        assert!((max::PLL_48_CLK as i32 - freq as i32).abs() <= max::PLL_48_TOLERANCE as i32);
+    }
+
+    let sysclk = if sysclk_on_pll {
+        unwrap!(plls.pllsysclk)
+    } else {
+        sysclk
+    };
+
+    // AHB prescaler
+    let hclk = config.hclk.map(|h| h.0).unwrap_or(sysclk);
+    let (hpre_bits, hpre_div) = match (sysclk + hclk - 1) / hclk {
+        0 => unreachable!(),
+        1 => (Hpre::DIV1, 1),
+        2 => (Hpre::DIV2, 2),
+        3..=5 => (Hpre::DIV4, 4),
+        6..=11 => (Hpre::DIV8, 8),
+        12..=39 => (Hpre::DIV16, 16),
+        40..=95 => (Hpre::DIV64, 64),
+        96..=191 => (Hpre::DIV128, 128),
+        192..=383 => (Hpre::DIV256, 256),
+        _ => (Hpre::DIV512, 512),
+    };
+
+    // Calculate real AHB clock
+    let hclk = sysclk / hpre_div;
+
+    let pclk1 = config
+        .pclk1
+        .map(|p| p.0)
+        .unwrap_or_else(|| core::cmp::min(max::PCLK1_MAX, hclk));
+
+    let (ppre1_bits, ppre1) = match (hclk + pclk1 - 1) / pclk1 {
+        0 => unreachable!(),
+        1 => (0b000, 1),
+        2 => (0b100, 2),
+        3..=5 => (0b101, 4),
+        6..=11 => (0b110, 8),
+        _ => (0b111, 16),
+    };
+    let timer_mul1 = if ppre1 == 1 { 1 } else { 2 };
+
+    // Calculate real APB1 clock
+    let pclk1 = hclk / ppre1;
+    assert!(pclk1 <= max::PCLK1_MAX);
+
+    let pclk2 = config
+        .pclk2
+        .map(|p| p.0)
+        .unwrap_or_else(|| core::cmp::min(max::PCLK2_MAX, hclk));
+    let (ppre2_bits, ppre2) = match (hclk + pclk2 - 1) / pclk2 {
+        0 => unreachable!(),
+        1 => (0b000, 1),
+        2 => (0b100, 2),
+        3..=5 => (0b101, 4),
+        6..=11 => (0b110, 8),
+        _ => (0b111, 16),
+    };
+    let timer_mul2 = if ppre2 == 1 { 1 } else { 2 };
+
+    // Calculate real APB2 clock
+    let pclk2 = hclk / ppre2;
+    assert!(pclk2 <= max::PCLK2_MAX);
+
+    flash_setup(sysclk);
+
+    if config.hse.is_some() {
+        RCC.cr().modify(|w| {
+            w.set_hsebyp(Hsebyp(config.bypass_hse as u8));
+            w.set_hseon(true);
+        });
+        while !RCC.cr().read().hserdy() {}
+    }
+
+    if plls.use_pll {
+        RCC.cr().modify(|w| w.set_pllon(true));
+
+        if hclk > max::HCLK_OVERDRIVE_FREQUENCY {
+            PWR.cr1().modify(|w| w.set_oden(true));
+            while !PWR.csr1().read().odrdy() {}
+
+            PWR.cr1().modify(|w| w.set_odswen(true));
+            while !PWR.csr1().read().odswrdy() {}
+        }
+
+        while !RCC.cr().read().pllrdy() {}
+    }
+
+    RCC.cfgr().modify(|w| {
+        w.set_ppre2(Ppre(ppre2_bits));
+        w.set_ppre1(Ppre(ppre1_bits));
+        w.set_hpre(hpre_bits);
+    });
+
+    // Wait for the new prescalers to kick in
+    // "The clocks are divided with the new prescaler factor from 1 to 16 AHB cycles after write"
+    cortex_m::asm::delay(16);
+
+    RCC.cfgr().modify(|w| {
+        w.set_sw(if sysclk_on_pll {
+            Sw::PLL
+        } else if config.hse.is_some() {
+            Sw::HSE
+        } else {
+            Sw::HSI
+        })
+    });
+
+    set_freqs(Clocks {
+        sys: Hertz(sysclk),
+        apb1: Hertz(pclk1),
+        apb2: Hertz(pclk2),
+
+        apb1_tim: Hertz(pclk1 * timer_mul1),
+        apb2_tim: Hertz(pclk2 * timer_mul2),
+
+        ahb1: Hertz(hclk),
+        ahb2: Hertz(hclk),
+        ahb3: Hertz(hclk),
+
+        pll48: plls.pll48clk.map(Hertz),
+    });
 }
 
 struct PllResults {
diff --git a/embassy-stm32/src/rcc/f7.rs b/embassy-stm32/src/rcc/f7.rs
index d29ba31f0..1a0530296 100644
--- a/embassy-stm32/src/rcc/f7.rs
+++ b/embassy-stm32/src/rcc/f7.rs
@@ -1,9 +1,9 @@
+use super::sealed::RccPeripheral;
+use crate::pac::pwr::vals::Vos;
+use crate::pac::rcc::vals::{Hpre, Hsebyp, Ppre, Sw};
 use crate::pac::{FLASH, PWR, RCC};
-use crate::peripherals;
-use crate::rcc::{get_freqs, set_freqs, Clocks};
+use crate::rcc::{set_freqs, Clocks};
 use crate::time::Hertz;
-use core::marker::PhantomData;
-use embassy::util::Unborrow;
 
 const HSI: u32 = 16_000_000;
 
@@ -21,318 +21,274 @@ pub struct Config {
     pub pll48: bool,
 }
 
-/// RCC peripheral
-pub struct Rcc<'d> {
-    config: Config,
-    phantom: PhantomData<&'d mut peripherals::RCC>,
+unsafe fn setup_pll(
+    pllsrcclk: u32,
+    use_hse: bool,
+    pllsysclk: Option<u32>,
+    pll48clk: bool,
+) -> PllResults {
+    use crate::pac::rcc::vals::{Pllp, Pllsrc};
+
+    let sysclk = pllsysclk.unwrap_or(pllsrcclk);
+    if pllsysclk.is_none() && !pll48clk {
+        RCC.pllcfgr()
+            .modify(|w| w.set_pllsrc(Pllsrc(use_hse as u8)));
+
+        return PllResults {
+            use_pll: false,
+            pllsysclk: None,
+            pll48clk: None,
+        };
+    }
+    // Input divisor from PLL source clock, must result to frequency in
+    // the range from 1 to 2 MHz
+    let pllm_min = (pllsrcclk + 1_999_999) / 2_000_000;
+    let pllm_max = pllsrcclk / 1_000_000;
+
+    // Sysclk output divisor must be one of 2, 4, 6 or 8
+    let sysclk_div = core::cmp::min(8, (432_000_000 / sysclk) & !1);
+
+    let target_freq = if pll48clk {
+        48_000_000
+    } else {
+        sysclk * sysclk_div
+    };
+
+    // Find the lowest pllm value that minimize the difference between
+    // target frequency and the real vco_out frequency.
+    let pllm = unwrap!((pllm_min..=pllm_max).min_by_key(|pllm| {
+        let vco_in = pllsrcclk / pllm;
+        let plln = target_freq / vco_in;
+        target_freq - vco_in * plln
+    }));
+
+    let vco_in = pllsrcclk / pllm;
+    assert!((1_000_000..=2_000_000).contains(&vco_in));
+
+    // Main scaler, must result in >= 100MHz (>= 192MHz for F401)
+    // and <= 432MHz, min 50, max 432
+    let plln = if pll48clk {
+        // try the different valid pllq according to the valid
+        // main scaller values, and take the best
+        let pllq = unwrap!((4..=9).min_by_key(|pllq| {
+            let plln = 48_000_000 * pllq / vco_in;
+            let pll48_diff = 48_000_000 - vco_in * plln / pllq;
+            let sysclk_diff = (sysclk as i32 - (vco_in * plln / sysclk_div) as i32).abs();
+            (pll48_diff, sysclk_diff)
+        }));
+        48_000_000 * pllq / vco_in
+    } else {
+        sysclk * sysclk_div / vco_in
+    };
+
+    let pllp = (sysclk_div / 2) - 1;
+
+    let pllq = (vco_in * plln + 47_999_999) / 48_000_000;
+    let real_pll48clk = vco_in * plln / pllq;
+
+    RCC.pllcfgr().modify(|w| {
+        w.set_pllm(pllm as u8);
+        w.set_plln(plln as u16);
+        w.set_pllp(Pllp(pllp as u8));
+        w.set_pllq(pllq as u8);
+        w.set_pllsrc(Pllsrc(use_hse as u8));
+    });
+
+    let real_pllsysclk = vco_in * plln / sysclk_div;
+
+    PllResults {
+        use_pll: true,
+        pllsysclk: Some(real_pllsysclk),
+        pll48clk: if pll48clk { Some(real_pll48clk) } else { None },
+    }
 }
 
-impl<'d> Rcc<'d> {
-    pub fn new(_rcc: impl Unborrow<Target = peripherals::RCC> + 'd, config: Config) -> Self {
-        if let Some(hse) = config.hse {
-            if config.bypass_hse {
-                assert!((max::HSE_BYPASS_MIN..=max::HSE_BYPASS_MAX).contains(&hse.0));
-            } else {
-                assert!((max::HSE_OSC_MIN..=max::HSE_OSC_MAX).contains(&hse.0));
-            }
-        }
-        Self {
-            config,
-            phantom: PhantomData,
-        }
-    }
+unsafe fn flash_setup(sysclk: u32) {
+    use crate::pac::flash::vals::Latency;
 
-    fn freeze(mut self) -> Clocks {
-        use super::sealed::RccPeripheral;
-        use crate::pac::pwr::vals::Vos;
-        use crate::pac::rcc::vals::{Hpre, Hsebyp, Ppre, Sw};
+    // Be conservative with voltage ranges
+    const FLASH_LATENCY_STEP: u32 = 30_000_000;
 
-        peripherals::PWR::enable();
-
-        let pllsrcclk = self.config.hse.map(|hse| hse.0).unwrap_or(HSI);
-        let sysclk = self.config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk);
-        let sysclk_on_pll = sysclk != pllsrcclk;
-
-        assert!((max::SYSCLK_MIN..=max::SYSCLK_MAX).contains(&sysclk));
-
-        let plls = self.setup_pll(
-            pllsrcclk,
-            self.config.hse.is_some(),
-            if sysclk_on_pll { Some(sysclk) } else { None },
-            self.config.pll48,
-        );
-
-        if self.config.pll48 {
-            let freq = unwrap!(plls.pll48clk);
-
-            assert!((max::PLL_48_CLK as i32 - freq as i32).abs() <= max::PLL_48_TOLERANCE as i32);
-        }
-
-        let sysclk = if sysclk_on_pll {
-            unwrap!(plls.pllsysclk)
-        } else {
-            sysclk
-        };
-
-        // AHB prescaler
-        let hclk = self.config.hclk.map(|h| h.0).unwrap_or(sysclk);
-        let (hpre_bits, hpre_div) = match (sysclk + hclk - 1) / hclk {
-            0 => unreachable!(),
-            1 => (Hpre::DIV1, 1),
-            2 => (Hpre::DIV2, 2),
-            3..=5 => (Hpre::DIV4, 4),
-            6..=11 => (Hpre::DIV8, 8),
-            12..=39 => (Hpre::DIV16, 16),
-            40..=95 => (Hpre::DIV64, 64),
-            96..=191 => (Hpre::DIV128, 128),
-            192..=383 => (Hpre::DIV256, 256),
-            _ => (Hpre::DIV512, 512),
-        };
-
-        // Calculate real AHB clock
-        let hclk = sysclk / hpre_div;
-
-        assert!(hclk < max::HCLK_MAX);
-
-        let pclk1 = self
-            .config
-            .pclk1
-            .map(|p| p.0)
-            .unwrap_or_else(|| core::cmp::min(max::PCLK1_MAX, hclk));
-
-        let (ppre1_bits, ppre1) = match (hclk + pclk1 - 1) / pclk1 {
-            0 => unreachable!(),
-            1 => (0b000, 1),
-            2 => (0b100, 2),
-            3..=5 => (0b101, 4),
-            6..=11 => (0b110, 8),
-            _ => (0b111, 16),
-        };
-        let timer_mul1 = if ppre1 == 1 { 1 } else { 2 };
-
-        // Calculate real APB1 clock
-        let pclk1 = hclk / ppre1;
-        assert!((max::PCLK1_MIN..=max::PCLK1_MAX).contains(&pclk1));
-
-        let pclk2 = self
-            .config
-            .pclk2
-            .map(|p| p.0)
-            .unwrap_or_else(|| core::cmp::min(max::PCLK2_MAX, hclk));
-        let (ppre2_bits, ppre2) = match (hclk + pclk2 - 1) / pclk2 {
-            0 => unreachable!(),
-            1 => (0b000, 1),
-            2 => (0b100, 2),
-            3..=5 => (0b101, 4),
-            6..=11 => (0b110, 8),
-            _ => (0b111, 16),
-        };
-        let timer_mul2 = if ppre2 == 1 { 1 } else { 2 };
-
-        // Calculate real APB2 clock
-        let pclk2 = hclk / ppre2;
-        assert!((max::PCLK2_MIN..=max::PCLK2_MAX).contains(&pclk2));
-
-        Self::flash_setup(sysclk);
-
-        if self.config.hse.is_some() {
-            // NOTE(unsafe) We own the peripheral block
-            unsafe {
-                RCC.cr().modify(|w| {
-                    w.set_hsebyp(Hsebyp(self.config.bypass_hse as u8));
-                    w.set_hseon(true);
-                });
-                while !RCC.cr().read().hserdy() {}
-            }
-        }
-
-        if plls.use_pll {
-            unsafe {
-                RCC.cr().modify(|w| w.set_pllon(false));
-
-                // enable PWR and setup VOSScale
-
-                RCC.apb1enr().modify(|w| w.set_pwren(true));
-
-                let vos_scale = if sysclk <= 144_000_000 {
-                    3
-                } else if sysclk <= 168_000_000 {
-                    2
-                } else {
-                    1
-                };
-                PWR.cr1().modify(|w| {
-                    w.set_vos(match vos_scale {
-                        3 => Vos::SCALE3,
-                        2 => Vos::SCALE2,
-                        1 => Vos::SCALE1,
-                        _ => panic!("Invalid VOS Scale."),
-                    })
-                });
-
-                RCC.cr().modify(|w| w.set_pllon(true));
-
-                if hclk > max::HCLK_OVERDRIVE_FREQUENCY {
-                    PWR.cr1().modify(|w| w.set_oden(true));
-                    while !PWR.csr1().read().odrdy() {}
-
-                    PWR.cr1().modify(|w| w.set_odswen(true));
-                    while !PWR.csr1().read().odswrdy() {}
-                }
-
-                while !RCC.cr().read().pllrdy() {}
-            }
-        }
-
-        unsafe {
-            RCC.cfgr().modify(|w| {
-                w.set_ppre2(Ppre(ppre2_bits));
-                w.set_ppre1(Ppre(ppre1_bits));
-                w.set_hpre(hpre_bits);
-            });
-
-            // Wait for the new prescalers to kick in
-            // "The clocks are divided with the new prescaler factor from 1 to 16 AHB cycles after write"
-            cortex_m::asm::delay(16);
-
-            RCC.cfgr().modify(|w| {
-                w.set_sw(if sysclk_on_pll {
-                    Sw::PLL
-                } else if self.config.hse.is_some() {
-                    Sw::HSE
-                } else {
-                    Sw::HSI
-                })
-            });
-        }
-
-        Clocks {
-            sys: Hertz(sysclk),
-            apb1: Hertz(pclk1),
-            apb2: Hertz(pclk2),
-
-            apb1_tim: Hertz(pclk1 * timer_mul1),
-            apb2_tim: Hertz(pclk2 * timer_mul2),
-
-            ahb1: Hertz(hclk),
-            ahb2: Hertz(hclk),
-            ahb3: Hertz(hclk),
-
-            pll48: plls.pll48clk.map(Hertz),
-        }
-    }
-
-    // Safety: RCC init must have been called
-    pub fn clocks(&self) -> &'static Clocks {
-        unsafe { get_freqs() }
-    }
-
-    fn setup_pll(
-        &mut self,
-        pllsrcclk: u32,
-        use_hse: bool,
-        pllsysclk: Option<u32>,
-        pll48clk: bool,
-    ) -> PllResults {
-        use crate::pac::rcc::vals::{Pllp, Pllsrc};
-
-        let sysclk = pllsysclk.unwrap_or(pllsrcclk);
-        if pllsysclk.is_none() && !pll48clk {
-            // NOTE(unsafe) We have a mutable borrow to the owner of the RegBlock
-            unsafe {
-                RCC.pllcfgr()
-                    .modify(|w| w.set_pllsrc(Pllsrc(use_hse as u8)));
-            }
-
-            return PllResults {
-                use_pll: false,
-                pllsysclk: None,
-                pll48clk: None,
-            };
-        }
-        // Input divisor from PLL source clock, must result to frequency in
-        // the range from 1 to 2 MHz
-        let pllm_min = (pllsrcclk + 1_999_999) / 2_000_000;
-        let pllm_max = pllsrcclk / 1_000_000;
-
-        // Sysclk output divisor must be one of 2, 4, 6 or 8
-        let sysclk_div = core::cmp::min(8, (432_000_000 / sysclk) & !1);
-
-        let target_freq = if pll48clk {
-            48_000_000
-        } else {
-            sysclk * sysclk_div
-        };
-
-        // Find the lowest pllm value that minimize the difference between
-        // target frequency and the real vco_out frequency.
-        let pllm = unwrap!((pllm_min..=pllm_max).min_by_key(|pllm| {
-            let vco_in = pllsrcclk / pllm;
-            let plln = target_freq / vco_in;
-            target_freq - vco_in * plln
-        }));
-
-        let vco_in = pllsrcclk / pllm;
-        assert!((1_000_000..=2_000_000).contains(&vco_in));
-
-        // Main scaler, must result in >= 100MHz (>= 192MHz for F401)
-        // and <= 432MHz, min 50, max 432
-        let plln = if pll48clk {
-            // try the different valid pllq according to the valid
-            // main scaller values, and take the best
-            let pllq = unwrap!((4..=9).min_by_key(|pllq| {
-                let plln = 48_000_000 * pllq / vco_in;
-                let pll48_diff = 48_000_000 - vco_in * plln / pllq;
-                let sysclk_diff = (sysclk as i32 - (vco_in * plln / sysclk_div) as i32).abs();
-                (pll48_diff, sysclk_diff)
-            }));
-            48_000_000 * pllq / vco_in
-        } else {
-            sysclk * sysclk_div / vco_in
-        };
-
-        let pllp = (sysclk_div / 2) - 1;
-
-        let pllq = (vco_in * plln + 47_999_999) / 48_000_000;
-        let real_pll48clk = vco_in * plln / pllq;
-
-        unsafe {
-            RCC.pllcfgr().modify(|w| {
-                w.set_pllm(pllm as u8);
-                w.set_plln(plln as u16);
-                w.set_pllp(Pllp(pllp as u8));
-                w.set_pllq(pllq as u8);
-                w.set_pllsrc(Pllsrc(use_hse as u8));
-            });
-        }
-
-        let real_pllsysclk = vco_in * plln / sysclk_div;
-
-        PllResults {
-            use_pll: true,
-            pllsysclk: Some(real_pllsysclk),
-            pll48clk: if pll48clk { Some(real_pll48clk) } else { None },
-        }
-    }
-
-    fn flash_setup(sysclk: u32) {
-        use crate::pac::flash::vals::Latency;
-
-        // Be conservative with voltage ranges
-        const FLASH_LATENCY_STEP: u32 = 30_000_000;
-
-        critical_section::with(|_| unsafe {
-            FLASH
-                .acr()
-                .modify(|w| w.set_latency(Latency(((sysclk - 1) / FLASH_LATENCY_STEP) as u8)));
-        });
-    }
+    critical_section::with(|_| {
+        FLASH
+            .acr()
+            .modify(|w| w.set_latency(Latency(((sysclk - 1) / FLASH_LATENCY_STEP) as u8)));
+    });
 }
 
 pub(crate) unsafe fn init(config: Config) {
-    let r = <peripherals::RCC as embassy::util::Steal>::steal();
-    let clocks = Rcc::new(r, config).freeze();
-    set_freqs(clocks);
+    crate::peripherals::PWR::enable();
+
+    if let Some(hse) = config.hse {
+        if config.bypass_hse {
+            assert!((max::HSE_BYPASS_MIN..=max::HSE_BYPASS_MAX).contains(&hse.0));
+        } else {
+            assert!((max::HSE_OSC_MIN..=max::HSE_OSC_MAX).contains(&hse.0));
+        }
+    }
+
+    let pllsrcclk = config.hse.map(|hse| hse.0).unwrap_or(HSI);
+    let sysclk = config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk);
+    let sysclk_on_pll = sysclk != pllsrcclk;
+
+    assert!((max::SYSCLK_MIN..=max::SYSCLK_MAX).contains(&sysclk));
+
+    let plls = setup_pll(
+        pllsrcclk,
+        config.hse.is_some(),
+        if sysclk_on_pll { Some(sysclk) } else { None },
+        config.pll48,
+    );
+
+    if config.pll48 {
+        let freq = unwrap!(plls.pll48clk);
+
+        assert!((max::PLL_48_CLK as i32 - freq as i32).abs() <= max::PLL_48_TOLERANCE as i32);
+    }
+
+    let sysclk = if sysclk_on_pll {
+        unwrap!(plls.pllsysclk)
+    } else {
+        sysclk
+    };
+
+    // AHB prescaler
+    let hclk = config.hclk.map(|h| h.0).unwrap_or(sysclk);
+    let (hpre_bits, hpre_div) = match (sysclk + hclk - 1) / hclk {
+        0 => unreachable!(),
+        1 => (Hpre::DIV1, 1),
+        2 => (Hpre::DIV2, 2),
+        3..=5 => (Hpre::DIV4, 4),
+        6..=11 => (Hpre::DIV8, 8),
+        12..=39 => (Hpre::DIV16, 16),
+        40..=95 => (Hpre::DIV64, 64),
+        96..=191 => (Hpre::DIV128, 128),
+        192..=383 => (Hpre::DIV256, 256),
+        _ => (Hpre::DIV512, 512),
+    };
+
+    // Calculate real AHB clock
+    let hclk = sysclk / hpre_div;
+
+    assert!(hclk < max::HCLK_MAX);
+
+    let pclk1 = config
+        .pclk1
+        .map(|p| p.0)
+        .unwrap_or_else(|| core::cmp::min(max::PCLK1_MAX, hclk));
+
+    let (ppre1_bits, ppre1) = match (hclk + pclk1 - 1) / pclk1 {
+        0 => unreachable!(),
+        1 => (0b000, 1),
+        2 => (0b100, 2),
+        3..=5 => (0b101, 4),
+        6..=11 => (0b110, 8),
+        _ => (0b111, 16),
+    };
+    let timer_mul1 = if ppre1 == 1 { 1 } else { 2 };
+
+    // Calculate real APB1 clock
+    let pclk1 = hclk / ppre1;
+    assert!((max::PCLK1_MIN..=max::PCLK1_MAX).contains(&pclk1));
+
+    let pclk2 = config
+        .pclk2
+        .map(|p| p.0)
+        .unwrap_or_else(|| core::cmp::min(max::PCLK2_MAX, hclk));
+    let (ppre2_bits, ppre2) = match (hclk + pclk2 - 1) / pclk2 {
+        0 => unreachable!(),
+        1 => (0b000, 1),
+        2 => (0b100, 2),
+        3..=5 => (0b101, 4),
+        6..=11 => (0b110, 8),
+        _ => (0b111, 16),
+    };
+    let timer_mul2 = if ppre2 == 1 { 1 } else { 2 };
+
+    // Calculate real APB2 clock
+    let pclk2 = hclk / ppre2;
+    assert!((max::PCLK2_MIN..=max::PCLK2_MAX).contains(&pclk2));
+
+    flash_setup(sysclk);
+
+    if config.hse.is_some() {
+        RCC.cr().modify(|w| {
+            w.set_hsebyp(Hsebyp(config.bypass_hse as u8));
+            w.set_hseon(true);
+        });
+        while !RCC.cr().read().hserdy() {}
+    }
+
+    if plls.use_pll {
+        RCC.cr().modify(|w| w.set_pllon(false));
+
+        // enable PWR and setup VOSScale
+
+        RCC.apb1enr().modify(|w| w.set_pwren(true));
+
+        let vos_scale = if sysclk <= 144_000_000 {
+            3
+        } else if sysclk <= 168_000_000 {
+            2
+        } else {
+            1
+        };
+        PWR.cr1().modify(|w| {
+            w.set_vos(match vos_scale {
+                3 => Vos::SCALE3,
+                2 => Vos::SCALE2,
+                1 => Vos::SCALE1,
+                _ => panic!("Invalid VOS Scale."),
+            })
+        });
+
+        RCC.cr().modify(|w| w.set_pllon(true));
+
+        if hclk > max::HCLK_OVERDRIVE_FREQUENCY {
+            PWR.cr1().modify(|w| w.set_oden(true));
+            while !PWR.csr1().read().odrdy() {}
+
+            PWR.cr1().modify(|w| w.set_odswen(true));
+            while !PWR.csr1().read().odswrdy() {}
+        }
+
+        while !RCC.cr().read().pllrdy() {}
+    }
+
+    RCC.cfgr().modify(|w| {
+        w.set_ppre2(Ppre(ppre2_bits));
+        w.set_ppre1(Ppre(ppre1_bits));
+        w.set_hpre(hpre_bits);
+    });
+
+    // Wait for the new prescalers to kick in
+    // "The clocks are divided with the new prescaler factor from 1 to 16 AHB cycles after write"
+    cortex_m::asm::delay(16);
+
+    RCC.cfgr().modify(|w| {
+        w.set_sw(if sysclk_on_pll {
+            Sw::PLL
+        } else if config.hse.is_some() {
+            Sw::HSE
+        } else {
+            Sw::HSI
+        })
+    });
+
+    set_freqs(Clocks {
+        sys: Hertz(sysclk),
+        apb1: Hertz(pclk1),
+        apb2: Hertz(pclk2),
+
+        apb1_tim: Hertz(pclk1 * timer_mul1),
+        apb2_tim: Hertz(pclk2 * timer_mul2),
+
+        ahb1: Hertz(hclk),
+        ahb2: Hertz(hclk),
+        ahb3: Hertz(hclk),
+
+        pll48: plls.pll48clk.map(Hertz),
+    });
 }
 
 struct PllResults {
diff --git a/embassy-stm32/src/rcc/g0.rs b/embassy-stm32/src/rcc/g0.rs
index df11ff36d..a3a4c197f 100644
--- a/embassy-stm32/src/rcc/g0.rs
+++ b/embassy-stm32/src/rcc/g0.rs
@@ -1,11 +1,7 @@
-use crate::pac;
-use crate::peripherals::{self, RCC};
-use crate::rcc::{get_freqs, set_freqs, Clocks};
+use crate::pac::{PWR, RCC};
+use crate::rcc::{set_freqs, Clocks};
 use crate::time::Hertz;
 use crate::time::U32Ext;
-use core::marker::PhantomData;
-use embassy::util::Unborrow;
-use embassy_hal_common::unborrow;
 
 /// HSI speed
 pub const HSI_FREQ: u32 = 16_000_000;
@@ -120,115 +116,68 @@ impl Default for Config {
     }
 }
 
-/// RCC peripheral
-pub struct Rcc<'d> {
-    _rb: peripherals::RCC,
-    phantom: PhantomData<&'d mut peripherals::RCC>,
-}
-
-impl<'d> Rcc<'d> {
-    pub fn new(rcc: impl Unborrow<Target = peripherals::RCC> + 'd) -> Self {
-        unborrow!(rcc);
-        Self {
-            _rb: rcc,
-            phantom: PhantomData,
-        }
-    }
-
-    // Safety: RCC init must have been called
-    pub fn clocks(&self) -> &'static Clocks {
-        unsafe { get_freqs() }
-    }
-}
-
-/// Extension trait that freezes the `RCC` peripheral with provided clocks configuration
-pub trait RccExt {
-    fn freeze(self, config: Config) -> Clocks;
-}
-
-impl RccExt for RCC {
-    #[inline]
-    fn freeze(self, cfgr: Config) -> Clocks {
-        let rcc = pac::RCC;
-        let (sys_clk, sw) = match cfgr.mux {
-            ClockSrc::HSI16(div) => {
-                // Enable HSI16
-                let div: u8 = div.into();
-                unsafe {
-                    rcc.cr().write(|w| {
-                        w.set_hsidiv(div);
-                        w.set_hsion(true)
-                    });
-                    while !rcc.cr().read().hsirdy() {}
-                }
-
-                (HSI_FREQ >> div, 0x00)
-            }
-            ClockSrc::HSE(freq) => {
-                // Enable HSE
-                unsafe {
-                    rcc.cr().write(|w| w.set_hseon(true));
-                    while !rcc.cr().read().hserdy() {}
-                }
-
-                (freq.0, 0x01)
-            }
-            ClockSrc::LSI => {
-                // Enable LSI
-                unsafe {
-                    rcc.csr().write(|w| w.set_lsion(true));
-                    while !rcc.csr().read().lsirdy() {}
-                }
-                (LSI_FREQ, 0x03)
-            }
-        };
-
-        unsafe {
-            rcc.cfgr().modify(|w| {
-                w.set_sw(sw.into());
-                w.set_hpre(cfgr.ahb_pre.into());
-                w.set_ppre(cfgr.apb_pre.into());
-            });
-        }
-
-        let ahb_freq: u32 = match cfgr.ahb_pre {
-            AHBPrescaler::NotDivided => sys_clk,
-            pre => {
-                let pre: u8 = pre.into();
-                let pre = 1 << (pre as u32 - 7);
-                sys_clk / pre
-            }
-        };
-
-        let (apb_freq, apb_tim_freq) = match cfgr.apb_pre {
-            APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
-            pre => {
-                let pre: u8 = pre.into();
-                let pre: u8 = 1 << (pre - 3);
-                let freq = ahb_freq / pre as u32;
-                (freq, freq * 2)
-            }
-        };
-
-        let pwr = pac::PWR;
-        if cfgr.low_power_run {
-            assert!(sys_clk.hz() <= 2_000_000.hz());
-            unsafe {
-                pwr.cr1().modify(|w| w.set_lpr(true));
-            }
-        }
-
-        Clocks {
-            sys: sys_clk.hz(),
-            ahb: ahb_freq.hz(),
-            apb: apb_freq.hz(),
-            apb_tim: apb_tim_freq.hz(),
-        }
-    }
-}
-
 pub(crate) unsafe fn init(config: Config) {
-    let r = <peripherals::RCC as embassy::util::Steal>::steal();
-    let clocks = r.freeze(config);
-    set_freqs(clocks);
+    let (sys_clk, sw) = match config.mux {
+        ClockSrc::HSI16(div) => {
+            // Enable HSI16
+            let div: u8 = div.into();
+            RCC.cr().write(|w| {
+                w.set_hsidiv(div);
+                w.set_hsion(true)
+            });
+            while !RCC.cr().read().hsirdy() {}
+
+            (HSI_FREQ >> div, 0x00)
+        }
+        ClockSrc::HSE(freq) => {
+            // Enable HSE
+            RCC.cr().write(|w| w.set_hseon(true));
+            while !RCC.cr().read().hserdy() {}
+
+            (freq.0, 0x01)
+        }
+        ClockSrc::LSI => {
+            // Enable LSI
+            RCC.csr().write(|w| w.set_lsion(true));
+            while !RCC.csr().read().lsirdy() {}
+            (LSI_FREQ, 0x03)
+        }
+    };
+
+    RCC.cfgr().modify(|w| {
+        w.set_sw(sw.into());
+        w.set_hpre(config.ahb_pre.into());
+        w.set_ppre(config.apb_pre.into());
+    });
+
+    let ahb_freq: u32 = match config.ahb_pre {
+        AHBPrescaler::NotDivided => sys_clk,
+        pre => {
+            let pre: u8 = pre.into();
+            let pre = 1 << (pre as u32 - 7);
+            sys_clk / pre
+        }
+    };
+
+    let (apb_freq, apb_tim_freq) = match config.apb_pre {
+        APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
+        pre => {
+            let pre: u8 = pre.into();
+            let pre: u8 = 1 << (pre - 3);
+            let freq = ahb_freq / pre as u32;
+            (freq, freq * 2)
+        }
+    };
+
+    if config.low_power_run {
+        assert!(sys_clk.hz() <= 2_000_000.hz());
+        PWR.cr1().modify(|w| w.set_lpr(true));
+    }
+
+    set_freqs(Clocks {
+        sys: sys_clk.hz(),
+        ahb: ahb_freq.hz(),
+        apb: apb_freq.hz(),
+        apb_tim: apb_tim_freq.hz(),
+    });
 }
diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs
index ee49e2ece..ce8cca45d 100644
--- a/embassy-stm32/src/rcc/g4.rs
+++ b/embassy-stm32/src/rcc/g4.rs
@@ -1,11 +1,7 @@
-use crate::pac;
-use crate::peripherals::{self, RCC};
-use crate::rcc::{get_freqs, set_freqs, Clocks};
+use crate::pac::{PWR, RCC};
+use crate::rcc::{set_freqs, Clocks};
 use crate::time::Hertz;
 use crate::time::U32Ext;
-use core::marker::PhantomData;
-use embassy::util::Unborrow;
-use embassy_hal_common::unborrow;
 
 /// HSI speed
 pub const HSI_FREQ: u32 = 16_000_000;
@@ -94,117 +90,72 @@ impl Default for Config {
     }
 }
 
-/// RCC peripheral
-pub struct Rcc<'d> {
-    _rb: peripherals::RCC,
-    phantom: PhantomData<&'d mut peripherals::RCC>,
-}
-
-impl<'d> Rcc<'d> {
-    pub fn new(rcc: impl Unborrow<Target = peripherals::RCC> + 'd) -> Self {
-        unborrow!(rcc);
-        Self {
-            _rb: rcc,
-            phantom: PhantomData,
-        }
-    }
-
-    // Safety: RCC init must have been called
-    pub fn clocks(&self) -> &'static Clocks {
-        unsafe { get_freqs() }
-    }
-}
-
-/// Extension trait that freezes the `RCC` peripheral with provided clocks configuration
-pub trait RccExt {
-    fn freeze(self, config: Config) -> Clocks;
-}
-
-impl RccExt for RCC {
-    #[inline]
-    fn freeze(self, cfgr: Config) -> Clocks {
-        let rcc = pac::RCC;
-        let (sys_clk, sw) = match cfgr.mux {
-            ClockSrc::HSI16 => {
-                // Enable HSI16
-                unsafe {
-                    rcc.cr().write(|w| w.set_hsion(true));
-                    while !rcc.cr().read().hsirdy() {}
-                }
-
-                (HSI_FREQ, 0x01)
-            }
-            ClockSrc::HSE(freq) => {
-                // Enable HSE
-                unsafe {
-                    rcc.cr().write(|w| w.set_hseon(true));
-                    while !rcc.cr().read().hserdy() {}
-                }
-
-                (freq.0, 0x02)
-            }
-        };
-
-        unsafe {
-            rcc.cfgr().modify(|w| {
-                w.set_sw(sw.into());
-                w.set_hpre(cfgr.ahb_pre.into());
-                w.set_ppre1(cfgr.apb1_pre.into());
-                w.set_ppre2(cfgr.apb2_pre.into());
-            });
-        }
-
-        let ahb_freq: u32 = match cfgr.ahb_pre {
-            AHBPrescaler::NotDivided => sys_clk,
-            pre => {
-                let pre: u8 = pre.into();
-                let pre = 1 << (pre as u32 - 7);
-                sys_clk / pre
-            }
-        };
-
-        let (apb1_freq, apb1_tim_freq) = match cfgr.apb1_pre {
-            APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
-            pre => {
-                let pre: u8 = pre.into();
-                let pre: u8 = 1 << (pre - 3);
-                let freq = ahb_freq / pre as u32;
-                (freq, freq * 2)
-            }
-        };
-
-        let (apb2_freq, apb2_tim_freq) = match cfgr.apb2_pre {
-            APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
-            pre => {
-                let pre: u8 = pre.into();
-                let pre: u8 = 1 << (pre - 3);
-                let freq = ahb_freq / pre as u32;
-                (freq, freq * 2)
-            }
-        };
-
-        let pwr = pac::PWR;
-        if cfgr.low_power_run {
-            assert!(sys_clk.hz() <= 2_000_000.hz());
-            unsafe {
-                pwr.cr1().modify(|w| w.set_lpr(true));
-            }
-        }
-
-        Clocks {
-            sys: sys_clk.hz(),
-            ahb1: ahb_freq.hz(),
-            ahb2: ahb_freq.hz(),
-            apb1: apb1_freq.hz(),
-            apb1_tim: apb1_tim_freq.hz(),
-            apb2: apb2_freq.hz(),
-            apb2_tim: apb2_tim_freq.hz(),
-        }
-    }
-}
-
 pub(crate) unsafe fn init(config: Config) {
-    let r = <peripherals::RCC as embassy::util::Steal>::steal();
-    let clocks = r.freeze(config);
-    set_freqs(clocks);
+    let (sys_clk, sw) = match config.mux {
+        ClockSrc::HSI16 => {
+            // Enable HSI16
+            RCC.cr().write(|w| w.set_hsion(true));
+            while !RCC.cr().read().hsirdy() {}
+
+            (HSI_FREQ, 0x01)
+        }
+        ClockSrc::HSE(freq) => {
+            // Enable HSE
+            RCC.cr().write(|w| w.set_hseon(true));
+            while !RCC.cr().read().hserdy() {}
+
+            (freq.0, 0x02)
+        }
+    };
+
+    RCC.cfgr().modify(|w| {
+        w.set_sw(sw.into());
+        w.set_hpre(config.ahb_pre.into());
+        w.set_ppre1(config.apb1_pre.into());
+        w.set_ppre2(config.apb2_pre.into());
+    });
+
+    let ahb_freq: u32 = match config.ahb_pre {
+        AHBPrescaler::NotDivided => sys_clk,
+        pre => {
+            let pre: u8 = pre.into();
+            let pre = 1 << (pre as u32 - 7);
+            sys_clk / pre
+        }
+    };
+
+    let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
+        APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
+        pre => {
+            let pre: u8 = pre.into();
+            let pre: u8 = 1 << (pre - 3);
+            let freq = ahb_freq / pre as u32;
+            (freq, freq * 2)
+        }
+    };
+
+    let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
+        APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
+        pre => {
+            let pre: u8 = pre.into();
+            let pre: u8 = 1 << (pre - 3);
+            let freq = ahb_freq / pre as u32;
+            (freq, freq * 2)
+        }
+    };
+
+    if config.low_power_run {
+        assert!(sys_clk.hz() <= 2_000_000.hz());
+        PWR.cr1().modify(|w| w.set_lpr(true));
+    }
+
+    set_freqs(Clocks {
+        sys: sys_clk.hz(),
+        ahb1: ahb_freq.hz(),
+        ahb2: ahb_freq.hz(),
+        apb1: apb1_freq.hz(),
+        apb1_tim: apb1_tim_freq.hz(),
+        apb2: apb2_freq.hz(),
+        apb2_tim: apb2_tim_freq.hz(),
+    });
 }
diff --git a/embassy-stm32/src/rcc/h7.rs b/embassy-stm32/src/rcc/h7.rs
index ac4d033ba..55ddf073a 100644
--- a/embassy-stm32/src/rcc/h7.rs
+++ b/embassy-stm32/src/rcc/h7.rs
@@ -7,9 +7,9 @@ use stm32_metapac::rcc::vals::{Mco1, Mco2};
 use crate::gpio::sealed::Pin as __GpioPin;
 use crate::gpio::Pin;
 use crate::pac::rcc::vals::Timpre;
-use crate::pac::{RCC, SYSCFG};
+use crate::pac::rcc::vals::{Ckpersel, Dppre, Hpre, Hsebyp, Hsidiv, Pllsrc, Sw};
+use crate::pac::{PWR, RCC, SYSCFG};
 use crate::peripherals;
-use crate::pwr::{Power, VoltageScale};
 use crate::rcc::{set_freqs, Clocks};
 use crate::time::Hertz;
 
@@ -20,6 +20,22 @@ const CSI: Hertz = Hertz(4_000_000);
 const HSI48: Hertz = Hertz(48_000_000);
 const LSI: Hertz = Hertz(32_000);
 
+/// Voltage Scale
+///
+/// Represents the voltage range feeding the CPU core. The maximum core
+/// clock frequency depends on this value.
+#[derive(Copy, Clone, PartialEq)]
+pub enum VoltageScale {
+    /// VOS 0 range VCORE 1.26V - 1.40V
+    Scale0,
+    /// VOS 1 range VCORE 1.15V - 1.26V
+    Scale1,
+    /// VOS 2 range VCORE 1.05V - 1.15V
+    Scale2,
+    /// VOS 3 range VCORE 0.95V - 1.05V
+    Scale3,
+}
+
 /// Core clock frequencies
 #[derive(Clone, Copy)]
 pub struct CoreClocks {
@@ -72,439 +88,151 @@ pub struct Config {
     pub pll3: PllConfig,
 }
 
-pub struct Rcc<'d> {
-    inner: PhantomData<&'d ()>,
-    config: Config,
+/// Setup traceclk
+/// Returns a pll1_r_ck
+fn traceclk_setup(config: &mut Config, sys_use_pll1_p: bool) {
+    let pll1_r_ck = match (sys_use_pll1_p, config.pll1.r_ck) {
+        // pll1_p_ck selected as system clock but pll1_r_ck not
+        // set. The traceclk mux is synchronous with the system
+        // clock mux, but has pll1_r_ck as an input. In order to
+        // keep traceclk running, we force a pll1_r_ck.
+        (true, None) => Some(Hertz(unwrap!(config.pll1.p_ck).0 / 2)),
+
+        // Either pll1 not selected as system clock, free choice
+        // of pll1_r_ck. Or pll1 is selected, assume user has set
+        // a suitable pll1_r_ck frequency.
+        _ => config.pll1.r_ck,
+    };
+    config.pll1.r_ck = pll1_r_ck;
 }
 
-impl<'d> Rcc<'d> {
-    pub fn new(_rcc: impl Unborrow<Target = peripherals::RCC> + 'd, config: Config) -> Self {
-        Self {
-            inner: PhantomData,
-            config,
-        }
-    }
+/// Divider calculator for pclk 1 - 4
+///
+/// Returns real pclk, bits, ppre and the timer kernel clock
+fn ppre_calculate(
+    requested_pclk: u32,
+    hclk: u32,
+    max_pclk: u32,
+    tim_pre: Option<Timpre>,
+) -> (u32, u8, u8, Option<u32>) {
+    let (bits, ppre) = match (hclk + requested_pclk - 1) / requested_pclk {
+        0 => panic!(),
+        1 => (0b000, 1),
+        2 => (0b100, 2),
+        3..=5 => (0b101, 4),
+        6..=11 => (0b110, 8),
+        _ => (0b111, 16),
+    };
+    let real_pclk = hclk / u32::from(ppre);
+    assert!(real_pclk <= max_pclk);
 
-    /// Freeze the core clocks, returning a Core Clocks Distribution
-    /// and Reset (CCDR) structure. The actual frequency of the clocks
-    /// configured is returned in the `clocks` member of the CCDR
-    /// structure.
-    ///
-    /// Note that `freeze` will never result in a clock _faster_ than
-    /// that specified. It may result in a clock that is a factor of [1,
-    /// 2) slower.
-    ///
-    /// `syscfg` is required to enable the I/O compensation cell.
-    ///
-    /// # Panics
-    ///
-    /// If a clock specification cannot be achieved within the
-    /// hardware specification then this function will panic. This
-    /// function may also panic if a clock specification can be
-    /// achieved, but the mechanism for doing so is not yet
-    /// implemented here.
-    pub fn freeze(mut self, pwr: &Power) -> CoreClocks {
-        use crate::pac::rcc::vals::{Ckpersel, Dppre, Hpre, Hsebyp, Hsidiv, Pllsrc, Sw};
-
-        let srcclk = self.config.hse.unwrap_or(HSI); // Available clocks
-        let (sys_ck, sys_use_pll1_p) = self.sys_ck_setup(srcclk);
-
-        // Configure traceclk from PLL if needed
-        self.traceclk_setup(sys_use_pll1_p);
-
-        // NOTE(unsafe) We have exclusive access to the RCC
-        let (pll1_p_ck, pll1_q_ck, pll1_r_ck) =
-            unsafe { pll::pll_setup(srcclk.0, &self.config.pll1, 0) };
-        let (pll2_p_ck, pll2_q_ck, pll2_r_ck) =
-            unsafe { pll::pll_setup(srcclk.0, &self.config.pll2, 1) };
-        let (pll3_p_ck, pll3_q_ck, pll3_r_ck) =
-            unsafe { pll::pll_setup(srcclk.0, &self.config.pll3, 2) };
-
-        let sys_ck = if sys_use_pll1_p {
-            Hertz(unwrap!(pll1_p_ck)) // Must have been set by sys_ck_setup
-        } else {
-            sys_ck
+    let tim_ker_clk = if let Some(tim_pre) = tim_pre {
+        let clk = match (bits, tim_pre) {
+            (0b101, Timpre::DEFAULTX2) => hclk / 2,
+            (0b110, Timpre::DEFAULTX4) => hclk / 2,
+            (0b110, Timpre::DEFAULTX2) => hclk / 4,
+            (0b111, Timpre::DEFAULTX4) => hclk / 4,
+            (0b111, Timpre::DEFAULTX2) => hclk / 8,
+            _ => hclk,
         };
+        Some(clk)
+    } else {
+        None
+    };
+    (real_pclk, bits, ppre, tim_ker_clk)
+}
 
-        // NOTE(unsafe) We own the regblock
-        unsafe {
-            // This routine does not support HSIDIV != 1. To
-            // do so it would need to ensure all PLLxON bits are clear
-            // before changing the value of HSIDIV
-            let cr = RCC.cr().read();
-            assert!(cr.hsion());
-            assert!(cr.hsidiv() == Hsidiv::DIV1);
+/// Setup sys_ck
+/// Returns sys_ck frequency, and a pll1_p_ck
+fn sys_ck_setup(config: &mut Config, srcclk: Hertz) -> (Hertz, bool) {
+    // Compare available with wanted clocks
+    let sys_ck = config.sys_ck.unwrap_or(srcclk);
 
-            RCC.csr().modify(|w| w.set_lsion(true));
-            while !RCC.csr().read().lsirdy() {}
-        }
-
-        // per_ck from HSI by default
-        let (per_ck, ckpersel) = match (self.config.per_ck == self.config.hse, self.config.per_ck) {
-            (true, Some(hse)) => (hse, Ckpersel::HSE), // HSE
-            (_, Some(CSI)) => (CSI, Ckpersel::CSI),    // CSI
-            _ => (HSI, Ckpersel::HSI),                 // HSI
-        };
-
-        // D1 Core Prescaler
-        // Set to 1
-        let d1cpre_bits = 0;
-        let d1cpre_div = 1;
-        let sys_d1cpre_ck = sys_ck.0 / d1cpre_div;
-
-        // Refer to part datasheet "General operating conditions"
-        // table for (rev V). We do not assert checks for earlier
-        // revisions which may have lower limits.
-        let (sys_d1cpre_ck_max, rcc_hclk_max, pclk_max) = match pwr.vos {
-            VoltageScale::Scale0 => (480_000_000, 240_000_000, 120_000_000),
-            VoltageScale::Scale1 => (400_000_000, 200_000_000, 100_000_000),
-            VoltageScale::Scale2 => (300_000_000, 150_000_000, 75_000_000),
-            _ => (200_000_000, 100_000_000, 50_000_000),
-        };
-        assert!(sys_d1cpre_ck <= sys_d1cpre_ck_max);
-
-        let rcc_hclk = self
-            .config
-            .rcc_hclk
-            .map(|v| v.0)
-            .unwrap_or(sys_d1cpre_ck / 2);
-        assert!(rcc_hclk <= rcc_hclk_max);
-
-        // Estimate divisor
-        let (hpre_bits, hpre_div) = match (sys_d1cpre_ck + rcc_hclk - 1) / rcc_hclk {
-            0 => panic!(),
-            1 => (Hpre::DIV1, 1),
-            2 => (Hpre::DIV2, 2),
-            3..=5 => (Hpre::DIV4, 4),
-            6..=11 => (Hpre::DIV8, 8),
-            12..=39 => (Hpre::DIV16, 16),
-            40..=95 => (Hpre::DIV64, 64),
-            96..=191 => (Hpre::DIV128, 128),
-            192..=383 => (Hpre::DIV256, 256),
-            _ => (Hpre::DIV512, 512),
-        };
-        // Calculate real AXI and AHB clock
-        let rcc_hclk = sys_d1cpre_ck / hpre_div;
-        assert!(rcc_hclk <= rcc_hclk_max);
-        let rcc_aclk = rcc_hclk; // AXI clock is always equal to AHB clock on H7
-                                 // Timer prescaler selection
-        let timpre = Timpre::DEFAULTX2;
-
-        let requested_pclk1 = self
-            .config
-            .pclk1
-            .map(|v| v.0)
-            .unwrap_or_else(|| pclk_max.min(rcc_hclk / 2));
-        let (rcc_pclk1, ppre1_bits, ppre1, rcc_timerx_ker_ck) =
-            Self::ppre_calculate(requested_pclk1, rcc_hclk, pclk_max, Some(timpre));
-
-        let requested_pclk2 = self
-            .config
-            .pclk2
-            .map(|v| v.0)
-            .unwrap_or_else(|| pclk_max.min(rcc_hclk / 2));
-        let (rcc_pclk2, ppre2_bits, ppre2, rcc_timery_ker_ck) =
-            Self::ppre_calculate(requested_pclk2, rcc_hclk, pclk_max, Some(timpre));
-
-        let requested_pclk3 = self
-            .config
-            .pclk3
-            .map(|v| v.0)
-            .unwrap_or_else(|| pclk_max.min(rcc_hclk / 2));
-        let (rcc_pclk3, ppre3_bits, ppre3, _) =
-            Self::ppre_calculate(requested_pclk3, rcc_hclk, pclk_max, None);
-
-        let requested_pclk4 = self
-            .config
-            .pclk4
-            .map(|v| v.0)
-            .unwrap_or_else(|| pclk_max.min(rcc_hclk / 2));
-        let (rcc_pclk4, ppre4_bits, ppre4, _) =
-            Self::ppre_calculate(requested_pclk4, rcc_hclk, pclk_max, None);
-
-        Self::flash_setup(rcc_aclk, pwr.vos);
-
-        // Start switching clocks -------------------
-        // NOTE(unsafe) We have the RCC singleton
-        unsafe {
-            // Ensure CSI is on and stable
-            RCC.cr().modify(|w| w.set_csion(true));
-            while !RCC.cr().read().csirdy() {}
-
-            // Ensure HSI48 is on and stable
-            RCC.cr().modify(|w| w.set_hsi48on(true));
-            while !RCC.cr().read().hsi48on() {}
-
-            // XXX: support MCO ?
-
-            let hse_ck = match self.config.hse {
-                Some(hse) => {
-                    // Ensure HSE is on and stable
-                    RCC.cr().modify(|w| {
-                        w.set_hseon(true);
-                        w.set_hsebyp(if self.config.bypass_hse {
-                            Hsebyp::BYPASSED
-                        } else {
-                            Hsebyp::NOTBYPASSED
-                        });
-                    });
-                    while !RCC.cr().read().hserdy() {}
-                    Some(hse)
-                }
-                None => None,
-            };
-
-            let pllsrc = if self.config.hse.is_some() {
-                Pllsrc::HSE
-            } else {
-                Pllsrc::HSI
-            };
-            RCC.pllckselr().modify(|w| w.set_pllsrc(pllsrc));
-
-            let enable_pll = |pll| {
-                RCC.cr().modify(|w| w.set_pllon(pll, true));
-                while !RCC.cr().read().pllrdy(pll) {}
-            };
-
-            if pll1_p_ck.is_some() {
-                enable_pll(0);
-            }
-
-            if pll2_p_ck.is_some() {
-                enable_pll(1);
-            }
-
-            if pll3_p_ck.is_some() {
-                enable_pll(2);
-            }
-
-            // Core Prescaler / AHB Prescaler / APB3 Prescaler
-            RCC.d1cfgr().modify(|w| {
-                w.set_d1cpre(Hpre(d1cpre_bits));
-                w.set_d1ppre(Dppre(ppre3_bits));
-                w.set_hpre(hpre_bits)
-            });
-            // Ensure core prescaler value is valid before future lower
-            // core voltage
-            while RCC.d1cfgr().read().d1cpre().0 != d1cpre_bits {}
-
-            // APB1 / APB2 Prescaler
-            RCC.d2cfgr().modify(|w| {
-                w.set_d2ppre1(Dppre(ppre1_bits));
-                w.set_d2ppre2(Dppre(ppre2_bits));
-            });
-
-            // APB4 Prescaler
-            RCC.d3cfgr().modify(|w| w.set_d3ppre(Dppre(ppre4_bits)));
-
-            // Peripheral Clock (per_ck)
-            RCC.d1ccipr().modify(|w| w.set_ckpersel(ckpersel));
-
-            // Set timer clocks prescaler setting
-            RCC.cfgr().modify(|w| w.set_timpre(timpre));
-
-            // Select system clock source
-            let sw = match (sys_use_pll1_p, self.config.hse.is_some()) {
-                (true, _) => Sw::PLL1,
-                (false, true) => Sw::HSE,
-                _ => Sw::HSI,
-            };
-            RCC.cfgr().modify(|w| w.set_sw(sw));
-            while RCC.cfgr().read().sws() != sw.0 {}
-
-            // IO compensation cell - Requires CSI clock and SYSCFG
-            assert!(RCC.cr().read().csirdy());
-            RCC.apb4enr().modify(|w| w.set_syscfgen(true));
-
-            // Enable the compensation cell, using back-bias voltage code
-            // provide by the cell.
-            critical_section::with(|_| {
-                SYSCFG.cccsr().modify(|w| {
-                    w.set_en(true);
-                    w.set_cs(false);
-                    w.set_hslv(false);
-                })
-            });
-            while !SYSCFG.cccsr().read().ready() {}
-
-            CoreClocks {
-                hclk: Hertz(rcc_hclk),
-                pclk1: Hertz(rcc_pclk1),
-                pclk2: Hertz(rcc_pclk2),
-                pclk3: Hertz(rcc_pclk3),
-                pclk4: Hertz(rcc_pclk4),
-                ppre1,
-                ppre2,
-                ppre3,
-                ppre4,
-                csi_ck: Some(CSI),
-                hsi_ck: Some(HSI),
-                hsi48_ck: Some(HSI48),
-                lsi_ck: Some(LSI),
-                per_ck: Some(per_ck),
-                hse_ck,
-                pll1_p_ck: pll1_p_ck.map(Hertz),
-                pll1_q_ck: pll1_q_ck.map(Hertz),
-                pll1_r_ck: pll1_r_ck.map(Hertz),
-                pll2_p_ck: pll2_p_ck.map(Hertz),
-                pll2_q_ck: pll2_q_ck.map(Hertz),
-                pll2_r_ck: pll2_r_ck.map(Hertz),
-                pll3_p_ck: pll3_p_ck.map(Hertz),
-                pll3_q_ck: pll3_q_ck.map(Hertz),
-                pll3_r_ck: pll3_r_ck.map(Hertz),
-                timx_ker_ck: rcc_timerx_ker_ck.map(Hertz),
-                timy_ker_ck: rcc_timery_ker_ck.map(Hertz),
-                sys_ck,
-                c_ck: Hertz(sys_d1cpre_ck),
-            }
-        }
-    }
-
-    /// Setup traceclk
-    /// Returns a pll1_r_ck
-    fn traceclk_setup(&mut self, sys_use_pll1_p: bool) {
-        let pll1_r_ck = match (sys_use_pll1_p, self.config.pll1.r_ck) {
-            // pll1_p_ck selected as system clock but pll1_r_ck not
-            // set. The traceclk mux is synchronous with the system
-            // clock mux, but has pll1_r_ck as an input. In order to
-            // keep traceclk running, we force a pll1_r_ck.
-            (true, None) => Some(Hertz(unwrap!(self.config.pll1.p_ck).0 / 2)),
-
-            // Either pll1 not selected as system clock, free choice
-            // of pll1_r_ck. Or pll1 is selected, assume user has set
-            // a suitable pll1_r_ck frequency.
-            _ => self.config.pll1.r_ck,
-        };
-        self.config.pll1.r_ck = pll1_r_ck;
-    }
-
-    /// Divider calculator for pclk 1 - 4
-    ///
-    /// Returns real pclk, bits, ppre and the timer kernel clock
-    fn ppre_calculate(
-        requested_pclk: u32,
-        hclk: u32,
-        max_pclk: u32,
-        tim_pre: Option<Timpre>,
-    ) -> (u32, u8, u8, Option<u32>) {
-        let (bits, ppre) = match (hclk + requested_pclk - 1) / requested_pclk {
-            0 => panic!(),
-            1 => (0b000, 1),
-            2 => (0b100, 2),
-            3..=5 => (0b101, 4),
-            6..=11 => (0b110, 8),
-            _ => (0b111, 16),
-        };
-        let real_pclk = hclk / u32::from(ppre);
-        assert!(real_pclk <= max_pclk);
-
-        let tim_ker_clk = if let Some(tim_pre) = tim_pre {
-            let clk = match (bits, tim_pre) {
-                (0b101, Timpre::DEFAULTX2) => hclk / 2,
-                (0b110, Timpre::DEFAULTX4) => hclk / 2,
-                (0b110, Timpre::DEFAULTX2) => hclk / 4,
-                (0b111, Timpre::DEFAULTX4) => hclk / 4,
-                (0b111, Timpre::DEFAULTX2) => hclk / 8,
-                _ => hclk,
-            };
-            Some(clk)
-        } else {
-            None
-        };
-        (real_pclk, bits, ppre, tim_ker_clk)
-    }
-
-    /// Setup sys_ck
-    /// Returns sys_ck frequency, and a pll1_p_ck
-    fn sys_ck_setup(&mut self, srcclk: Hertz) -> (Hertz, bool) {
-        // Compare available with wanted clocks
-        let sys_ck = self.config.sys_ck.unwrap_or(srcclk);
-
-        if sys_ck != srcclk {
-            // The requested system clock is not the immediately available
-            // HSE/HSI clock. Perhaps there are other ways of obtaining
-            // the requested system clock (such as `HSIDIV`) but we will
-            // ignore those for now.
-            //
-            // Therefore we must use pll1_p_ck
-            let pll1_p_ck = match self.config.pll1.p_ck {
-                Some(p_ck) => {
-                    assert!(p_ck == sys_ck,
+    if sys_ck != srcclk {
+        // The requested system clock is not the immediately available
+        // HSE/HSI clock. Perhaps there are other ways of obtaining
+        // the requested system clock (such as `HSIDIV`) but we will
+        // ignore those for now.
+        //
+        // Therefore we must use pll1_p_ck
+        let pll1_p_ck = match config.pll1.p_ck {
+            Some(p_ck) => {
+                assert!(p_ck == sys_ck,
                             "Error: Cannot set pll1_p_ck independently as it must be used to generate sys_ck");
-                    Some(p_ck)
-                }
-                None => Some(sys_ck),
-            };
-            self.config.pll1.p_ck = pll1_p_ck;
-
-            (sys_ck, true)
-        } else {
-            // sys_ck is derived directly from a source clock
-            // (HSE/HSI). pll1_p_ck can be as requested
-            (sys_ck, false)
-        }
-    }
-
-    fn flash_setup(rcc_aclk: u32, vos: VoltageScale) {
-        use crate::pac::FLASH;
-
-        // ACLK in MHz, round down and subtract 1 from integers. eg.
-        // 61_999_999 -> 61MHz
-        // 62_000_000 -> 61MHz
-        // 62_000_001 -> 62MHz
-        let rcc_aclk_mhz = (rcc_aclk - 1) / 1_000_000;
-
-        // See RM0433 Rev 7 Table 17. FLASH recommended number of wait
-        // states and programming delay
-        let (wait_states, progr_delay) = match vos {
-            // VOS 0 range VCORE 1.26V - 1.40V
-            VoltageScale::Scale0 => match rcc_aclk_mhz {
-                0..=69 => (0, 0),
-                70..=139 => (1, 1),
-                140..=184 => (2, 1),
-                185..=209 => (2, 2),
-                210..=224 => (3, 2),
-                225..=239 => (4, 2),
-                _ => (7, 3),
-            },
-            // VOS 1 range VCORE 1.15V - 1.26V
-            VoltageScale::Scale1 => match rcc_aclk_mhz {
-                0..=69 => (0, 0),
-                70..=139 => (1, 1),
-                140..=184 => (2, 1),
-                185..=209 => (2, 2),
-                210..=224 => (3, 2),
-                _ => (7, 3),
-            },
-            // VOS 2 range VCORE 1.05V - 1.15V
-            VoltageScale::Scale2 => match rcc_aclk_mhz {
-                0..=54 => (0, 0),
-                55..=109 => (1, 1),
-                110..=164 => (2, 1),
-                165..=224 => (3, 2),
-                _ => (7, 3),
-            },
-            // VOS 3 range VCORE 0.95V - 1.05V
-            VoltageScale::Scale3 => match rcc_aclk_mhz {
-                0..=44 => (0, 0),
-                45..=89 => (1, 1),
-                90..=134 => (2, 1),
-                135..=179 => (3, 2),
-                180..=224 => (4, 2),
-                _ => (7, 3),
-            },
+                Some(p_ck)
+            }
+            None => Some(sys_ck),
         };
+        config.pll1.p_ck = pll1_p_ck;
 
-        // NOTE(unsafe) Atomic write
-        unsafe {
-            FLASH.acr().write(|w| {
-                w.set_wrhighfreq(progr_delay);
-                w.set_latency(wait_states)
-            });
-            while FLASH.acr().read().latency() != wait_states {}
-        }
+        (sys_ck, true)
+    } else {
+        // sys_ck is derived directly from a source clock
+        // (HSE/HSI). pll1_p_ck can be as requested
+        (sys_ck, false)
     }
 }
+
+fn flash_setup(rcc_aclk: u32, vos: VoltageScale) {
+    use crate::pac::FLASH;
+
+    // ACLK in MHz, round down and subtract 1 from integers. eg.
+    // 61_999_999 -> 61MHz
+    // 62_000_000 -> 61MHz
+    // 62_000_001 -> 62MHz
+    let rcc_aclk_mhz = (rcc_aclk - 1) / 1_000_000;
+
+    // See RM0433 Rev 7 Table 17. FLASH recommended number of wait
+    // states and programming delay
+    let (wait_states, progr_delay) = match vos {
+        // VOS 0 range VCORE 1.26V - 1.40V
+        VoltageScale::Scale0 => match rcc_aclk_mhz {
+            0..=69 => (0, 0),
+            70..=139 => (1, 1),
+            140..=184 => (2, 1),
+            185..=209 => (2, 2),
+            210..=224 => (3, 2),
+            225..=239 => (4, 2),
+            _ => (7, 3),
+        },
+        // VOS 1 range VCORE 1.15V - 1.26V
+        VoltageScale::Scale1 => match rcc_aclk_mhz {
+            0..=69 => (0, 0),
+            70..=139 => (1, 1),
+            140..=184 => (2, 1),
+            185..=209 => (2, 2),
+            210..=224 => (3, 2),
+            _ => (7, 3),
+        },
+        // VOS 2 range VCORE 1.05V - 1.15V
+        VoltageScale::Scale2 => match rcc_aclk_mhz {
+            0..=54 => (0, 0),
+            55..=109 => (1, 1),
+            110..=164 => (2, 1),
+            165..=224 => (3, 2),
+            _ => (7, 3),
+        },
+        // VOS 3 range VCORE 0.95V - 1.05V
+        VoltageScale::Scale3 => match rcc_aclk_mhz {
+            0..=44 => (0, 0),
+            45..=89 => (1, 1),
+            90..=134 => (2, 1),
+            135..=179 => (3, 2),
+            180..=224 => (4, 2),
+            _ => (7, 3),
+        },
+    };
+
+    // NOTE(unsafe) Atomic write
+    unsafe {
+        FLASH.acr().write(|w| {
+            w.set_wrhighfreq(progr_delay);
+            w.set_latency(wait_states)
+        });
+        while FLASH.acr().read().latency() != wait_states {}
+    }
+}
+
 pub enum McoClock {
     Disabled,
     Bypassed,
@@ -681,10 +409,309 @@ impl<'d, T: McoInstance> Mco<'d, T> {
     }
 }
 
-pub(crate) unsafe fn init(config: Config) {
-    let mut power = Power::new(<peripherals::PWR as embassy::util::Steal>::steal(), false);
-    let rcc = Rcc::new(<peripherals::RCC as embassy::util::Steal>::steal(), config);
-    let core_clocks = rcc.freeze(&mut power);
+pub(crate) unsafe fn init(mut config: Config) {
+    // TODO make configurable?
+    let enable_overdrive = false;
+
+    // NB. The lower bytes of CR3 can only be written once after
+    // POR, and must be written with a valid combination. Refer to
+    // RM0433 Rev 7 6.8.4. This is partially enforced by dropping
+    // `self` at the end of this method, but of course we cannot
+    // know what happened between the previous POR and here.
+    #[cfg(pwr_h7)]
+    PWR.cr3().modify(|w| {
+        w.set_scuen(true);
+        w.set_ldoen(true);
+        w.set_bypass(false);
+    });
+
+    #[cfg(pwr_h7smps)]
+    PWR.cr3().modify(|w| {
+        // hardcode "Direct SPMS" for now, this is what works on nucleos with the
+        // default solderbridge configuration.
+        w.set_sden(true);
+        w.set_ldoen(false);
+    });
+
+    // Validate the supply configuration. If you are stuck here, it is
+    // because the voltages on your board do not match those specified
+    // in the D3CR.VOS and CR3.SDLEVEL fields. By default after reset
+    // VOS = Scale 3, so check that the voltage on the VCAP pins =
+    // 1.0V.
+    while !PWR.csr1().read().actvosrdy() {}
+
+    // Go to Scale 1
+    PWR.d3cr().modify(|w| w.set_vos(0b11));
+    while !PWR.d3cr().read().vosrdy() {}
+
+    let pwr_vos = if !enable_overdrive {
+        VoltageScale::Scale1
+    } else {
+        critical_section::with(|_| {
+            RCC.apb4enr().modify(|w| w.set_syscfgen(true));
+
+            SYSCFG.pwrcr().modify(|w| w.set_oden(1));
+        });
+        while !PWR.d3cr().read().vosrdy() {}
+        VoltageScale::Scale0
+    };
+
+    // Freeze the core clocks, returning a Core Clocks Distribution
+    // and Reset (CCDR) structure. The actual frequency of the clocks
+    // configured is returned in the `clocks` member of the CCDR
+    // structure.
+    //
+    // Note that `freeze` will never result in a clock _faster_ than
+    // that specified. It may result in a clock that is a factor of [1,
+    // 2) slower.
+    //
+    // `syscfg` is required to enable the I/O compensation cell.
+    //
+    // # Panics
+    //
+    // If a clock specification cannot be achieved within the
+    // hardware specification then this function will panic. This
+    // function may also panic if a clock specification can be
+    // achieved, but the mechanism for doing so is not yet
+    // implemented here.
+
+    let srcclk = config.hse.unwrap_or(HSI); // Available clocks
+    let (sys_ck, sys_use_pll1_p) = sys_ck_setup(&mut config, srcclk);
+
+    // Configure traceclk from PLL if needed
+    traceclk_setup(&mut config, sys_use_pll1_p);
+
+    // NOTE(unsafe) We have exclusive access to the RCC
+    let (pll1_p_ck, pll1_q_ck, pll1_r_ck) = pll::pll_setup(srcclk.0, &config.pll1, 0);
+    let (pll2_p_ck, pll2_q_ck, pll2_r_ck) = pll::pll_setup(srcclk.0, &config.pll2, 1);
+    let (pll3_p_ck, pll3_q_ck, pll3_r_ck) = pll::pll_setup(srcclk.0, &config.pll3, 2);
+
+    let sys_ck = if sys_use_pll1_p {
+        Hertz(unwrap!(pll1_p_ck)) // Must have been set by sys_ck_setup
+    } else {
+        sys_ck
+    };
+
+    // This routine does not support HSIDIV != 1. To
+    // do so it would need to ensure all PLLxON bits are clear
+    // before changing the value of HSIDIV
+    let cr = RCC.cr().read();
+    assert!(cr.hsion());
+    assert!(cr.hsidiv() == Hsidiv::DIV1);
+
+    RCC.csr().modify(|w| w.set_lsion(true));
+    while !RCC.csr().read().lsirdy() {}
+
+    // per_ck from HSI by default
+    let (per_ck, ckpersel) = match (config.per_ck == config.hse, config.per_ck) {
+        (true, Some(hse)) => (hse, Ckpersel::HSE), // HSE
+        (_, Some(CSI)) => (CSI, Ckpersel::CSI),    // CSI
+        _ => (HSI, Ckpersel::HSI),                 // HSI
+    };
+
+    // D1 Core Prescaler
+    // Set to 1
+    let d1cpre_bits = 0;
+    let d1cpre_div = 1;
+    let sys_d1cpre_ck = sys_ck.0 / d1cpre_div;
+
+    // Refer to part datasheet "General operating conditions"
+    // table for (rev V). We do not assert checks for earlier
+    // revisions which may have lower limits.
+    let (sys_d1cpre_ck_max, rcc_hclk_max, pclk_max) = match pwr_vos {
+        VoltageScale::Scale0 => (480_000_000, 240_000_000, 120_000_000),
+        VoltageScale::Scale1 => (400_000_000, 200_000_000, 100_000_000),
+        VoltageScale::Scale2 => (300_000_000, 150_000_000, 75_000_000),
+        _ => (200_000_000, 100_000_000, 50_000_000),
+    };
+    assert!(sys_d1cpre_ck <= sys_d1cpre_ck_max);
+
+    let rcc_hclk = config.rcc_hclk.map(|v| v.0).unwrap_or(sys_d1cpre_ck / 2);
+    assert!(rcc_hclk <= rcc_hclk_max);
+
+    // Estimate divisor
+    let (hpre_bits, hpre_div) = match (sys_d1cpre_ck + rcc_hclk - 1) / rcc_hclk {
+        0 => panic!(),
+        1 => (Hpre::DIV1, 1),
+        2 => (Hpre::DIV2, 2),
+        3..=5 => (Hpre::DIV4, 4),
+        6..=11 => (Hpre::DIV8, 8),
+        12..=39 => (Hpre::DIV16, 16),
+        40..=95 => (Hpre::DIV64, 64),
+        96..=191 => (Hpre::DIV128, 128),
+        192..=383 => (Hpre::DIV256, 256),
+        _ => (Hpre::DIV512, 512),
+    };
+    // Calculate real AXI and AHB clock
+    let rcc_hclk = sys_d1cpre_ck / hpre_div;
+    assert!(rcc_hclk <= rcc_hclk_max);
+    let rcc_aclk = rcc_hclk; // AXI clock is always equal to AHB clock on H7
+                             // Timer prescaler selection
+    let timpre = Timpre::DEFAULTX2;
+
+    let requested_pclk1 = config
+        .pclk1
+        .map(|v| v.0)
+        .unwrap_or_else(|| pclk_max.min(rcc_hclk / 2));
+    let (rcc_pclk1, ppre1_bits, ppre1, rcc_timerx_ker_ck) =
+        ppre_calculate(requested_pclk1, rcc_hclk, pclk_max, Some(timpre));
+
+    let requested_pclk2 = config
+        .pclk2
+        .map(|v| v.0)
+        .unwrap_or_else(|| pclk_max.min(rcc_hclk / 2));
+    let (rcc_pclk2, ppre2_bits, ppre2, rcc_timery_ker_ck) =
+        ppre_calculate(requested_pclk2, rcc_hclk, pclk_max, Some(timpre));
+
+    let requested_pclk3 = config
+        .pclk3
+        .map(|v| v.0)
+        .unwrap_or_else(|| pclk_max.min(rcc_hclk / 2));
+    let (rcc_pclk3, ppre3_bits, ppre3, _) =
+        ppre_calculate(requested_pclk3, rcc_hclk, pclk_max, None);
+
+    let requested_pclk4 = config
+        .pclk4
+        .map(|v| v.0)
+        .unwrap_or_else(|| pclk_max.min(rcc_hclk / 2));
+    let (rcc_pclk4, ppre4_bits, ppre4, _) =
+        ppre_calculate(requested_pclk4, rcc_hclk, pclk_max, None);
+
+    flash_setup(rcc_aclk, pwr_vos);
+
+    // Start switching clocks -------------------
+
+    // Ensure CSI is on and stable
+    RCC.cr().modify(|w| w.set_csion(true));
+    while !RCC.cr().read().csirdy() {}
+
+    // Ensure HSI48 is on and stable
+    RCC.cr().modify(|w| w.set_hsi48on(true));
+    while !RCC.cr().read().hsi48on() {}
+
+    // XXX: support MCO ?
+
+    let hse_ck = match config.hse {
+        Some(hse) => {
+            // Ensure HSE is on and stable
+            RCC.cr().modify(|w| {
+                w.set_hseon(true);
+                w.set_hsebyp(if config.bypass_hse {
+                    Hsebyp::BYPASSED
+                } else {
+                    Hsebyp::NOTBYPASSED
+                });
+            });
+            while !RCC.cr().read().hserdy() {}
+            Some(hse)
+        }
+        None => None,
+    };
+
+    let pllsrc = if config.hse.is_some() {
+        Pllsrc::HSE
+    } else {
+        Pllsrc::HSI
+    };
+    RCC.pllckselr().modify(|w| w.set_pllsrc(pllsrc));
+
+    let enable_pll = |pll| {
+        RCC.cr().modify(|w| w.set_pllon(pll, true));
+        while !RCC.cr().read().pllrdy(pll) {}
+    };
+
+    if pll1_p_ck.is_some() {
+        enable_pll(0);
+    }
+
+    if pll2_p_ck.is_some() {
+        enable_pll(1);
+    }
+
+    if pll3_p_ck.is_some() {
+        enable_pll(2);
+    }
+
+    // Core Prescaler / AHB Prescaler / APB3 Prescaler
+    RCC.d1cfgr().modify(|w| {
+        w.set_d1cpre(Hpre(d1cpre_bits));
+        w.set_d1ppre(Dppre(ppre3_bits));
+        w.set_hpre(hpre_bits)
+    });
+    // Ensure core prescaler value is valid before future lower
+    // core voltage
+    while RCC.d1cfgr().read().d1cpre().0 != d1cpre_bits {}
+
+    // APB1 / APB2 Prescaler
+    RCC.d2cfgr().modify(|w| {
+        w.set_d2ppre1(Dppre(ppre1_bits));
+        w.set_d2ppre2(Dppre(ppre2_bits));
+    });
+
+    // APB4 Prescaler
+    RCC.d3cfgr().modify(|w| w.set_d3ppre(Dppre(ppre4_bits)));
+
+    // Peripheral Clock (per_ck)
+    RCC.d1ccipr().modify(|w| w.set_ckpersel(ckpersel));
+
+    // Set timer clocks prescaler setting
+    RCC.cfgr().modify(|w| w.set_timpre(timpre));
+
+    // Select system clock source
+    let sw = match (sys_use_pll1_p, config.hse.is_some()) {
+        (true, _) => Sw::PLL1,
+        (false, true) => Sw::HSE,
+        _ => Sw::HSI,
+    };
+    RCC.cfgr().modify(|w| w.set_sw(sw));
+    while RCC.cfgr().read().sws() != sw.0 {}
+
+    // IO compensation cell - Requires CSI clock and SYSCFG
+    assert!(RCC.cr().read().csirdy());
+    RCC.apb4enr().modify(|w| w.set_syscfgen(true));
+
+    // Enable the compensation cell, using back-bias voltage code
+    // provide by the cell.
+    critical_section::with(|_| {
+        SYSCFG.cccsr().modify(|w| {
+            w.set_en(true);
+            w.set_cs(false);
+            w.set_hslv(false);
+        })
+    });
+    while !SYSCFG.cccsr().read().ready() {}
+
+    let core_clocks = CoreClocks {
+        hclk: Hertz(rcc_hclk),
+        pclk1: Hertz(rcc_pclk1),
+        pclk2: Hertz(rcc_pclk2),
+        pclk3: Hertz(rcc_pclk3),
+        pclk4: Hertz(rcc_pclk4),
+        ppre1,
+        ppre2,
+        ppre3,
+        ppre4,
+        csi_ck: Some(CSI),
+        hsi_ck: Some(HSI),
+        hsi48_ck: Some(HSI48),
+        lsi_ck: Some(LSI),
+        per_ck: Some(per_ck),
+        hse_ck,
+        pll1_p_ck: pll1_p_ck.map(Hertz),
+        pll1_q_ck: pll1_q_ck.map(Hertz),
+        pll1_r_ck: pll1_r_ck.map(Hertz),
+        pll2_p_ck: pll2_p_ck.map(Hertz),
+        pll2_q_ck: pll2_q_ck.map(Hertz),
+        pll2_r_ck: pll2_r_ck.map(Hertz),
+        pll3_p_ck: pll3_p_ck.map(Hertz),
+        pll3_q_ck: pll3_q_ck.map(Hertz),
+        pll3_r_ck: pll3_r_ck.map(Hertz),
+        timx_ker_ck: rcc_timerx_ker_ck.map(Hertz),
+        timy_ker_ck: rcc_timery_ker_ck.map(Hertz),
+        sys_ck,
+        c_ck: Hertz(sys_d1cpre_ck),
+    };
+
     set_freqs(Clocks {
         sys: core_clocks.c_ck,
         ahb1: core_clocks.hclk,
diff --git a/embassy-stm32/src/rcc/l0.rs b/embassy-stm32/src/rcc/l0.rs
index fc70ef0ac..25daeedf0 100644
--- a/embassy-stm32/src/rcc/l0.rs
+++ b/embassy-stm32/src/rcc/l0.rs
@@ -1,18 +1,11 @@
-use crate::pac;
-use crate::peripherals::{self, CRS, RCC, SYSCFG};
-use crate::rcc::{get_freqs, set_freqs, Clocks};
+use crate::pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw};
+use crate::pac::{CRS, RCC, SYSCFG};
+use crate::rcc::{set_freqs, Clocks};
 use crate::time::Hertz;
 use crate::time::U32Ext;
-use core::marker::PhantomData;
-use embassy::util::Unborrow;
-use embassy_hal_common::unborrow;
-use pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw};
 
-/// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC,
-/// and with the addition of the init function to configure a system clock.
-
-/// HSI speed
-pub const HSI_FREQ: u32 = 16_000_000;
+/// HSI16 speed
+pub const HSI16_FREQ: u32 = 16_000_000;
 
 /// System clock mux source
 #[derive(Clone, Copy)]
@@ -104,9 +97,9 @@ pub enum PLLSource {
     HSE(Hertz),
 }
 
-impl Into<Pllmul> for PLLMul {
-    fn into(self) -> Pllmul {
-        match self {
+impl From<PLLMul> for Pllmul {
+    fn from(val: PLLMul) -> Pllmul {
+        match val {
             PLLMul::Mul3 => Pllmul::MUL3,
             PLLMul::Mul4 => Pllmul::MUL4,
             PLLMul::Mul6 => Pllmul::MUL6,
@@ -120,9 +113,9 @@ impl Into<Pllmul> for PLLMul {
     }
 }
 
-impl Into<Plldiv> for PLLDiv {
-    fn into(self) -> Plldiv {
-        match self {
+impl From<PLLDiv> for Plldiv {
+    fn from(val: PLLDiv) -> Plldiv {
+        match val {
             PLLDiv::Div2 => Plldiv::DIV2,
             PLLDiv::Div3 => Plldiv::DIV3,
             PLLDiv::Div4 => Plldiv::DIV4,
@@ -130,18 +123,18 @@ impl Into<Plldiv> for PLLDiv {
     }
 }
 
-impl Into<Pllsrc> for PLLSource {
-    fn into(self) -> Pllsrc {
-        match self {
+impl From<PLLSource> for Pllsrc {
+    fn from(val: PLLSource) -> Pllsrc {
+        match val {
             PLLSource::HSI16 => Pllsrc::HSI16,
             PLLSource::HSE(_) => Pllsrc::HSE,
         }
     }
 }
 
-impl Into<Ppre> for APBPrescaler {
-    fn into(self) -> Ppre {
-        match self {
+impl From<APBPrescaler> for Ppre {
+    fn from(val: APBPrescaler) -> Ppre {
+        match val {
             APBPrescaler::NotDivided => Ppre::DIV1,
             APBPrescaler::Div2 => Ppre::DIV2,
             APBPrescaler::Div4 => Ppre::DIV4,
@@ -151,9 +144,9 @@ impl Into<Ppre> for APBPrescaler {
     }
 }
 
-impl Into<Hpre> for AHBPrescaler {
-    fn into(self) -> Hpre {
-        match self {
+impl From<AHBPrescaler> for Hpre {
+    fn from(val: AHBPrescaler) -> Hpre {
+        match val {
             AHBPrescaler::NotDivided => Hpre::DIV1,
             AHBPrescaler::Div2 => Hpre::DIV2,
             AHBPrescaler::Div4 => Hpre::DIV4,
@@ -167,9 +160,9 @@ impl Into<Hpre> for AHBPrescaler {
     }
 }
 
-impl Into<Msirange> for MSIRange {
-    fn into(self) -> Msirange {
-        match self {
+impl From<MSIRange> for Msirange {
+    fn from(val: MSIRange) -> Msirange {
+        match val {
             MSIRange::Range0 => Msirange::RANGE0,
             MSIRange::Range1 => Msirange::RANGE1,
             MSIRange::Range2 => Msirange::RANGE2,
@@ -187,6 +180,7 @@ pub struct Config {
     pub ahb_pre: AHBPrescaler,
     pub apb1_pre: APBPrescaler,
     pub apb2_pre: APBPrescaler,
+    pub enable_hsi48: bool,
 }
 
 impl Default for Config {
@@ -197,241 +191,172 @@ impl Default for Config {
             ahb_pre: AHBPrescaler::NotDivided,
             apb1_pre: APBPrescaler::NotDivided,
             apb2_pre: APBPrescaler::NotDivided,
+            enable_hsi48: false,
         }
     }
 }
 
-/// RCC peripheral
-pub struct Rcc<'d> {
-    _rb: peripherals::RCC,
-    phantom: PhantomData<&'d mut peripherals::RCC>,
-}
-
-impl<'d> Rcc<'d> {
-    pub fn new(rcc: impl Unborrow<Target = peripherals::RCC> + 'd) -> Self {
-        unborrow!(rcc);
-        Self {
-            _rb: rcc,
-            phantom: PhantomData,
-        }
-    }
-
-    // Safety: RCC init must have been called
-    pub fn clocks(&self) -> &'static Clocks {
-        unsafe { get_freqs() }
-    }
-
-    pub fn enable_hsi48(&mut self, _syscfg: &mut SYSCFG, _crs: CRS) -> HSI48 {
-        let rcc = pac::RCC;
-        unsafe {
-            // Reset SYSCFG peripheral
-            rcc.apb2rstr().modify(|w| w.set_syscfgrst(true));
-            rcc.apb2rstr().modify(|w| w.set_syscfgrst(false));
-
-            // Enable SYSCFG peripheral
-            rcc.apb2enr().modify(|w| w.set_syscfgen(true));
-
-            // Reset CRS peripheral
-            rcc.apb1rstr().modify(|w| w.set_crsrst(true));
-            rcc.apb1rstr().modify(|w| w.set_crsrst(false));
-
-            // Enable CRS peripheral
-            rcc.apb1enr().modify(|w| w.set_crsen(true));
-
-            // Initialize CRS
-            let crs = pac::CRS;
-            crs.cfgr().write(|w|
-
-            // Select LSE as synchronization source
-            w.set_syncsrc(0b01));
-            crs.cr().modify(|w| {
-                w.set_autotrimen(true);
-                w.set_cen(true);
-            });
-
-            // Enable VREFINT reference for HSI48 oscillator
-            let syscfg = pac::SYSCFG;
-            syscfg.cfgr3().modify(|w| {
-                w.set_enref_hsi48(true);
-                w.set_en_vrefint(true);
-            });
-
-            // Select HSI48 as USB clock
-            rcc.ccipr().modify(|w| w.set_hsi48msel(true));
-
-            // Enable dedicated USB clock
-            rcc.crrcr().modify(|w| w.set_hsi48on(true));
-            while !rcc.crrcr().read().hsi48rdy() {}
-        }
-
-        HSI48(())
-    }
-}
-
-/// Extension trait that freezes the `RCC` peripheral with provided clocks configuration
-pub trait RccExt {
-    fn freeze(self, config: Config) -> Clocks;
-}
-
-impl RccExt for RCC {
-    // `cfgr` is almost always a constant, so make sure it can be constant-propagated properly by
-    // marking this function and all `Config` constructors and setters as `#[inline]`.
-    // This saves ~900 Bytes for the `pwr.rs` example.
-    #[inline]
-    fn freeze(self, cfgr: Config) -> Clocks {
-        let rcc = pac::RCC;
-        let (sys_clk, sw) = match cfgr.mux {
-            ClockSrc::MSI(range) => {
-                // Set MSI range
-                unsafe {
-                    rcc.icscr().write(|w| w.set_msirange(range.into()));
-                }
-
-                // Enable MSI
-                unsafe {
-                    rcc.cr().write(|w| w.set_msion(true));
-                    while !rcc.cr().read().msirdy() {}
-                }
-
-                let freq = 32_768 * (1 << (range as u8 + 1));
-                (freq, Sw::MSI)
-            }
-            ClockSrc::HSI16 => {
-                // Enable HSI16
-                unsafe {
-                    rcc.cr().write(|w| w.set_hsi16on(true));
-                    while !rcc.cr().read().hsi16rdyf() {}
-                }
-
-                (HSI_FREQ, Sw::HSI16)
-            }
-            ClockSrc::HSE(freq) => {
-                // Enable HSE
-                unsafe {
-                    rcc.cr().write(|w| w.set_hseon(true));
-                    while !rcc.cr().read().hserdy() {}
-                }
-
-                (freq.0, Sw::HSE)
-            }
-            ClockSrc::PLL(src, mul, div) => {
-                let freq = match src {
-                    PLLSource::HSE(freq) => {
-                        // Enable HSE
-                        unsafe {
-                            rcc.cr().write(|w| w.set_hseon(true));
-                            while !rcc.cr().read().hserdy() {}
-                        }
-                        freq.0
-                    }
-                    PLLSource::HSI16 => {
-                        // Enable HSI
-                        unsafe {
-                            rcc.cr().write(|w| w.set_hsi16on(true));
-                            while !rcc.cr().read().hsi16rdyf() {}
-                        }
-                        HSI_FREQ
-                    }
-                };
-
-                // Disable PLL
-                unsafe {
-                    rcc.cr().modify(|w| w.set_pllon(false));
-                    while rcc.cr().read().pllrdy() {}
-                }
-
-                let freq = match mul {
-                    PLLMul::Mul3 => freq * 3,
-                    PLLMul::Mul4 => freq * 4,
-                    PLLMul::Mul6 => freq * 6,
-                    PLLMul::Mul8 => freq * 8,
-                    PLLMul::Mul12 => freq * 12,
-                    PLLMul::Mul16 => freq * 16,
-                    PLLMul::Mul24 => freq * 24,
-                    PLLMul::Mul32 => freq * 32,
-                    PLLMul::Mul48 => freq * 48,
-                };
-
-                let freq = match div {
-                    PLLDiv::Div2 => freq / 2,
-                    PLLDiv::Div3 => freq / 3,
-                    PLLDiv::Div4 => freq / 4,
-                };
-                assert!(freq <= 32_u32.mhz().0);
-
-                unsafe {
-                    rcc.cfgr().write(move |w| {
-                        w.set_pllmul(mul.into());
-                        w.set_plldiv(div.into());
-                        w.set_pllsrc(src.into());
-                    });
-
-                    // Enable PLL
-                    rcc.cr().modify(|w| w.set_pllon(true));
-                    while !rcc.cr().read().pllrdy() {}
-                }
-
-                (freq, Sw::PLL)
-            }
-        };
-
-        unsafe {
-            rcc.cfgr().modify(|w| {
-                w.set_sw(sw.into());
-                w.set_hpre(cfgr.ahb_pre.into());
-                w.set_ppre1(cfgr.apb1_pre.into());
-                w.set_ppre2(cfgr.apb2_pre.into());
-            });
-        }
-
-        let ahb_freq: u32 = match cfgr.ahb_pre {
-            AHBPrescaler::NotDivided => sys_clk,
-            pre => {
-                let pre: Hpre = pre.into();
-                let pre = 1 << (pre.0 as u32 - 7);
-                sys_clk / pre
-            }
-        };
-
-        let (apb1_freq, apb1_tim_freq) = match cfgr.apb1_pre {
-            APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
-            pre => {
-                let pre: Ppre = pre.into();
-                let pre: u8 = 1 << (pre.0 - 3);
-                let freq = ahb_freq / pre as u32;
-                (freq, freq * 2)
-            }
-        };
-
-        let (apb2_freq, apb2_tim_freq) = match cfgr.apb2_pre {
-            APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
-            pre => {
-                let pre: Ppre = pre.into();
-                let pre: u8 = 1 << (pre.0 - 3);
-                let freq = ahb_freq / (1 << (pre as u8 - 3));
-                (freq, freq * 2)
-            }
-        };
-
-        Clocks {
-            sys: sys_clk.hz(),
-            ahb: ahb_freq.hz(),
-            apb1: apb1_freq.hz(),
-            apb2: apb2_freq.hz(),
-            apb1_tim: apb1_tim_freq.hz(),
-            apb2_tim: apb2_tim_freq.hz(),
-        }
-    }
-}
-
-/// Token that exists only, if the HSI48 clock has been enabled
-///
-/// You can get an instance of this struct by calling [`Rcc::enable_hsi48`].
-#[derive(Clone, Copy)]
-pub struct HSI48(());
-
 pub(crate) unsafe fn init(config: Config) {
-    let r = <peripherals::RCC as embassy::util::Steal>::steal();
-    let clocks = r.freeze(config);
-    set_freqs(clocks);
+    let (sys_clk, sw) = match config.mux {
+        ClockSrc::MSI(range) => {
+            // Set MSI range
+            RCC.icscr().write(|w| w.set_msirange(range.into()));
+
+            // Enable MSI
+            RCC.cr().write(|w| w.set_msion(true));
+            while !RCC.cr().read().msirdy() {}
+
+            let freq = 32_768 * (1 << (range as u8 + 1));
+            (freq, Sw::MSI)
+        }
+        ClockSrc::HSI16 => {
+            // Enable HSI16
+            RCC.cr().write(|w| w.set_hsi16on(true));
+            while !RCC.cr().read().hsi16rdyf() {}
+
+            (HSI16_FREQ, Sw::HSI16)
+        }
+        ClockSrc::HSE(freq) => {
+            // Enable HSE
+            RCC.cr().write(|w| w.set_hseon(true));
+            while !RCC.cr().read().hserdy() {}
+
+            (freq.0, Sw::HSE)
+        }
+        ClockSrc::PLL(src, mul, div) => {
+            let freq = match src {
+                PLLSource::HSE(freq) => {
+                    // Enable HSE
+                    RCC.cr().write(|w| w.set_hseon(true));
+                    while !RCC.cr().read().hserdy() {}
+                    freq.0
+                }
+                PLLSource::HSI16 => {
+                    // Enable HSI
+                    RCC.cr().write(|w| w.set_hsi16on(true));
+                    while !RCC.cr().read().hsi16rdyf() {}
+                    HSI16_FREQ
+                }
+            };
+
+            // Disable PLL
+            RCC.cr().modify(|w| w.set_pllon(false));
+            while RCC.cr().read().pllrdy() {}
+
+            let freq = match mul {
+                PLLMul::Mul3 => freq * 3,
+                PLLMul::Mul4 => freq * 4,
+                PLLMul::Mul6 => freq * 6,
+                PLLMul::Mul8 => freq * 8,
+                PLLMul::Mul12 => freq * 12,
+                PLLMul::Mul16 => freq * 16,
+                PLLMul::Mul24 => freq * 24,
+                PLLMul::Mul32 => freq * 32,
+                PLLMul::Mul48 => freq * 48,
+            };
+
+            let freq = match div {
+                PLLDiv::Div2 => freq / 2,
+                PLLDiv::Div3 => freq / 3,
+                PLLDiv::Div4 => freq / 4,
+            };
+            assert!(freq <= 32_u32.mhz().0);
+
+            RCC.cfgr().write(move |w| {
+                w.set_pllmul(mul.into());
+                w.set_plldiv(div.into());
+                w.set_pllsrc(src.into());
+            });
+
+            // Enable PLL
+            RCC.cr().modify(|w| w.set_pllon(true));
+            while !RCC.cr().read().pllrdy() {}
+
+            (freq, Sw::PLL)
+        }
+    };
+
+    RCC.cfgr().modify(|w| {
+        w.set_sw(sw);
+        w.set_hpre(config.ahb_pre.into());
+        w.set_ppre1(config.apb1_pre.into());
+        w.set_ppre2(config.apb2_pre.into());
+    });
+
+    let ahb_freq: u32 = match config.ahb_pre {
+        AHBPrescaler::NotDivided => sys_clk,
+        pre => {
+            let pre: Hpre = pre.into();
+            let pre = 1 << (pre.0 as u32 - 7);
+            sys_clk / pre
+        }
+    };
+
+    let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
+        APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
+        pre => {
+            let pre: Ppre = pre.into();
+            let pre: u8 = 1 << (pre.0 - 3);
+            let freq = ahb_freq / pre as u32;
+            (freq, freq * 2)
+        }
+    };
+
+    let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
+        APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
+        pre => {
+            let pre: Ppre = pre.into();
+            let pre: u8 = 1 << (pre.0 - 3);
+            let freq = ahb_freq / (1 << (pre as u8 - 3));
+            (freq, freq * 2)
+        }
+    };
+
+    if config.enable_hsi48 {
+        // Reset SYSCFG peripheral
+        RCC.apb2rstr().modify(|w| w.set_syscfgrst(true));
+        RCC.apb2rstr().modify(|w| w.set_syscfgrst(false));
+
+        // Enable SYSCFG peripheral
+        RCC.apb2enr().modify(|w| w.set_syscfgen(true));
+
+        // Reset CRS peripheral
+        RCC.apb1rstr().modify(|w| w.set_crsrst(true));
+        RCC.apb1rstr().modify(|w| w.set_crsrst(false));
+
+        // Enable CRS peripheral
+        RCC.apb1enr().modify(|w| w.set_crsen(true));
+
+        // Initialize CRS
+        CRS.cfgr().write(|w|
+
+        // Select LSE as synchronization source
+        w.set_syncsrc(0b01));
+        CRS.cr().modify(|w| {
+            w.set_autotrimen(true);
+            w.set_cen(true);
+        });
+
+        // Enable VREFINT reference for HSI48 oscillator
+        SYSCFG.cfgr3().modify(|w| {
+            w.set_enref_hsi48(true);
+            w.set_en_vrefint(true);
+        });
+
+        // Select HSI48 as USB clock
+        RCC.ccipr().modify(|w| w.set_hsi48msel(true));
+
+        // Enable dedicated USB clock
+        RCC.crrcr().modify(|w| w.set_hsi48on(true));
+        while !RCC.crrcr().read().hsi48rdy() {}
+    }
+
+    set_freqs(Clocks {
+        sys: sys_clk.hz(),
+        ahb: ahb_freq.hz(),
+        apb1: apb1_freq.hz(),
+        apb2: apb2_freq.hz(),
+        apb1_tim: apb1_tim_freq.hz(),
+        apb2_tim: apb2_tim_freq.hz(),
+    });
 }
diff --git a/embassy-stm32/src/rcc/l1.rs b/embassy-stm32/src/rcc/l1.rs
index 746433c12..517869ca4 100644
--- a/embassy-stm32/src/rcc/l1.rs
+++ b/embassy-stm32/src/rcc/l1.rs
@@ -1,13 +1,8 @@
-use crate::pac;
-use crate::peripherals::{self, RCC};
-use crate::rcc::{get_freqs, set_freqs, Clocks};
+use crate::pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw};
+use crate::pac::RCC;
+use crate::rcc::{set_freqs, Clocks};
 use crate::time::Hertz;
 use crate::time::U32Ext;
-use core::marker::PhantomData;
-use embassy::util::Unborrow;
-use embassy_hal_common::unborrow;
-
-/// Most of clock setup is copied from rcc/l0
 
 /// HSI speed
 pub const HSI_FREQ: u32 = 16_000_000;
@@ -16,6 +11,7 @@ pub const HSI_FREQ: u32 = 16_000_000;
 #[derive(Clone, Copy)]
 pub enum ClockSrc {
     MSI(MSIRange),
+    PLL(PLLSource, PLLMul, PLLDiv),
     HSE(Hertz),
     HSI,
 }
@@ -48,6 +44,28 @@ impl Default for MSIRange {
     }
 }
 
+/// PLL divider
+#[derive(Clone, Copy)]
+pub enum PLLDiv {
+    Div2,
+    Div3,
+    Div4,
+}
+
+/// PLL multiplier
+#[derive(Clone, Copy)]
+pub enum PLLMul {
+    Mul3,
+    Mul4,
+    Mul6,
+    Mul8,
+    Mul12,
+    Mul16,
+    Mul24,
+    Mul32,
+    Mul48,
+}
+
 /// AHB prescaler
 #[derive(Clone, Copy, PartialEq)]
 pub enum AHBPrescaler {
@@ -72,46 +90,86 @@ pub enum APBPrescaler {
     Div16,
 }
 
-type Ppre = u8;
-impl Into<Ppre> for APBPrescaler {
-    fn into(self) -> Ppre {
-        match self {
-            APBPrescaler::NotDivided => 0b000,
-            APBPrescaler::Div2 => 0b100,
-            APBPrescaler::Div4 => 0b101,
-            APBPrescaler::Div8 => 0b110,
-            APBPrescaler::Div16 => 0b111,
+/// PLL clock input source
+#[derive(Clone, Copy)]
+pub enum PLLSource {
+    HSI,
+    HSE(Hertz),
+}
+
+impl From<PLLMul> for Pllmul {
+    fn from(val: PLLMul) -> Pllmul {
+        match val {
+            PLLMul::Mul3 => Pllmul::MUL3,
+            PLLMul::Mul4 => Pllmul::MUL4,
+            PLLMul::Mul6 => Pllmul::MUL6,
+            PLLMul::Mul8 => Pllmul::MUL8,
+            PLLMul::Mul12 => Pllmul::MUL12,
+            PLLMul::Mul16 => Pllmul::MUL16,
+            PLLMul::Mul24 => Pllmul::MUL24,
+            PLLMul::Mul32 => Pllmul::MUL32,
+            PLLMul::Mul48 => Pllmul::MUL48,
         }
     }
 }
 
-type Hpre = u8;
-impl Into<Hpre> for AHBPrescaler {
-    fn into(self) -> Hpre {
-        match self {
-            AHBPrescaler::NotDivided => 0b0000,
-            AHBPrescaler::Div2 => 0b1000,
-            AHBPrescaler::Div4 => 0b1001,
-            AHBPrescaler::Div8 => 0b1010,
-            AHBPrescaler::Div16 => 0b1011,
-            AHBPrescaler::Div64 => 0b1100,
-            AHBPrescaler::Div128 => 0b1101,
-            AHBPrescaler::Div256 => 0b1110,
-            AHBPrescaler::Div512 => 0b1111,
+impl From<PLLDiv> for Plldiv {
+    fn from(val: PLLDiv) -> Plldiv {
+        match val {
+            PLLDiv::Div2 => Plldiv::DIV2,
+            PLLDiv::Div3 => Plldiv::DIV3,
+            PLLDiv::Div4 => Plldiv::DIV4,
         }
     }
 }
 
-impl Into<u8> for MSIRange {
-    fn into(self) -> u8 {
-        match self {
-            MSIRange::Range0 => 0b000,
-            MSIRange::Range1 => 0b001,
-            MSIRange::Range2 => 0b010,
-            MSIRange::Range3 => 0b011,
-            MSIRange::Range4 => 0b100,
-            MSIRange::Range5 => 0b101,
-            MSIRange::Range6 => 0b110,
+impl From<PLLSource> for Pllsrc {
+    fn from(val: PLLSource) -> Pllsrc {
+        match val {
+            PLLSource::HSI => Pllsrc::HSI,
+            PLLSource::HSE(_) => Pllsrc::HSE,
+        }
+    }
+}
+
+impl From<APBPrescaler> for Ppre {
+    fn from(val: APBPrescaler) -> Ppre {
+        match val {
+            APBPrescaler::NotDivided => Ppre::DIV1,
+            APBPrescaler::Div2 => Ppre::DIV2,
+            APBPrescaler::Div4 => Ppre::DIV4,
+            APBPrescaler::Div8 => Ppre::DIV8,
+            APBPrescaler::Div16 => Ppre::DIV16,
+        }
+    }
+}
+
+impl From<AHBPrescaler> for Hpre {
+    fn from(val: AHBPrescaler) -> Hpre {
+        match val {
+            AHBPrescaler::NotDivided => Hpre::DIV1,
+            AHBPrescaler::Div2 => Hpre::DIV2,
+            AHBPrescaler::Div4 => Hpre::DIV4,
+            AHBPrescaler::Div8 => Hpre::DIV8,
+            AHBPrescaler::Div16 => Hpre::DIV16,
+            AHBPrescaler::Div64 => Hpre::DIV64,
+            AHBPrescaler::Div128 => Hpre::DIV128,
+            AHBPrescaler::Div256 => Hpre::DIV256,
+            AHBPrescaler::Div512 => Hpre::DIV512,
+        }
+    }
+}
+
+impl From<MSIRange> for Msirange {
+    fn from(val: MSIRange) -> Msirange {
+        match val {
+            MSIRange::Range0 => Msirange::RANGE0,
+            MSIRange::Range1 => Msirange::RANGE1,
+            MSIRange::Range2 => Msirange::RANGE2,
+            MSIRange::Range3 => Msirange::RANGE3,
+            MSIRange::Range4 => Msirange::RANGE4,
+            MSIRange::Range5 => Msirange::RANGE5,
+            MSIRange::Range6 => Msirange::RANGE6,
         }
     }
 }
@@ -136,126 +194,128 @@ impl Default for Config {
     }
 }
 
-/// RCC peripheral
-pub struct Rcc<'d> {
-    _rb: peripherals::RCC,
-    phantom: PhantomData<&'d mut peripherals::RCC>,
-}
-
-impl<'d> Rcc<'d> {
-    pub fn new(rcc: impl Unborrow<Target = peripherals::RCC> + 'd) -> Self {
-        unborrow!(rcc);
-        Self {
-            _rb: rcc,
-            phantom: PhantomData,
-        }
-    }
-
-    // Safety: RCC init must have been called
-    pub fn clocks(&self) -> &'static Clocks {
-        unsafe { get_freqs() }
-    }
-}
-
-/// Extension trait that freezes the `RCC` peripheral with provided clocks configuration
-pub trait RccExt {
-    fn freeze(self, config: Config) -> Clocks;
-}
-
-impl RccExt for RCC {
-    // `cfgr` is almost always a constant, so make sure it can be constant-propagated properly by
-    // marking this function and all `Config` constructors and setters as `#[inline]`.
-    // This saves ~900 Bytes for the `pwr.rs` example.
-    #[inline]
-    fn freeze(self, cfgr: Config) -> Clocks {
-        let rcc = pac::RCC;
-        let (sys_clk, sw) = match cfgr.mux {
-            ClockSrc::MSI(range) => {
-                // Set MSI range
-                unsafe {
-                    rcc.icscr().write(|w| w.set_msirange(range.into()));
-                }
-
-                // Enable MSI
-                unsafe {
-                    rcc.cr().write(|w| w.set_msion(true));
-                    while !rcc.cr().read().msirdy() {}
-                }
-
-                let freq = 32_768 * (1 << (range as u8 + 1));
-                (freq, 0b00)
-            }
-            ClockSrc::HSI => {
-                // Enable HSI
-                unsafe {
-                    rcc.cr().write(|w| w.set_hsion(true));
-                    while !rcc.cr().read().hsirdy() {}
-                }
-
-                (HSI_FREQ, 0b01)
-            }
-            ClockSrc::HSE(freq) => {
-                // Enable HSE
-                unsafe {
-                    rcc.cr().write(|w| w.set_hseon(true));
-                    while !rcc.cr().read().hserdy() {}
-                }
-
-                (freq.0, 0b10)
-            }
-        };
-
-        unsafe {
-            rcc.cfgr().modify(|w| {
-                w.set_sw(sw.into());
-                w.set_hpre(cfgr.ahb_pre.into());
-                w.set_ppre1(cfgr.apb1_pre.into());
-                w.set_ppre2(cfgr.apb2_pre.into());
-            });
-        }
-
-        let ahb_freq: u32 = match cfgr.ahb_pre {
-            AHBPrescaler::NotDivided => sys_clk,
-            pre => {
-                let pre: Hpre = pre.into();
-                let pre = 1 << (pre as u32 - 7);
-                sys_clk / pre
-            }
-        };
-
-        let (apb1_freq, apb1_tim_freq) = match cfgr.apb1_pre {
-            APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
-            pre => {
-                let pre: Ppre = pre.into();
-                let pre: u8 = 1 << (pre - 3);
-                let freq = ahb_freq / pre as u32;
-                (freq, freq * 2)
-            }
-        };
-
-        let (apb2_freq, apb2_tim_freq) = match cfgr.apb2_pre {
-            APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
-            pre => {
-                let pre: Ppre = pre.into();
-                let pre: u8 = 1 << (pre - 3);
-                let freq = ahb_freq / (1 << (pre as u8 - 3));
-                (freq, freq * 2)
-            }
-        };
-
-        Clocks {
-            sys: sys_clk.hz(),
-            ahb: ahb_freq.hz(),
-            apb1: apb1_freq.hz(),
-            apb2: apb2_freq.hz(),
-            apb1_tim: apb1_tim_freq.hz(),
-            apb2_tim: apb2_tim_freq.hz(),
-        }
-    }
-}
-
 pub(crate) unsafe fn init(config: Config) {
-    let r = <peripherals::RCC as embassy::util::Steal>::steal();
-    let clocks = r.freeze(config);
-    set_freqs(clocks);
+    let (sys_clk, sw) = match config.mux {
+        ClockSrc::MSI(range) => {
+            // Set MSI range
+            RCC.icscr().write(|w| w.set_msirange(range.into()));
+
+            // Enable MSI
+            RCC.cr().write(|w| w.set_msion(true));
+            while !RCC.cr().read().msirdy() {}
+
+            let freq = 32_768 * (1 << (range as u8 + 1));
+            (freq, Sw::MSI)
+        }
+        ClockSrc::HSI => {
+            // Enable HSI
+            RCC.cr().write(|w| w.set_hsion(true));
+            while !RCC.cr().read().hsirdy() {}
+
+            (HSI_FREQ, Sw::HSI)
+        }
+        ClockSrc::HSE(freq) => {
+            // Enable HSE
+            RCC.cr().write(|w| w.set_hseon(true));
+            while !RCC.cr().read().hserdy() {}
+
+            (freq.0, Sw::HSE)
+        }
+        ClockSrc::PLL(src, mul, div) => {
+            let freq = match src {
+                PLLSource::HSE(freq) => {
+                    // Enable HSE
+                    RCC.cr().write(|w| w.set_hseon(true));
+                    while !RCC.cr().read().hserdy() {}
+                    freq.0
+                }
+                PLLSource::HSI => {
+                    // Enable HSI
+                    RCC.cr().write(|w| w.set_hsion(true));
+                    while !RCC.cr().read().hsirdy() {}
+                    HSI_FREQ
+                }
+            };
+
+            // Disable PLL
+            RCC.cr().modify(|w| w.set_pllon(false));
+            while RCC.cr().read().pllrdy() {}
+
+            let freq = match mul {
+                PLLMul::Mul3 => freq * 3,
+                PLLMul::Mul4 => freq * 4,
+                PLLMul::Mul6 => freq * 6,
+                PLLMul::Mul8 => freq * 8,
+                PLLMul::Mul12 => freq * 12,
+                PLLMul::Mul16 => freq * 16,
+                PLLMul::Mul24 => freq * 24,
+                PLLMul::Mul32 => freq * 32,
+                PLLMul::Mul48 => freq * 48,
+            };
+
+            let freq = match div {
+                PLLDiv::Div2 => freq / 2,
+                PLLDiv::Div3 => freq / 3,
+                PLLDiv::Div4 => freq / 4,
+            };
+            assert!(freq <= 32_u32.mhz().0);
+
+            RCC.cfgr().write(move |w| {
+                w.set_pllmul(mul.into());
+                w.set_plldiv(div.into());
+                w.set_pllsrc(src.into());
+            });
+
+            // Enable PLL
+            RCC.cr().modify(|w| w.set_pllon(true));
+            while !RCC.cr().read().pllrdy() {}
+
+            (freq, Sw::PLL)
+        }
+    };
+
+    RCC.cfgr().modify(|w| {
+        w.set_sw(sw);
+        w.set_hpre(config.ahb_pre.into());
+        w.set_ppre1(config.apb1_pre.into());
+        w.set_ppre2(config.apb2_pre.into());
+    });
+
+    let ahb_freq: u32 = match config.ahb_pre {
+        AHBPrescaler::NotDivided => sys_clk,
+        pre => {
+            let pre: Hpre = pre.into();
+            let pre = 1 << (pre.0 as u32 - 7);
+            sys_clk / pre
+        }
+    };
+
+    let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
+        APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
+        pre => {
+            let pre: Ppre = pre.into();
+            let pre: u8 = 1 << (pre.0 - 3);
+            let freq = ahb_freq / pre as u32;
+            (freq, freq * 2)
+        }
+    };
+
+    let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
+        APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
+        pre => {
+            let pre: Ppre = pre.into();
+            let pre: u8 = 1 << (pre.0 - 3);
+            let freq = ahb_freq / (1 << (pre as u8 - 3));
+            (freq, freq * 2)
+        }
+    };
+
+    set_freqs(Clocks {
+        sys: sys_clk.hz(),
+        ahb: ahb_freq.hz(),
+        apb1: apb1_freq.hz(),
+        apb2: apb2_freq.hz(),
+        apb1_tim: apb1_tim_freq.hz(),
+        apb2_tim: apb2_tim_freq.hz(),
+    });
 }
diff --git a/embassy-stm32/src/rcc/l4.rs b/embassy-stm32/src/rcc/l4.rs
index 510cbddfa..68b960d7c 100644
--- a/embassy-stm32/src/rcc/l4.rs
+++ b/embassy-stm32/src/rcc/l4.rs
@@ -1,17 +1,8 @@
-use crate::pac;
-use crate::peripherals::{self, RCC};
-use crate::rcc::{get_freqs, set_freqs, Clocks};
+use crate::pac::rcc::vals::{Hpre, Msirange, Pllsrc, Ppre, Sw};
+use crate::pac::{FLASH, RCC};
+use crate::rcc::{set_freqs, Clocks};
 use crate::time::Hertz;
 use crate::time::U32Ext;
-use core::marker::PhantomData;
-use embassy::util::Unborrow;
-use embassy_hal_common::unborrow;
-use stm32_metapac::rcc::vals::Msirange;
-
-/// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC,
-/// and with the addition of the init function to configure a system clock.
-
-/// Only the basic setup using the HSE and HSI clocks are supported as of now.
 
 /// HSI16 speed
 pub const HSI16_FREQ: u32 = 16_000_000;
@@ -19,8 +10,8 @@ pub const HSI16_FREQ: u32 = 16_000_000;
 /// System clock mux source
 #[derive(Clone, Copy)]
 pub enum ClockSrc {
-    PLL(PLLSource, PLLClkDiv, PLLSrcDiv, PLLMul, Option<PLL48Div>),
     MSI(MSIRange),
+    PLL(PLLSource, PLLClkDiv, PLLSrcDiv, PLLMul, Option<PLL48Div>),
     HSE(Hertz),
     HSI16,
 }
@@ -57,25 +48,6 @@ pub enum MSIRange {
     Range11,
 }
 
-impl Into<u32> for MSIRange {
-    fn into(self) -> u32 {
-        match self {
-            MSIRange::Range0 => 100_000,
-            MSIRange::Range1 => 200_000,
-            MSIRange::Range2 => 400_000,
-            MSIRange::Range3 => 800_000,
-            MSIRange::Range4 => 1_000_000,
-            MSIRange::Range5 => 2_000_000,
-            MSIRange::Range6 => 4_000_000,
-            MSIRange::Range7 => 8_000_000,
-            MSIRange::Range8 => 16_000_000,
-            MSIRange::Range9 => 24_000_000,
-            MSIRange::Range10 => 32_000_000,
-            MSIRange::Range11 => 48_000_000,
-        }
-    }
-}
-
 impl Default for MSIRange {
     fn default() -> MSIRange {
         MSIRange::Range6
@@ -131,9 +103,9 @@ seq_macro::seq!(N in 8..=86 {
         )*
     }
 
-    impl Into<u8> for PLLMul {
-        fn into(self) -> u8 {
-            match self {
+    impl From<PLLMul> for u8 {
+        fn from(val: PLLMul) -> u8 {
+            match val {
                 #(
                     PLLMul::Mul#N => N,
                 )*
@@ -163,13 +135,13 @@ pub enum PLLClkDiv {
 impl PLLClkDiv {
     pub fn to_div(self) -> u32 {
         let val: u8 = self.into();
-        val as u32 + 1 * 2
+        (val as u32 + 1) * 2
     }
 }
 
-impl Into<u8> for PLLClkDiv {
-    fn into(self) -> u8 {
-        match self {
+impl From<PLLClkDiv> for u8 {
+    fn from(val: PLLClkDiv) -> u8 {
+        match val {
             PLLClkDiv::Div2 => 0b00,
             PLLClkDiv::Div4 => 0b01,
             PLLClkDiv::Div6 => 0b10,
@@ -197,9 +169,9 @@ impl PLLSrcDiv {
     }
 }
 
-impl Into<u8> for PLLSrcDiv {
-    fn into(self) -> u8 {
-        match self {
+impl From<PLLSrcDiv> for u8 {
+    fn from(val: PLLSrcDiv) -> u8 {
+        match val {
             PLLSrcDiv::Div1 => 0b000,
             PLLSrcDiv::Div2 => 0b001,
             PLLSrcDiv::Div3 => 0b010,
@@ -212,18 +184,46 @@ impl Into<u8> for PLLSrcDiv {
     }
 }
 
-impl Into<u8> for PLLSource {
-    fn into(self) -> u8 {
-        match self {
-            PLLSource::HSI16 => 0b10,
-            PLLSource::HSE(_) => 0b11,
+impl From<PLLSource> for Pllsrc {
+    fn from(val: PLLSource) -> Pllsrc {
+        match val {
+            PLLSource::HSI16 => Pllsrc::HSI16,
+            PLLSource::HSE(_) => Pllsrc::HSE,
         }
     }
 }
 
-impl Into<Msirange> for MSIRange {
-    fn into(self) -> Msirange {
-        match self {
+impl From<APBPrescaler> for Ppre {
+    fn from(val: APBPrescaler) -> Ppre {
+        match val {
+            APBPrescaler::NotDivided => Ppre::DIV1,
+            APBPrescaler::Div2 => Ppre::DIV2,
+            APBPrescaler::Div4 => Ppre::DIV4,
+            APBPrescaler::Div8 => Ppre::DIV8,
+            APBPrescaler::Div16 => Ppre::DIV16,
+        }
+    }
+}
+
+impl From<AHBPrescaler> for Hpre {
+    fn from(val: AHBPrescaler) -> Hpre {
+        match val {
+            AHBPrescaler::NotDivided => Hpre::DIV1,
+            AHBPrescaler::Div2 => Hpre::DIV2,
+            AHBPrescaler::Div4 => Hpre::DIV4,
+            AHBPrescaler::Div8 => Hpre::DIV8,
+            AHBPrescaler::Div16 => Hpre::DIV16,
+            AHBPrescaler::Div64 => Hpre::DIV64,
+            AHBPrescaler::Div128 => Hpre::DIV128,
+            AHBPrescaler::Div256 => Hpre::DIV256,
+            AHBPrescaler::Div512 => Hpre::DIV512,
+        }
+    }
+}
+
+impl From<MSIRange> for Msirange {
+    fn from(val: MSIRange) -> Msirange {
+        match val {
             MSIRange::Range0 => Msirange::RANGE100K,
             MSIRange::Range1 => Msirange::RANGE200K,
             MSIRange::Range2 => Msirange::RANGE400K,
@@ -239,30 +239,22 @@ impl Into<Msirange> for MSIRange {
         }
     }
 }
-impl Into<u8> for APBPrescaler {
-    fn into(self) -> u8 {
-        match self {
-            APBPrescaler::NotDivided => 1,
-            APBPrescaler::Div2 => 0x04,
-            APBPrescaler::Div4 => 0x05,
-            APBPrescaler::Div8 => 0x06,
-            APBPrescaler::Div16 => 0x07,
-        }
-    }
-}
 
-impl Into<u8> for AHBPrescaler {
-    fn into(self) -> u8 {
-        match self {
-            AHBPrescaler::NotDivided => 1,
-            AHBPrescaler::Div2 => 0x08,
-            AHBPrescaler::Div4 => 0x09,
-            AHBPrescaler::Div8 => 0x0a,
-            AHBPrescaler::Div16 => 0x0b,
-            AHBPrescaler::Div64 => 0x0c,
-            AHBPrescaler::Div128 => 0x0d,
-            AHBPrescaler::Div256 => 0x0e,
-            AHBPrescaler::Div512 => 0x0f,
+impl From<MSIRange> for u32 {
+    fn from(val: MSIRange) -> u32 {
+        match val {
+            MSIRange::Range0 => 100_000,
+            MSIRange::Range1 => 200_000,
+            MSIRange::Range2 => 400_000,
+            MSIRange::Range3 => 800_000,
+            MSIRange::Range4 => 1_000_000,
+            MSIRange::Range5 => 2_000_000,
+            MSIRange::Range6 => 4_000_000,
+            MSIRange::Range7 => 8_000_000,
+            MSIRange::Range8 => 16_000_000,
+            MSIRange::Range9 => 24_000_000,
+            MSIRange::Range10 => 32_000_000,
+            MSIRange::Range11 => 48_000_000,
         }
     }
 }
@@ -287,203 +279,151 @@ impl Default for Config {
     }
 }
 
-/// RCC peripheral
-pub struct Rcc<'d> {
-    _rb: peripherals::RCC,
-    phantom: PhantomData<&'d mut peripherals::RCC>,
-}
-
-impl<'d> Rcc<'d> {
-    pub fn new(rcc: impl Unborrow<Target = peripherals::RCC> + 'd) -> Self {
-        unborrow!(rcc);
-        Self {
-            _rb: rcc,
-            phantom: PhantomData,
-        }
-    }
-
-    // Safety: RCC init must have been called
-    pub fn clocks(&self) -> &'static Clocks {
-        unsafe { get_freqs() }
-    }
-}
-
-/// Extension trait that freezes the `RCC` peripheral with provided clocks configuration
-pub trait RccExt {
-    fn freeze(self, config: Config) -> Clocks;
-}
-
-impl RccExt for RCC {
-    #[inline]
-    fn freeze(self, cfgr: Config) -> Clocks {
-        let rcc = pac::RCC;
-        let (sys_clk, sw) = match cfgr.mux {
-            ClockSrc::HSI16 => {
-                // Enable HSI16
-                unsafe {
-                    rcc.cr().write(|w| w.set_hsion(true));
-                    while !rcc.cr().read().hsirdy() {}
-                }
-
-                (HSI16_FREQ, 0b01)
-            }
-            ClockSrc::HSE(freq) => {
-                // Enable HSE
-                unsafe {
-                    rcc.cr().write(|w| w.set_hseon(true));
-                    while !rcc.cr().read().hserdy() {}
-                }
-
-                (freq.0, 0b10)
-            }
-            ClockSrc::MSI(range) => {
-                // Enable MSI
-                unsafe {
-                    rcc.cr().write(|w| {
-                        let bits: Msirange = range.into();
-                        w.set_msirange(bits);
-                        w.set_msipllen(false);
-                        w.set_msirgsel(true);
-                        w.set_msion(true);
-                    });
-                    while !rcc.cr().read().msirdy() {}
-
-                    // Enable as clock source for USB, RNG if running at 48 MHz
-                    if let MSIRange::Range11 = range {
-                        rcc.ccipr().modify(|w| {
-                            w.set_clk48sel(0b11);
-                        });
-                    }
-                }
-                (range.into(), 0b00)
-            }
-            ClockSrc::PLL(src, div, prediv, mul, pll48div) => {
-                let freq = match src {
-                    PLLSource::HSE(freq) => {
-                        // Enable HSE
-                        unsafe {
-                            rcc.cr().write(|w| w.set_hseon(true));
-                            while !rcc.cr().read().hserdy() {}
-                        }
-                        freq.0
-                    }
-                    PLLSource::HSI16 => {
-                        // Enable HSI
-                        unsafe {
-                            rcc.cr().write(|w| w.set_hsion(true));
-                            while !rcc.cr().read().hsirdy() {}
-                        }
-                        HSI16_FREQ
-                    }
-                };
-
-                // Disable PLL
-                unsafe {
-                    rcc.cr().modify(|w| w.set_pllon(false));
-                    while rcc.cr().read().pllrdy() {}
-                }
-
-                let freq = (freq / prediv.to_div() * mul.to_mul()) / div.to_div();
-
-                assert!(freq <= 80_000_000);
-
-                unsafe {
-                    rcc.pllcfgr().write(move |w| {
-                        w.set_plln(mul.into());
-                        w.set_pllm(prediv.into());
-                        w.set_pllr(div.into());
-                        if let Some(pll48div) = pll48div {
-                            w.set_pllq(pll48div.into());
-                            w.set_pllqen(true);
-                        }
-                        w.set_pllsrc(src.into());
-                    });
-
-                    // Enable as clock source for USB, RNG if PLL48 divisor is provided
-                    if pll48div.is_some() {
-                        rcc.ccipr().modify(|w| {
-                            w.set_clk48sel(0b10);
-                        });
-                    }
-
-                    // Enable PLL
-                    rcc.cr().modify(|w| w.set_pllon(true));
-                    while !rcc.cr().read().pllrdy() {}
-                    rcc.pllcfgr().modify(|w| w.set_pllren(true));
-                }
-                (freq, 0b11)
-            }
-        };
-
-        unsafe {
-            // Set flash wait states
-            pac::FLASH.acr().modify(|w| {
-                w.set_latency(if sys_clk <= 16_000_000 {
-                    0b000
-                } else if sys_clk <= 32_000_000 {
-                    0b001
-                } else if sys_clk <= 48_000_000 {
-                    0b010
-                } else if sys_clk <= 64_000_000 {
-                    0b011
-                } else {
-                    0b100
-                });
-            });
-
-            // Switch active clocks to new clock source
-            rcc.cfgr().modify(|w| {
-                w.set_sw(sw.into());
-                w.set_hpre(cfgr.ahb_pre.into());
-                w.set_ppre1(cfgr.apb1_pre.into());
-                w.set_ppre2(cfgr.apb2_pre.into());
-            });
-        }
-
-        let ahb_freq: u32 = match cfgr.ahb_pre {
-            AHBPrescaler::NotDivided => sys_clk,
-            pre => {
-                let pre: u8 = pre.into();
-                let pre = 1 << (pre as u32 - 7);
-                sys_clk / pre
-            }
-        };
-
-        let (apb1_freq, apb1_tim_freq) = match cfgr.apb1_pre {
-            APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
-            pre => {
-                let pre: u8 = pre.into();
-                let pre: u8 = 1 << (pre - 3);
-                let freq = ahb_freq / pre as u32;
-                (freq, freq * 2)
-            }
-        };
-
-        let (apb2_freq, apb2_tim_freq) = match cfgr.apb2_pre {
-            APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
-            pre => {
-                let pre: u8 = pre.into();
-                let pre: u8 = 1 << (pre - 3);
-                let freq = ahb_freq / (1 << (pre as u8 - 3));
-                (freq, freq * 2)
-            }
-        };
-
-        Clocks {
-            sys: sys_clk.hz(),
-            ahb1: ahb_freq.hz(),
-            ahb2: ahb_freq.hz(),
-            ahb3: ahb_freq.hz(),
-            apb1: apb1_freq.hz(),
-            apb2: apb2_freq.hz(),
-            apb1_tim: apb1_tim_freq.hz(),
-            apb2_tim: apb2_tim_freq.hz(),
-        }
-    }
-}
-
 pub(crate) unsafe fn init(config: Config) {
-    let r = <peripherals::RCC as embassy::util::Steal>::steal();
-    let clocks = r.freeze(config);
-    set_freqs(clocks);
+    let (sys_clk, sw) = match config.mux {
+        ClockSrc::MSI(range) => {
+            // Enable MSI
+            RCC.cr().write(|w| {
+                let bits: Msirange = range.into();
+                w.set_msirange(bits);
+                w.set_msipllen(false);
+                w.set_msirgsel(true);
+                w.set_msion(true);
+            });
+            while !RCC.cr().read().msirdy() {}
+
+            // Enable as clock source for USB, RNG if running at 48 MHz
+            if let MSIRange::Range11 = range {
+                RCC.ccipr().modify(|w| {
+                    w.set_clk48sel(0b11);
+                });
+            }
+            (range.into(), Sw::MSI)
+        }
+        ClockSrc::HSI16 => {
+            // Enable HSI16
+            RCC.cr().write(|w| w.set_hsion(true));
+            while !RCC.cr().read().hsirdy() {}
+
+            (HSI16_FREQ, Sw::HSI16)
+        }
+        ClockSrc::HSE(freq) => {
+            // Enable HSE
+            RCC.cr().write(|w| w.set_hseon(true));
+            while !RCC.cr().read().hserdy() {}
+
+            (freq.0, Sw::HSE)
+        }
+        ClockSrc::PLL(src, div, prediv, mul, pll48div) => {
+            let freq = match src {
+                PLLSource::HSE(freq) => {
+                    // Enable HSE
+                    RCC.cr().write(|w| w.set_hseon(true));
+                    while !RCC.cr().read().hserdy() {}
+                    freq.0
+                }
+                PLLSource::HSI16 => {
+                    // Enable HSI
+                    RCC.cr().write(|w| w.set_hsion(true));
+                    while !RCC.cr().read().hsirdy() {}
+                    HSI16_FREQ
+                }
+            };
+
+            // Disable PLL
+            RCC.cr().modify(|w| w.set_pllon(false));
+            while RCC.cr().read().pllrdy() {}
+
+            let freq = (freq / prediv.to_div() * mul.to_mul()) / div.to_div();
+
+            assert!(freq <= 80_000_000);
+
+            RCC.pllcfgr().write(move |w| {
+                w.set_plln(mul.into());
+                w.set_pllm(prediv.into());
+                w.set_pllr(div.into());
+                if let Some(pll48div) = pll48div {
+                    w.set_pllq(pll48div.into());
+                    w.set_pllqen(true);
+                }
+                w.set_pllsrc(src.into());
+            });
+
+            // Enable as clock source for USB, RNG if PLL48 divisor is provided
+            if pll48div.is_some() {
+                RCC.ccipr().modify(|w| {
+                    w.set_clk48sel(0b10);
+                });
+            }
+
+            // Enable PLL
+            RCC.cr().modify(|w| w.set_pllon(true));
+            while !RCC.cr().read().pllrdy() {}
+            RCC.pllcfgr().modify(|w| w.set_pllren(true));
+
+            (freq, Sw::PLL)
+        }
+    };
+
+    // Set flash wait states
+    FLASH.acr().modify(|w| {
+        w.set_latency(if sys_clk <= 16_000_000 {
+            0b000
+        } else if sys_clk <= 32_000_000 {
+            0b001
+        } else if sys_clk <= 48_000_000 {
+            0b010
+        } else if sys_clk <= 64_000_000 {
+            0b011
+        } else {
+            0b100
+        });
+    });
+
+    RCC.cfgr().modify(|w| {
+        w.set_sw(sw);
+        w.set_hpre(config.ahb_pre.into());
+        w.set_ppre1(config.apb1_pre.into());
+        w.set_ppre2(config.apb2_pre.into());
+    });
+
+    let ahb_freq: u32 = match config.ahb_pre {
+        AHBPrescaler::NotDivided => sys_clk,
+        pre => {
+            let pre: Hpre = pre.into();
+            let pre = 1 << (pre.0 as u32 - 7);
+            sys_clk / pre
+        }
+    };
+
+    let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
+        APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
+        pre => {
+            let pre: Ppre = pre.into();
+            let pre: u8 = 1 << (pre.0 - 3);
+            let freq = ahb_freq / pre as u32;
+            (freq, freq * 2)
+        }
+    };
+
+    let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
+        APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
+        pre => {
+            let pre: Ppre = pre.into();
+            let pre: u8 = 1 << (pre.0 - 3);
+            let freq = ahb_freq / (1 << (pre as u8 - 3));
+            (freq, freq * 2)
+        }
+    };
+
+    set_freqs(Clocks {
+        sys: sys_clk.hz(),
+        ahb1: ahb_freq.hz(),
+        ahb2: ahb_freq.hz(),
+        ahb3: ahb_freq.hz(),
+        apb1: apb1_freq.hz(),
+        apb2: apb2_freq.hz(),
+        apb1_tim: apb1_tim_freq.hz(),
+        apb2_tim: apb2_tim_freq.hz(),
+    });
 }
diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs
index e8bd82718..ac1cd06c8 100644
--- a/embassy-stm32/src/rcc/u5.rs
+++ b/embassy-stm32/src/rcc/u5.rs
@@ -1,6 +1,4 @@
-use crate::pac;
-use crate::peripherals::{self, RCC};
-use crate::pwr::{Power, VoltageScale};
+use crate::pac::{FLASH, RCC};
 use crate::rcc::{set_freqs, Clocks};
 use crate::time::{Hertz, U32Ext};
 use stm32_metapac::rcc::vals::{Hpre, Msirange, Msirgsel, Pllm, Pllsrc, Ppre, Sw};
@@ -8,6 +6,20 @@ use stm32_metapac::rcc::vals::{Hpre, Msirange, Msirgsel, Pllm, Pllsrc, Ppre, Sw}
 /// HSI16 speed
 pub const HSI16_FREQ: u32 = 16_000_000;
 
+/// Voltage Scale
+///
+/// Represents the voltage range feeding the CPU core. The maximum core
+/// clock frequency depends on this value.
+#[derive(Copy, Clone, PartialEq)]
+pub enum VoltageScale {
+    // Highest frequency
+    Range1,
+    Range2,
+    Range3,
+    // Lowest power
+    Range4,
+}
+
 #[derive(Copy, Clone)]
 pub enum ClockSrc {
     MSI(MSIRange),
@@ -293,218 +305,188 @@ impl Default for Config {
     }
 }
 
-/// Extension trait that freezes the `RCC` peripheral with provided clocks configuration
-pub trait RccExt {
-    fn freeze(self, config: Config, power: &Power) -> Clocks;
-}
-
-impl RccExt for RCC {
-    #[inline]
-    fn freeze(self, cfgr: Config, power: &Power) -> Clocks {
-        let rcc = pac::RCC;
-
-        let sys_clk = match cfgr.mux {
-            ClockSrc::MSI(range) => {
-                unsafe {
-                    rcc.icscr1().modify(|w| {
-                        let bits: Msirange = range.into();
-                        w.set_msisrange(bits);
-                        w.set_msirgsel(Msirgsel::RCC_ICSCR1);
-                    });
-                    rcc.cr().write(|w| {
-                        w.set_msipllen(false);
-                        w.set_msison(true);
-                        w.set_msison(true);
-                    });
-                    while !rcc.cr().read().msisrdy() {}
-                }
-
-                range.into()
-            }
-            ClockSrc::HSE(freq) => {
-                unsafe {
-                    rcc.cr().write(|w| w.set_hseon(true));
-                    while !rcc.cr().read().hserdy() {}
-                }
-
-                freq.0
-            }
-            ClockSrc::HSI16 => {
-                unsafe {
-                    rcc.cr().write(|w| w.set_hsion(true));
-                    while !rcc.cr().read().hsirdy() {}
-                }
-
-                HSI16_FREQ
-            }
-            ClockSrc::PLL1R(src, m, n, div) => {
-                let freq = match src {
-                    PllSrc::MSI(_) => MSIRange::default().into(),
-                    PllSrc::HSE(hertz) => hertz.0,
-                    PllSrc::HSI16 => HSI16_FREQ,
-                };
-
-                // disable
-                unsafe {
-                    rcc.cr().modify(|w| w.set_pllon(0, false));
-                    while rcc.cr().read().pllrdy(0) {}
-                }
-
-                let vco = freq * n as u8 as u32;
-                let pll_ck = vco / (div as u8 as u32 + 1);
-
-                unsafe {
-                    rcc.pll1cfgr().write(|w| {
-                        w.set_pllm(m.into());
-                        w.set_pllsrc(src.into());
-                    });
-
-                    rcc.pll1divr().modify(|w| {
-                        w.set_pllr(div.to_div());
-                        w.set_plln(n.to_mul());
-                    });
-
-                    // Enable PLL
-                    rcc.cr().modify(|w| w.set_pllon(0, true));
-                    while !rcc.cr().read().pllrdy(0) {}
-                    rcc.pll1cfgr().modify(|w| w.set_pllren(true));
-                }
-
-                unsafe {
-                    rcc.cr().write(|w| w.set_pllon(0, true));
-                    while !rcc.cr().read().pllrdy(0) {}
-                }
-
-                pll_ck
-            }
-        };
-
-        // states and programming delay
-        let wait_states = match power.vos {
-            // VOS 0 range VCORE 1.26V - 1.40V
-            VoltageScale::Range1 => {
-                if sys_clk < 32_000_000 {
-                    0
-                } else if sys_clk < 64_000_000 {
-                    1
-                } else if sys_clk < 96_000_000 {
-                    2
-                } else if sys_clk < 128_000_000 {
-                    3
-                } else {
-                    4
-                }
-            }
-            // VOS 1 range VCORE 1.15V - 1.26V
-            VoltageScale::Range2 => {
-                if sys_clk < 30_000_000 {
-                    0
-                } else if sys_clk < 60_000_000 {
-                    1
-                } else if sys_clk < 90_000_000 {
-                    2
-                } else {
-                    3
-                }
-            }
-            // VOS 2 range VCORE 1.05V - 1.15V
-            VoltageScale::Range3 => {
-                if sys_clk < 24_000_000 {
-                    0
-                } else if sys_clk < 48_000_000 {
-                    1
-                } else {
-                    2
-                }
-            }
-            // VOS 3 range VCORE 0.95V - 1.05V
-            VoltageScale::Range4 => {
-                if sys_clk < 12_000_000 {
-                    0
-                } else {
-                    1
-                }
-            }
-        };
-
-        unsafe {
-            pac::FLASH.acr().modify(|w| {
-                w.set_latency(wait_states);
-            })
-        }
-
-        unsafe {
-            rcc.cfgr1().modify(|w| {
-                w.set_sw(cfgr.mux.into());
-            });
-
-            rcc.cfgr2().modify(|w| {
-                w.set_hpre(cfgr.ahb_pre.into());
-                w.set_ppre1(cfgr.apb1_pre.into());
-                w.set_ppre2(cfgr.apb2_pre.into());
-            });
-
-            rcc.cfgr3().modify(|w| {
-                w.set_ppre3(cfgr.apb3_pre.into());
-            });
-        }
-
-        let ahb_freq: u32 = match cfgr.ahb_pre {
-            AHBPrescaler::NotDivided => sys_clk,
-            pre => {
-                let pre: u8 = pre.into();
-                let pre = 1 << (pre as u32 - 7);
-                sys_clk / pre
-            }
-        };
-
-        let (apb1_freq, apb1_tim_freq) = match cfgr.apb1_pre {
-            APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
-            pre => {
-                let pre: u8 = pre.into();
-                let pre: u8 = 1 << (pre - 3);
-                let freq = ahb_freq / pre as u32;
-                (freq, freq * 2)
-            }
-        };
-
-        let (apb2_freq, apb2_tim_freq) = match cfgr.apb2_pre {
-            APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
-            pre => {
-                let pre: u8 = pre.into();
-                let pre: u8 = 1 << (pre - 3);
-                let freq = ahb_freq / (1 << (pre as u8 - 3));
-                (freq, freq * 2)
-            }
-        };
-
-        let (apb3_freq, _apb3_tim_freq) = match cfgr.apb3_pre {
-            APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
-            pre => {
-                let pre: u8 = pre.into();
-                let pre: u8 = 1 << (pre - 3);
-                let freq = ahb_freq / (1 << (pre as u8 - 3));
-                (freq, freq * 2)
-            }
-        };
-
-        Clocks {
-            sys: sys_clk.hz(),
-            ahb1: ahb_freq.hz(),
-            ahb2: ahb_freq.hz(),
-            ahb3: ahb_freq.hz(),
-            apb1: apb1_freq.hz(),
-            apb2: apb2_freq.hz(),
-            apb3: apb3_freq.hz(),
-            apb1_tim: apb1_tim_freq.hz(),
-            apb2_tim: apb2_tim_freq.hz(),
-        }
-    }
-}
-
 pub(crate) unsafe fn init(config: Config) {
-    let r = <peripherals::RCC as embassy::util::Steal>::steal();
-    let power = Power::new(<peripherals::PWR as embassy::util::Steal>::steal());
-    let clocks = r.freeze(config, &power);
-    set_freqs(clocks);
+    let sys_clk = match config.mux {
+        ClockSrc::MSI(range) => {
+            RCC.icscr1().modify(|w| {
+                let bits: Msirange = range.into();
+                w.set_msisrange(bits);
+                w.set_msirgsel(Msirgsel::RCC_ICSCR1);
+            });
+            RCC.cr().write(|w| {
+                w.set_msipllen(false);
+                w.set_msison(true);
+                w.set_msison(true);
+            });
+            while !RCC.cr().read().msisrdy() {}
+
+            range.into()
+        }
+        ClockSrc::HSE(freq) => {
+            RCC.cr().write(|w| w.set_hseon(true));
+            while !RCC.cr().read().hserdy() {}
+
+            freq.0
+        }
+        ClockSrc::HSI16 => {
+            RCC.cr().write(|w| w.set_hsion(true));
+            while !RCC.cr().read().hsirdy() {}
+
+            HSI16_FREQ
+        }
+        ClockSrc::PLL1R(src, m, n, div) => {
+            let freq = match src {
+                PllSrc::MSI(_) => MSIRange::default().into(),
+                PllSrc::HSE(hertz) => hertz.0,
+                PllSrc::HSI16 => HSI16_FREQ,
+            };
+
+            // disable
+            RCC.cr().modify(|w| w.set_pllon(0, false));
+            while RCC.cr().read().pllrdy(0) {}
+
+            let vco = freq * n as u8 as u32;
+            let pll_ck = vco / (div as u8 as u32 + 1);
+
+            RCC.pll1cfgr().write(|w| {
+                w.set_pllm(m.into());
+                w.set_pllsrc(src.into());
+            });
+
+            RCC.pll1divr().modify(|w| {
+                w.set_pllr(div.to_div());
+                w.set_plln(n.to_mul());
+            });
+
+            // Enable PLL
+            RCC.cr().modify(|w| w.set_pllon(0, true));
+            while !RCC.cr().read().pllrdy(0) {}
+            RCC.pll1cfgr().modify(|w| w.set_pllren(true));
+
+            RCC.cr().write(|w| w.set_pllon(0, true));
+            while !RCC.cr().read().pllrdy(0) {}
+
+            pll_ck
+        }
+    };
+
+    // TODO make configurable
+    let power_vos = VoltageScale::Range4;
+
+    // states and programming delay
+    let wait_states = match power_vos {
+        // VOS 0 range VCORE 1.26V - 1.40V
+        VoltageScale::Range1 => {
+            if sys_clk < 32_000_000 {
+                0
+            } else if sys_clk < 64_000_000 {
+                1
+            } else if sys_clk < 96_000_000 {
+                2
+            } else if sys_clk < 128_000_000 {
+                3
+            } else {
+                4
+            }
+        }
+        // VOS 1 range VCORE 1.15V - 1.26V
+        VoltageScale::Range2 => {
+            if sys_clk < 30_000_000 {
+                0
+            } else if sys_clk < 60_000_000 {
+                1
+            } else if sys_clk < 90_000_000 {
+                2
+            } else {
+                3
+            }
+        }
+        // VOS 2 range VCORE 1.05V - 1.15V
+        VoltageScale::Range3 => {
+            if sys_clk < 24_000_000 {
+                0
+            } else if sys_clk < 48_000_000 {
+                1
+            } else {
+                2
+            }
+        }
+        // VOS 3 range VCORE 0.95V - 1.05V
+        VoltageScale::Range4 => {
+            if sys_clk < 12_000_000 {
+                0
+            } else {
+                1
+            }
+        }
+    };
+
+    FLASH.acr().modify(|w| {
+        w.set_latency(wait_states);
+    });
+
+    RCC.cfgr1().modify(|w| {
+        w.set_sw(config.mux.into());
+    });
+
+    RCC.cfgr2().modify(|w| {
+        w.set_hpre(config.ahb_pre.into());
+        w.set_ppre1(config.apb1_pre.into());
+        w.set_ppre2(config.apb2_pre.into());
+    });
+
+    RCC.cfgr3().modify(|w| {
+        w.set_ppre3(config.apb3_pre.into());
+    });
+
+    let ahb_freq: u32 = match config.ahb_pre {
+        AHBPrescaler::NotDivided => sys_clk,
+        pre => {
+            let pre: u8 = pre.into();
+            let pre = 1 << (pre as u32 - 7);
+            sys_clk / pre
+        }
+    };
+
+    let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
+        APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
+        pre => {
+            let pre: u8 = pre.into();
+            let pre: u8 = 1 << (pre - 3);
+            let freq = ahb_freq / pre as u32;
+            (freq, freq * 2)
+        }
+    };
+
+    let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
+        APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
+        pre => {
+            let pre: u8 = pre.into();
+            let pre: u8 = 1 << (pre - 3);
+            let freq = ahb_freq / (1 << (pre as u8 - 3));
+            (freq, freq * 2)
+        }
+    };
+
+    let (apb3_freq, _apb3_tim_freq) = match config.apb3_pre {
+        APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
+        pre => {
+            let pre: u8 = pre.into();
+            let pre: u8 = 1 << (pre - 3);
+            let freq = ahb_freq / (1 << (pre as u8 - 3));
+            (freq, freq * 2)
+        }
+    };
+
+    set_freqs(Clocks {
+        sys: sys_clk.hz(),
+        ahb1: ahb_freq.hz(),
+        ahb2: ahb_freq.hz(),
+        ahb3: ahb_freq.hz(),
+        apb1: apb1_freq.hz(),
+        apb2: apb2_freq.hz(),
+        apb3: apb3_freq.hz(),
+        apb1_tim: apb1_tim_freq.hz(),
+        apb2_tim: apb2_tim_freq.hz(),
+    });
 }
diff --git a/embassy-stm32/src/rcc/wb.rs b/embassy-stm32/src/rcc/wb.rs
index 58146d4bd..eae7c9464 100644
--- a/embassy-stm32/src/rcc/wb.rs
+++ b/embassy-stm32/src/rcc/wb.rs
@@ -1,11 +1,7 @@
-use crate::pac;
-use crate::peripherals::{self, RCC};
-use crate::rcc::{get_freqs, set_freqs, Clocks};
+use crate::pac::RCC;
+use crate::rcc::{set_freqs, Clocks};
 use crate::time::Hertz;
 use crate::time::U32Ext;
-use core::marker::PhantomData;
-use embassy::util::Unborrow;
-use embassy_hal_common::unborrow;
 
 /// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC,
 /// and with the addition of the init function to configure a system clock.
@@ -104,110 +100,68 @@ impl Default for Config {
     }
 }
 
-/// RCC peripheral
-pub struct Rcc<'d> {
-    _rb: peripherals::RCC,
-    phantom: PhantomData<&'d mut peripherals::RCC>,
-}
-
-impl<'d> Rcc<'d> {
-    pub fn new(rcc: impl Unborrow<Target = peripherals::RCC> + 'd) -> Self {
-        unborrow!(rcc);
-        Self {
-            _rb: rcc,
-            phantom: PhantomData,
-        }
-    }
-
-    // Safety: RCC init must have been called
-    pub fn clocks(&self) -> &'static Clocks {
-        unsafe { get_freqs() }
-    }
-}
-
-/// Extension trait that freezes the `RCC` peripheral with provided clocks configuration
-pub trait RccExt {
-    fn freeze(self, config: Config) -> Clocks;
-}
-
-impl RccExt for RCC {
-    #[inline]
-    fn freeze(self, cfgr: Config) -> Clocks {
-        let rcc = pac::RCC;
-        let (sys_clk, sw) = match cfgr.mux {
-            ClockSrc::HSI16 => {
-                // Enable HSI16
-                unsafe {
-                    rcc.cr().write(|w| w.set_hsion(true));
-                    while !rcc.cr().read().hsirdy() {}
-                }
-
-                (HSI_FREQ, 0x01)
-            }
-            ClockSrc::HSE(freq) => {
-                // Enable HSE
-                unsafe {
-                    rcc.cr().write(|w| w.set_hseon(true));
-                    while !rcc.cr().read().hserdy() {}
-                }
-
-                (freq.0, 0x02)
-            }
-        };
-
-        unsafe {
-            rcc.cfgr().modify(|w| {
-                w.set_sw(sw.into());
-                w.set_hpre(cfgr.ahb_pre.into());
-                w.set_ppre1(cfgr.apb1_pre.into());
-                w.set_ppre2(cfgr.apb2_pre.into());
-            });
-        }
-
-        let ahb_freq: u32 = match cfgr.ahb_pre {
-            AHBPrescaler::NotDivided => sys_clk,
-            pre => {
-                let pre: u8 = pre.into();
-                let pre = 1 << (pre as u32 - 7);
-                sys_clk / pre
-            }
-        };
-
-        let (apb1_freq, apb1_tim_freq) = match cfgr.apb1_pre {
-            APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
-            pre => {
-                let pre: u8 = pre.into();
-                let pre: u8 = 1 << (pre - 3);
-                let freq = ahb_freq / pre as u32;
-                (freq, freq * 2)
-            }
-        };
-
-        let (apb2_freq, apb2_tim_freq) = match cfgr.apb2_pre {
-            APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
-            pre => {
-                let pre: u8 = pre.into();
-                let pre: u8 = 1 << (pre - 3);
-                let freq = ahb_freq / (1 << (pre as u8 - 3));
-                (freq, freq * 2)
-            }
-        };
-
-        Clocks {
-            sys: sys_clk.hz(),
-            ahb1: ahb_freq.hz(),
-            ahb2: ahb_freq.hz(),
-            ahb3: ahb_freq.hz(),
-            apb1: apb1_freq.hz(),
-            apb2: apb2_freq.hz(),
-            apb1_tim: apb1_tim_freq.hz(),
-            apb2_tim: apb2_tim_freq.hz(),
-        }
-    }
-}
-
 pub(crate) unsafe fn init(config: Config) {
-    let r = <peripherals::RCC as embassy::util::Steal>::steal();
-    let clocks = r.freeze(config);
-    set_freqs(clocks);
+    let (sys_clk, sw) = match config.mux {
+        ClockSrc::HSI16 => {
+            // Enable HSI16
+            RCC.cr().write(|w| w.set_hsion(true));
+            while !RCC.cr().read().hsirdy() {}
+
+            (HSI_FREQ, 0x01)
+        }
+        ClockSrc::HSE(freq) => {
+            // Enable HSE
+            RCC.cr().write(|w| w.set_hseon(true));
+            while !RCC.cr().read().hserdy() {}
+
+            (freq.0, 0x02)
+        }
+    };
+
+    RCC.cfgr().modify(|w| {
+        w.set_sw(sw.into());
+        w.set_hpre(config.ahb_pre.into());
+        w.set_ppre1(config.apb1_pre.into());
+        w.set_ppre2(config.apb2_pre.into());
+    });
+
+    let ahb_freq: u32 = match config.ahb_pre {
+        AHBPrescaler::NotDivided => sys_clk,
+        pre => {
+            let pre: u8 = pre.into();
+            let pre = 1 << (pre as u32 - 7);
+            sys_clk / pre
+        }
+    };
+
+    let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
+        APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
+        pre => {
+            let pre: u8 = pre.into();
+            let pre: u8 = 1 << (pre - 3);
+            let freq = ahb_freq / pre as u32;
+            (freq, freq * 2)
+        }
+    };
+
+    let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
+        APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
+        pre => {
+            let pre: u8 = pre.into();
+            let pre: u8 = 1 << (pre - 3);
+            let freq = ahb_freq / (1 << (pre as u8 - 3));
+            (freq, freq * 2)
+        }
+    };
+
+    set_freqs(Clocks {
+        sys: sys_clk.hz(),
+        ahb1: ahb_freq.hz(),
+        ahb2: ahb_freq.hz(),
+        ahb3: ahb_freq.hz(),
+        apb1: apb1_freq.hz(),
+        apb2: apb2_freq.hz(),
+        apb1_tim: apb1_tim_freq.hz(),
+        apb2_tim: apb2_tim_freq.hz(),
+    });
 }
diff --git a/embassy-stm32/src/rcc/wl5.rs b/embassy-stm32/src/rcc/wl5.rs
index 00b91dfec..fb2dd9986 100644
--- a/embassy-stm32/src/rcc/wl5.rs
+++ b/embassy-stm32/src/rcc/wl5.rs
@@ -1,10 +1,6 @@
-use crate::pac;
-use crate::peripherals::{self, RCC};
-use crate::rcc::{get_freqs, set_freqs, Clocks};
+use crate::pac::RCC;
+use crate::rcc::{set_freqs, Clocks};
 use crate::time::U32Ext;
-use core::marker::PhantomData;
-use embassy::util::Unborrow;
-use embassy_hal_common::unborrow;
 
 /// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC,
 /// and with the addition of the init function to configure a system clock.
@@ -91,6 +87,7 @@ pub struct Config {
     pub ahb_pre: AHBPrescaler,
     pub apb1_pre: APBPrescaler,
     pub apb2_pre: APBPrescaler,
+    pub enable_lsi: bool,
 }
 
 impl Default for Config {
@@ -101,136 +98,92 @@ impl Default for Config {
             ahb_pre: AHBPrescaler::NotDivided,
             apb1_pre: APBPrescaler::NotDivided,
             apb2_pre: APBPrescaler::NotDivided,
-        }
-    }
-}
-
-/// RCC peripheral
-pub struct Rcc<'d> {
-    _rb: peripherals::RCC,
-    phantom: PhantomData<&'d mut peripherals::RCC>,
-}
-
-impl<'d> Rcc<'d> {
-    pub fn new(rcc: impl Unborrow<Target = peripherals::RCC> + 'd) -> Self {
-        unborrow!(rcc);
-        Self {
-            _rb: rcc,
-            phantom: PhantomData,
-        }
-    }
-
-    pub fn enable_lsi(&mut self) {
-        let rcc = pac::RCC;
-        unsafe {
-            let csr = rcc.csr().read();
-            if !csr.lsion() {
-                rcc.csr().modify(|w| w.set_lsion(true));
-                while !rcc.csr().read().lsirdy() {}
-            }
-        }
-    }
-
-    // Safety: RCC init must have been called
-    pub fn clocks(&self) -> &'static Clocks {
-        unsafe { get_freqs() }
-    }
-}
-
-/// Extension trait that freezes the `RCC` peripheral with provided clocks configuration
-pub trait RccExt {
-    fn freeze(self, config: Config) -> Clocks;
-}
-
-impl RccExt for RCC {
-    #[inline]
-    fn freeze(self, cfgr: Config) -> Clocks {
-        let rcc = pac::RCC;
-        let (sys_clk, sw) = match cfgr.mux {
-            ClockSrc::HSI16 => {
-                // Enable HSI16
-                unsafe {
-                    rcc.cr().write(|w| w.set_hsion(true));
-                    while !rcc.cr().read().hsirdy() {}
-                }
-
-                (HSI_FREQ, 0x01)
-            }
-            ClockSrc::HSE32 => {
-                // Enable HSE32
-                unsafe {
-                    rcc.cr().write(|w| {
-                        w.set_hsebyppwr(true);
-                        w.set_hseon(true);
-                    });
-                    while !rcc.cr().read().hserdy() {}
-                }
-
-                (HSE32_FREQ, 0x02)
-            }
-        };
-
-        unsafe {
-            rcc.cfgr().modify(|w| {
-                w.set_sw(sw.into());
-                if cfgr.ahb_pre == AHBPrescaler::NotDivided {
-                    w.set_hpre(0);
-                } else {
-                    w.set_hpre(cfgr.ahb_pre.into());
-                }
-                w.set_ppre1(cfgr.apb1_pre.into());
-                w.set_ppre2(cfgr.apb2_pre.into());
-            });
-        }
-
-        let ahb_freq: u32 = match cfgr.ahb_pre {
-            AHBPrescaler::NotDivided => sys_clk,
-            pre => {
-                let pre: u8 = pre.into();
-                let pre = 1 << (pre as u32 - 7);
-                sys_clk / pre
-            }
-        };
-
-        let (apb1_freq, apb1_tim_freq) = match cfgr.apb1_pre {
-            APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
-            pre => {
-                let pre: u8 = pre.into();
-                let pre: u8 = 1 << (pre - 3);
-                let freq = ahb_freq / pre as u32;
-                (freq, freq * 2)
-            }
-        };
-
-        let (apb2_freq, apb2_tim_freq) = match cfgr.apb2_pre {
-            APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
-            pre => {
-                let pre: u8 = pre.into();
-                let pre: u8 = 1 << (pre - 3);
-                let freq = ahb_freq / (1 << (pre as u8 - 3));
-                (freq, freq * 2)
-            }
-        };
-
-        // TODO: completely untested
-        let apb3_freq = ahb_freq;
-
-        Clocks {
-            sys: sys_clk.hz(),
-            ahb1: ahb_freq.hz(),
-            ahb2: ahb_freq.hz(),
-            ahb3: ahb_freq.hz(),
-            apb1: apb1_freq.hz(),
-            apb2: apb2_freq.hz(),
-            apb3: apb3_freq.hz(),
-            apb1_tim: apb1_tim_freq.hz(),
-            apb2_tim: apb2_tim_freq.hz(),
+            enable_lsi: false,
         }
     }
 }
 
 pub(crate) unsafe fn init(config: Config) {
-    let r = <peripherals::RCC as embassy::util::Steal>::steal();
-    let clocks = r.freeze(config);
-    set_freqs(clocks);
+    let (sys_clk, sw) = match config.mux {
+        ClockSrc::HSI16 => {
+            // Enable HSI16
+            RCC.cr().write(|w| w.set_hsion(true));
+            while !RCC.cr().read().hsirdy() {}
+
+            (HSI_FREQ, 0x01)
+        }
+        ClockSrc::HSE32 => {
+            // Enable HSE32
+            RCC.cr().write(|w| {
+                w.set_hsebyppwr(true);
+                w.set_hseon(true);
+            });
+            while !RCC.cr().read().hserdy() {}
+
+            (HSE32_FREQ, 0x02)
+        }
+    };
+
+    RCC.cfgr().modify(|w| {
+        w.set_sw(sw.into());
+        if config.ahb_pre == AHBPrescaler::NotDivided {
+            w.set_hpre(0);
+        } else {
+            w.set_hpre(config.ahb_pre.into());
+        }
+        w.set_ppre1(config.apb1_pre.into());
+        w.set_ppre2(config.apb2_pre.into());
+    });
+
+    let ahb_freq: u32 = match config.ahb_pre {
+        AHBPrescaler::NotDivided => sys_clk,
+        pre => {
+            let pre: u8 = pre.into();
+            let pre = 1 << (pre as u32 - 7);
+            sys_clk / pre
+        }
+    };
+
+    let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
+        APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
+        pre => {
+            let pre: u8 = pre.into();
+            let pre: u8 = 1 << (pre - 3);
+            let freq = ahb_freq / pre as u32;
+            (freq, freq * 2)
+        }
+    };
+
+    let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
+        APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
+        pre => {
+            let pre: u8 = pre.into();
+            let pre: u8 = 1 << (pre - 3);
+            let freq = ahb_freq / (1 << (pre as u8 - 3));
+            (freq, freq * 2)
+        }
+    };
+
+    // TODO: completely untested
+    let apb3_freq = ahb_freq;
+
+    if config.enable_lsi {
+        let csr = RCC.csr().read();
+        if !csr.lsion() {
+            RCC.csr().modify(|w| w.set_lsion(true));
+            while !RCC.csr().read().lsirdy() {}
+        }
+    }
+
+    set_freqs(Clocks {
+        sys: sys_clk.hz(),
+        ahb1: ahb_freq.hz(),
+        ahb2: ahb_freq.hz(),
+        ahb3: ahb_freq.hz(),
+        apb1: apb1_freq.hz(),
+        apb2: apb2_freq.hz(),
+        apb3: apb3_freq.hz(),
+        apb1_tim: apb1_tim_freq.hz(),
+        apb2_tim: apb2_tim_freq.hz(),
+    });
 }
diff --git a/examples/stm32l0/src/bin/button_exti.rs b/examples/stm32l0/src/bin/button_exti.rs
index 20d6f5555..88c75ce6d 100644
--- a/examples/stm32l0/src/bin/button_exti.rs
+++ b/examples/stm32l0/src/bin/button_exti.rs
@@ -8,16 +8,18 @@ mod example_common;
 use embassy::executor::Spawner;
 use embassy_stm32::exti::ExtiInput;
 use embassy_stm32::gpio::{Input, Pull};
-use embassy_stm32::{rcc, Peripherals};
+use embassy_stm32::Peripherals;
 use embassy_traits::gpio::{WaitForFallingEdge, WaitForRisingEdge};
 use example_common::*;
 
-#[embassy::main]
-async fn main(_spawner: Spawner, mut p: Peripherals) {
-    let mut rcc = rcc::Rcc::new(p.RCC);
-    // Enables SYSCFG
-    let _ = rcc.enable_hsi48(&mut p.SYSCFG, p.CRS);
+fn config() -> embassy_stm32::Config {
+    let mut config = embassy_stm32::Config::default();
+    config.rcc.enable_hsi48 = true;
+    config
+}
 
+#[embassy::main(config = "config()")]
+async fn main(_spawner: Spawner, p: Peripherals) {
     let button = Input::new(p.PB2, Pull::Up);
     let mut button = ExtiInput::new(button, p.EXTI2);
 
diff --git a/examples/stm32l0/src/bin/lorawan.rs b/examples/stm32l0/src/bin/lorawan.rs
index 7ce859a8d..df08ba18c 100644
--- a/examples/stm32l0/src/bin/lorawan.rs
+++ b/examples/stm32l0/src/bin/lorawan.rs
@@ -11,10 +11,8 @@ mod example_common;
 
 use embassy_lora::{sx127x::*, LoraTimer};
 use embassy_stm32::{
-    dbgmcu::Dbgmcu,
     exti::ExtiInput,
     gpio::{Input, Level, Output, Pull, Speed},
-    rcc,
     rng::Rng,
     spi,
     time::U32Ext,
@@ -26,18 +24,12 @@ use lorawan_encoding::default_crypto::DefaultFactory as Crypto;
 fn config() -> embassy_stm32::Config {
     let mut config = embassy_stm32::Config::default();
     config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSI16;
+    config.rcc.enable_hsi48 = true;
     config
 }
 
 #[embassy::main(config = "config()")]
-async fn main(_spawner: embassy::executor::Spawner, mut p: Peripherals) {
-    unsafe {
-        Dbgmcu::enable_all();
-    }
-
-    let mut rcc = rcc::Rcc::new(p.RCC);
-    let _ = rcc.enable_hsi48(&mut p.SYSCFG, p.CRS);
-
+async fn main(_spawner: embassy::executor::Spawner, p: Peripherals) {
     // SPI for sx127x
     let spi = spi::Spi::new(
         p.SPI1,
diff --git a/examples/stm32wl55/src/bin/lorawan.rs b/examples/stm32wl55/src/bin/lorawan.rs
index 7048a5814..5d26dead2 100644
--- a/examples/stm32wl55/src/bin/lorawan.rs
+++ b/examples/stm32wl55/src/bin/lorawan.rs
@@ -10,10 +10,9 @@ mod example_common;
 
 use embassy_lora::{stm32wl::*, LoraTimer};
 use embassy_stm32::{
-    dbgmcu::Dbgmcu,
     dma::NoDma,
     gpio::{Level, Output, Pin, Speed},
-    interrupt, pac, rcc,
+    interrupt, pac,
     rng::Rng,
     subghz::*,
     Peripherals,
@@ -24,19 +23,13 @@ use lorawan_encoding::default_crypto::DefaultFactory as Crypto;
 fn config() -> embassy_stm32::Config {
     let mut config = embassy_stm32::Config::default();
     config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSI16;
+    config.rcc.enable_lsi = true;
     config
 }
 
 #[embassy::main(config = "config()")]
 async fn main(_spawner: embassy::executor::Spawner, p: Peripherals) {
-    unsafe {
-        Dbgmcu::enable_all();
-        let mut rcc = rcc::Rcc::new(p.RCC);
-        rcc.enable_lsi();
-        pac::RCC.ccipr().modify(|w| {
-            w.set_rngsel(0b01);
-        });
-    }
+    unsafe { pac::RCC.ccipr().modify(|w| w.set_rngsel(0b01)) }
 
     let ctrl1 = Output::new(p.PC3.degrade(), Level::High, Speed::High);
     let ctrl2 = Output::new(p.PC4.degrade(), Level::High, Speed::High);
diff --git a/examples/stm32wl55/src/bin/subghz.rs b/examples/stm32wl55/src/bin/subghz.rs
index a73c361c2..52fe6e9fa 100644
--- a/examples/stm32wl55/src/bin/subghz.rs
+++ b/examples/stm32wl55/src/bin/subghz.rs
@@ -11,7 +11,6 @@ mod example_common;
 use embassy::channel::signal::Signal;
 use embassy::interrupt::{Interrupt, InterruptExt};
 use embassy::traits::gpio::WaitForRisingEdge;
-use embassy_stm32::dbgmcu::Dbgmcu;
 use embassy_stm32::dma::NoDma;
 use embassy_stm32::exti::ExtiInput;
 use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
@@ -72,10 +71,6 @@ fn config() -> embassy_stm32::Config {
 
 #[embassy::main(config = "config()")]
 async fn main(_spawner: embassy::executor::Spawner, p: Peripherals) {
-    unsafe {
-        Dbgmcu::enable_all();
-    }
-
     let mut led1 = Output::new(p.PB15, Level::High, Speed::Low);
     let mut led2 = Output::new(p.PB9, Level::Low, Speed::Low);
     let mut led3 = Output::new(p.PB11, Level::Low, Speed::Low);
diff --git a/stm32-data b/stm32-data
index 8530a19ff..3fa97966f 160000
--- a/stm32-data
+++ b/stm32-data
@@ -1 +1 @@
-Subproject commit 8530a19ffdcdcbc608a97b40895827d09e670eb7
+Subproject commit 3fa97966f07d43a28c0031175591e1c2ff5d0831

From 3486d59d730ac6124290ced600c00c61133c0fdb Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis <dirbaio@dirbaio.net>
Date: Tue, 4 Jan 2022 23:58:57 +0100
Subject: [PATCH 4/6] stm32: remove Dbgmcu from public API.

The use case is already covered by `config.enable_debug_during_sleep`.
---
 embassy-stm32/src/dbgmcu/mod.rs | 13 -------------
 embassy-stm32/src/lib.rs        | 10 +++++++---
 2 files changed, 7 insertions(+), 16 deletions(-)
 delete mode 100644 embassy-stm32/src/dbgmcu/mod.rs

diff --git a/embassy-stm32/src/dbgmcu/mod.rs b/embassy-stm32/src/dbgmcu/mod.rs
deleted file mode 100644
index 8dc4cc53f..000000000
--- a/embassy-stm32/src/dbgmcu/mod.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-pub struct Dbgmcu {}
-
-impl Dbgmcu {
-    pub unsafe fn enable_all() {
-        crate::pac::DBGMCU.cr().modify(|cr| {
-            crate::pac::dbgmcu! {
-                (cr, $fn_name:ident) => {
-                    cr.$fn_name(true);
-                };
-            }
-        });
-    }
-}
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index 117f3ed2a..bcd9bd5c1 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -29,8 +29,6 @@ pub mod adc;
 pub mod can;
 #[cfg(dac)]
 pub mod dac;
-#[cfg(dbgmcu)]
-pub mod dbgmcu;
 #[cfg(dcmi)]
 pub mod dcmi;
 #[cfg(all(eth, feature = "net"))]
@@ -90,7 +88,13 @@ pub fn init(config: Config) -> Peripherals {
 
     unsafe {
         if config.enable_debug_during_sleep {
-            dbgmcu::Dbgmcu::enable_all();
+            crate::pac::DBGMCU.cr().modify(|cr| {
+                crate::pac::dbgmcu! {
+                    (cr, $fn_name:ident) => {
+                        cr.$fn_name(true);
+                    };
+                }
+            });
         }
 
         gpio::init();

From 58e9dfbc00c0fed1400ecf8c3827f476a25b7c11 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis <dirbaio@dirbaio.net>
Date: Wed, 5 Jan 2022 13:30:08 +0100
Subject: [PATCH 5/6] tests/stm32: make __sdata=__edata so that cortex-m-rt
 doesn't try to copy it from "flash".

---
 tests/stm32/link_ram.x | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tests/stm32/link_ram.x b/tests/stm32/link_ram.x
index d23ffc747..26da86baa 100644
--- a/tests/stm32/link_ram.x
+++ b/tests/stm32/link_ram.x
@@ -125,6 +125,7 @@ SECTIONS
   {
     . = ALIGN(4);
     __sdata = .;
+    __edata = .;
     *(.data .data.*);
     . = ALIGN(4); /* 4-byte align the end (VMA) of this section */
   } > RAM
@@ -132,7 +133,6 @@ SECTIONS
    * use the .data loading mechanism by pushing __edata. Note: do not change
    * output region or load region in those user sections! */
   . = ALIGN(4);
-  __edata = .;
 
   /* LMA of .data */
   __sidata = LOADADDR(.data);

From caf48d8a9593cfd408a230600173e510e397c7dd Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis <dirbaio@dirbaio.net>
Date: Wed, 5 Jan 2022 13:30:46 +0100
Subject: [PATCH 6/6] macros: initialize chip before executor.

The executor will call into the chip's time-driver, which may need the chip
to be initialized.
---
 embassy-macros/src/lib.rs | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/embassy-macros/src/lib.rs b/embassy-macros/src/lib.rs
index cdbc25179..44a8d3b93 100644
--- a/embassy-macros/src/lib.rs
+++ b/embassy-macros/src/lib.rs
@@ -370,16 +370,14 @@ pub fn main(args: TokenStream, item: TokenStream) -> TokenStream {
                 ::core::mem::transmute(t)
             }
 
-            let mut executor = #embassy_path::executor::Executor::new();
-
-            let executor = unsafe { make_static(&mut executor) };
-
             #chip_setup
 
+            let mut executor = #embassy_path::executor::Executor::new();
+            let executor = unsafe { make_static(&mut executor) };
+
             executor.run(|spawner| {
                 spawner.must_spawn(__embassy_main(spawner, p));
             })
-
         }
     };
     result.into()