diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 460184920..4bbd43c47 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -70,7 +70,7 @@ rand_core = "0.6.3"
 sdio-host = "0.5.0"
 critical-section = "1.1"
 #stm32-metapac = { version = "15" }
-stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-d7462d805ef05892531a83cd9ad60c9cba568d54" }
+stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-e853cf944b150898312984d092d63926970c340d" }
 vcell = "0.1.3"
 bxcan = "0.7.0"
 nb = "1.0.0"
@@ -94,7 +94,7 @@ critical-section = { version = "1.1", features = ["std"] }
 proc-macro2 = "1.0.36"
 quote = "1.0.15"
 #stm32-metapac = { version = "15", default-features = false, features = ["metadata"]}
-stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-d7462d805ef05892531a83cd9ad60c9cba568d54", default-features = false, features = ["metadata"]}
+stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-e853cf944b150898312984d092d63926970c340d", default-features = false, features = ["metadata"]}
 
 
 [features]
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index 08c051956..84e8be25d 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -5,7 +5,9 @@ use std::{env, fs};
 
 use proc_macro2::{Ident, TokenStream};
 use quote::{format_ident, quote};
-use stm32_metapac::metadata::{MemoryRegionKind, PeripheralRccKernelClock, StopMode, METADATA};
+use stm32_metapac::metadata::{
+    MemoryRegionKind, PeripheralRccKernelClock, PeripheralRccRegister, PeripheralRegisters, StopMode, METADATA,
+};
 
 fn main() {
     let target = env::var("TARGET").unwrap();
@@ -374,12 +376,130 @@ fn main() {
         }
     }
 
-    let force_refcount = HashSet::from(["usart"]);
-    let mut refcount_statics = BTreeSet::new();
+    struct ClockGen<'a> {
+        rcc_registers: &'a PeripheralRegisters,
+        chained_muxes: HashMap<&'a str, &'a PeripheralRccRegister>,
+        force_refcount: HashSet<&'a str>,
 
-    let mut clock_names = BTreeSet::new();
+        refcount_statics: BTreeSet<Ident>,
+        clock_names: BTreeSet<String>,
+        muxes: BTreeSet<(Ident, Ident, Ident)>,
+    }
 
-    let mut rcc_cfgr_regs = BTreeSet::new();
+    let mut clock_gen = ClockGen {
+        rcc_registers,
+        chained_muxes: HashMap::new(),
+        force_refcount: HashSet::from(["usart"]),
+
+        refcount_statics: BTreeSet::new(),
+        clock_names: BTreeSet::new(),
+        muxes: BTreeSet::new(),
+    };
+    if chip_name.starts_with("stm32h5") {
+        clock_gen.chained_muxes.insert(
+            "PER",
+            &PeripheralRccRegister {
+                register: "CCIPR5",
+                field: "PERSEL",
+            },
+        );
+    }
+    if chip_name.starts_with("stm32h7") {
+        clock_gen.chained_muxes.insert(
+            "PER",
+            &PeripheralRccRegister {
+                register: "D1CCIPR",
+                field: "PERSEL",
+            },
+        );
+    }
+    if chip_name.starts_with("stm32u5") {
+        clock_gen.chained_muxes.insert(
+            "ICLK",
+            &PeripheralRccRegister {
+                register: "CCIPR1",
+                field: "ICLKSEL",
+            },
+        );
+    }
+    if chip_name.starts_with("stm32wb") && !chip_name.starts_with("stm32wba") {
+        clock_gen.chained_muxes.insert(
+            "CLK48",
+            &PeripheralRccRegister {
+                register: "CCIPR",
+                field: "CLK48SEL",
+            },
+        );
+    }
+    if chip_name.starts_with("stm32f7") {
+        clock_gen.chained_muxes.insert(
+            "CLK48",
+            &PeripheralRccRegister {
+                register: "DCKCFGR2",
+                field: "CLK48SEL",
+            },
+        );
+    }
+    if chip_name.starts_with("stm32f4") && !chip_name.starts_with("stm32f410") {
+        clock_gen.chained_muxes.insert(
+            "CLK48",
+            &PeripheralRccRegister {
+                register: "DCKCFGR",
+                field: "CLK48SEL",
+            },
+        );
+    }
+
+    impl<'a> ClockGen<'a> {
+        fn gen_clock(&mut self, name: &str) -> TokenStream {
+            let clock_name = format_ident!("{}", name.to_ascii_lowercase());
+            self.clock_names.insert(name.to_ascii_lowercase());
+            quote!( unsafe { crate::rcc::get_freqs().#clock_name.unwrap() } )
+        }
+
+        fn gen_mux(&mut self, mux: &PeripheralRccRegister) -> TokenStream {
+            let ir = &self.rcc_registers.ir;
+            let fieldset_name = mux.register.to_ascii_lowercase();
+            let fieldset = ir
+                .fieldsets
+                .iter()
+                .find(|i| i.name.eq_ignore_ascii_case(&fieldset_name))
+                .unwrap();
+            let field_name = mux.field.to_ascii_lowercase();
+            let field = fieldset.fields.iter().find(|i| i.name == field_name).unwrap();
+            let enum_name = field.enumm.unwrap();
+            let enumm = ir.enums.iter().find(|i| i.name == enum_name).unwrap();
+
+            let fieldset_name = format_ident!("{}", fieldset_name);
+            let field_name = format_ident!("{}", field_name);
+            let enum_name = format_ident!("{}", enum_name);
+
+            self.muxes
+                .insert((fieldset_name.clone(), field_name.clone(), enum_name.clone()));
+
+            let mut match_arms = TokenStream::new();
+
+            for v in enumm.variants.iter().filter(|v| v.name != "DISABLE") {
+                let variant_name = format_ident!("{}", v.name);
+                let expr = if let Some(mux) = self.chained_muxes.get(&v.name) {
+                    self.gen_mux(mux)
+                } else {
+                    self.gen_clock(&v.name)
+                };
+                match_arms.extend(quote! {
+                    crate::pac::rcc::vals::#enum_name::#variant_name => #expr,
+                });
+            }
+
+            quote! {
+                match crate::pac::RCC.#fieldset_name().read().#field_name() {
+                    #match_arms
+                    #[allow(unreachable_patterns)]
+                    _ => unreachable!(),
+                }
+            }
+        }
+    }
 
     for p in METADATA.peripherals {
         if !singletons.contains(&p.name.to_string()) {
@@ -416,12 +536,12 @@ fn main() {
             let set_en_field = format_ident!("set_{}", en.field.to_ascii_lowercase());
 
             let refcount =
-                force_refcount.contains(ptype) || *rcc_field_count.get(&(en.register, en.field)).unwrap() > 1;
+                clock_gen.force_refcount.contains(ptype) || *rcc_field_count.get(&(en.register, en.field)).unwrap() > 1;
             let (before_enable, before_disable) = if refcount {
                 let refcount_static =
                     format_ident!("{}_{}", en.register.to_ascii_uppercase(), en.field.to_ascii_uppercase());
 
-                refcount_statics.insert(refcount_static.clone());
+                clock_gen.refcount_statics.insert(refcount_static.clone());
 
                 (
                     quote! {
@@ -442,63 +562,12 @@ fn main() {
             };
 
             let clock_frequency = match &rcc.kernel_clock {
-                PeripheralRccKernelClock::Mux(mux) => {
-                    let ir = &rcc_registers.ir;
-                    let fieldset_name = mux.register.to_ascii_lowercase();
-                    let fieldset = ir
-                        .fieldsets
-                        .iter()
-                        .find(|i| i.name.eq_ignore_ascii_case(&fieldset_name))
-                        .unwrap();
-                    let field_name = mux.field.to_ascii_lowercase();
-                    let field = fieldset.fields.iter().find(|i| i.name == field_name).unwrap();
-                    let enum_name = field.enumm.unwrap();
-                    let enumm = ir.enums.iter().find(|i| i.name == enum_name).unwrap();
-
-                    let fieldset_name = format_ident!("{}", fieldset_name);
-                    let field_name = format_ident!("{}", field_name);
-                    let enum_name = format_ident!("{}", enum_name);
-
-                    rcc_cfgr_regs.insert((fieldset_name.clone(), field_name.clone(), enum_name.clone()));
-
-                    let match_arms: TokenStream = enumm
-                        .variants
-                        .iter()
-                        .filter(|v| v.name != "DISABLE")
-                        .map(|v| {
-                            let variant_name = format_ident!("{}", v.name);
-                            let clock_name = format_ident!("{}", v.name.to_ascii_lowercase());
-                            clock_names.insert(v.name.to_ascii_lowercase());
-                            quote! {
-                                #enum_name::#variant_name => unsafe { crate::rcc::get_freqs().#clock_name.unwrap() },
-                            }
-                        })
-                        .collect();
-
-                    quote! {
-                        use crate::pac::rcc::vals::#enum_name;
-
-                        #[allow(unreachable_patterns)]
-                        match crate::pac::RCC.#fieldset_name().read().#field_name() {
-                            #match_arms
-                            _ => unreachable!(),
-                        }
-                    }
-                }
-                PeripheralRccKernelClock::Clock(clock) => {
-                    let clock = clock.to_ascii_lowercase();
-                    let clock_name = format_ident!("{}", clock);
-                    clock_names.insert(clock.to_string());
-                    quote! {
-                        unsafe { crate::rcc::get_freqs().#clock_name.unwrap() }
-                    }
-                }
+                PeripheralRccKernelClock::Mux(mux) => clock_gen.gen_mux(mux),
+                PeripheralRccKernelClock::Clock(clock) => clock_gen.gen_clock(clock),
             };
 
-            /*
-                A refcount leak can result if the same field is shared by peripherals with different stop modes
-                This condition should be checked in stm32-data
-            */
+            // A refcount leak can result if the same field is shared by peripherals with different stop modes
+            // This condition should be checked in stm32-data
             let stop_refcount = match rcc.stop_mode {
                 StopMode::Standby => None,
                 StopMode::Stop2 => Some(quote! { REFCOUNT_STOP2 }),
@@ -543,74 +612,79 @@ fn main() {
         }
     }
 
-    if !rcc_cfgr_regs.is_empty() {
-        println!("cargo:rustc-cfg=clock_mux");
+    let struct_fields: Vec<_> = clock_gen
+        .muxes
+        .iter()
+        .map(|(_fieldset, fieldname, enum_name)| {
+            quote! {
+                pub #fieldname: #enum_name
+            }
+        })
+        .collect();
 
-        let struct_fields: Vec<_> = rcc_cfgr_regs
+    let mut inits = TokenStream::new();
+    for fieldset in clock_gen
+        .muxes
+        .iter()
+        .map(|(f, _, _)| f)
+        .collect::<BTreeSet<_>>()
+        .into_iter()
+    {
+        let setters: Vec<_> = clock_gen
+            .muxes
             .iter()
-            .map(|(_fieldset, fieldname, enum_name)| {
-                quote! {
-                    pub #fieldname: Option<#enum_name>
-                }
-            })
-            .collect();
-
-        let field_names: Vec<_> = rcc_cfgr_regs
-            .iter()
-            .map(|(_fieldset, fieldname, _enum_name)| fieldname)
-            .collect();
-
-        let inits: Vec<_> = rcc_cfgr_regs
-            .iter()
-            .map(|(fieldset, fieldname, _enum_name)| {
+            .filter(|(f, _, _)| f == fieldset)
+            .map(|(_, fieldname, _)| {
                 let setter = format_ident!("set_{}", fieldname);
                 quote! {
-                    match self.#fieldname {
-                        None => {}
-                        Some(val) => {
-                            crate::pac::RCC.#fieldset()
-                                .modify(|w| w.#setter(val));
-                        }
-                    };
+                    w.#setter(self.#fieldname);
                 }
             })
             .collect();
 
-        let enum_names: BTreeSet<_> = rcc_cfgr_regs
-            .iter()
-            .map(|(_fieldset, _fieldname, enum_name)| enum_name)
-            .collect();
-
-        g.extend(quote! {
-            pub mod mux {
-                #(pub use crate::pac::rcc::vals::#enum_names as #enum_names; )*
-
-                #[derive(Clone, Copy)]
-                pub struct ClockMux {
-                    #( #struct_fields, )*
-                }
-
-                impl Default for ClockMux {
-                    fn default() -> Self {
-                        Self {
-                            #( #field_names: None, )*
-                        }
-                    }
-                }
-
-                impl ClockMux {
-                    pub fn init(self) {
-                        #( #inits )*
-                    }
-                }
-            }
-        });
+        inits.extend(quote! {
+            crate::pac::RCC.#fieldset().modify(|w| {
+                #(#setters)*
+            });
+        })
     }
 
+    let enum_names: BTreeSet<_> = clock_gen.muxes.iter().map(|(_, _, enum_name)| enum_name).collect();
+
+    g.extend(quote! {
+        pub mod mux {
+            #(pub use crate::pac::rcc::vals::#enum_names as #enum_names; )*
+
+            #[derive(Clone, Copy)]
+            pub struct ClockMux {
+                #( #struct_fields, )*
+            }
+
+            impl ClockMux {
+                pub(crate) const fn default() -> Self {
+                    // safety: zero value is valid for all PAC enums.
+                    unsafe { ::core::mem::zeroed() }
+                }
+            }
+
+            impl Default for ClockMux {
+                fn default() -> Self {
+                    Self::default()
+                }
+            }
+
+            impl ClockMux {
+                pub(crate) fn init(&self) {
+                    #inits
+                }
+            }
+        }
+    });
+
     // Generate RCC
-    clock_names.insert("sys".to_string());
-    clock_names.insert("rtc".to_string());
-    let clock_idents: Vec<_> = clock_names.iter().map(|n| format_ident!("{}", n)).collect();
+    clock_gen.clock_names.insert("sys".to_string());
+    clock_gen.clock_names.insert("rtc".to_string());
+    let clock_idents: Vec<_> = clock_gen.clock_names.iter().map(|n| format_ident!("{}", n)).collect();
     g.extend(quote! {
         #[derive(Clone, Copy, Debug)]
         #[cfg_attr(feature = "defmt", derive(defmt::Format))]
@@ -640,7 +714,8 @@ fn main() {
         }
     );
 
-    let refcount_mod: TokenStream = refcount_statics
+    let refcount_mod: TokenStream = clock_gen
+        .refcount_statics
         .iter()
         .map(|refcount_static| {
             quote! {
diff --git a/embassy-stm32/src/ipcc.rs b/embassy-stm32/src/ipcc.rs
index 663a7f59d..523719bb9 100644
--- a/embassy-stm32/src/ipcc.rs
+++ b/embassy-stm32/src/ipcc.rs
@@ -7,7 +7,6 @@ use core::task::Poll;
 use self::sealed::Instance;
 use crate::interrupt;
 use crate::interrupt::typelevel::Interrupt;
-use crate::pac::rcc::vals::{Lptim1sel, Lptim2sel};
 use crate::peripherals::IPCC;
 use crate::rcc::sealed::RccPeripheral;
 
@@ -105,7 +104,8 @@ impl Ipcc {
         IPCC::enable_and_reset();
         IPCC::set_cpu2(true);
 
-        _configure_pwr();
+        // set RF wake-up clock = LSE
+        crate::pac::RCC.csr().modify(|w| w.set_rfwkpsel(0b01));
 
         let regs = IPCC::regs();
 
@@ -271,18 +271,3 @@ pub(crate) mod sealed {
         fn state() -> &'static State;
     }
 }
-
-fn _configure_pwr() {
-    // TODO: move the rest of this to rcc
-    let rcc = crate::pac::RCC;
-
-    // TODO: required
-    // set RF wake-up clock = LSE
-    rcc.csr().modify(|w| w.set_rfwkpsel(0b01));
-
-    // set LPTIM1 & LPTIM2 clock source
-    rcc.ccipr().modify(|w| {
-        w.set_lptim1sel(Lptim1sel::PCLK1);
-        w.set_lptim2sel(Lptim2sel::PCLK1);
-    });
-}
diff --git a/embassy-stm32/src/rcc/c0.rs b/embassy-stm32/src/rcc/c0.rs
index ec6ec34e8..1946c5a15 100644
--- a/embassy-stm32/src/rcc/c0.rs
+++ b/embassy-stm32/src/rcc/c0.rs
@@ -21,6 +21,9 @@ pub struct Config {
     pub ahb_pre: AHBPrescaler,
     pub apb_pre: APBPrescaler,
     pub ls: super::LsConfig,
+
+    /// Per-peripheral kernel clock selection muxes
+    pub mux: super::mux::ClockMux,
 }
 
 impl Default for Config {
@@ -31,6 +34,7 @@ impl Default for Config {
             ahb_pre: AHBPrescaler::DIV1,
             apb_pre: APBPrescaler::DIV1,
             ls: Default::default(),
+            mux: Default::default(),
         }
     }
 }
@@ -97,28 +101,25 @@ pub(crate) unsafe fn init(config: Config) {
 
     if !set_flash_latency_after {
         // Spin until the effective flash latency is compatible with the clock change
-        while FLASH.acr().read().latency().to_bits() < target_flash_latency.to_bits() {}
+        while FLASH.acr().read().latency() < target_flash_latency {}
     }
 
     // Configure SYSCLK source, HCLK divisor, and PCLK divisor all at once
-    let (sw, hpre, ppre) = (sw.into(), config.ahb_pre, config.apb_pre);
     RCC.cfgr().modify(|w| {
         w.set_sw(sw);
-        w.set_hpre(hpre);
-        w.set_ppre(ppre);
+        w.set_hpre(config.ahb_pre);
+        w.set_ppre(config.apb_pre);
     });
-
-    if set_flash_latency_after {
-        // We can make the flash require fewer wait states
-        // Spin until the SYSCLK changes have taken effect
-        loop {
-            let cfgr = RCC.cfgr().read();
-            if cfgr.sw() == sw && cfgr.hpre() == hpre && cfgr.ppre() == ppre {
-                break;
-            }
+    // Spin until the SYSCLK changes have taken effect
+    loop {
+        let cfgr = RCC.cfgr().read();
+        if cfgr.sw() == sw && cfgr.hpre() == config.ahb_pre && cfgr.ppre() == config.apb_pre {
+            break;
         }
+    }
 
-        // Set the flash latency to require fewer wait states
+    // Set the flash latency to require fewer wait states
+    if set_flash_latency_after {
         FLASH.acr().modify(|w| w.set_latency(target_flash_latency));
     }
 
@@ -132,6 +133,11 @@ pub(crate) unsafe fn init(config: Config) {
         }
     };
 
+    config.mux.init();
+
+    // without this, the ringbuffered uart test fails.
+    cortex_m::asm::dsb();
+
     set_clocks!(
         hsi: None,
         lse: None,
diff --git a/embassy-stm32/src/rcc/f013.rs b/embassy-stm32/src/rcc/f013.rs
index 5046f0a3a..215f8a3d2 100644
--- a/embassy-stm32/src/rcc/f013.rs
+++ b/embassy-stm32/src/rcc/f013.rs
@@ -98,8 +98,8 @@ pub struct Config {
     #[cfg(all(stm32f3, not(rcc_f37), adc3_common))]
     pub adc34: AdcClockSource,
 
-    #[cfg(clock_mux)]
-    pub mux: crate::rcc::mux::ClockMux,
+    /// Per-peripheral kernel clock selection muxes
+    pub mux: super::mux::ClockMux,
 
     pub ls: super::LsConfig,
 }
@@ -128,7 +128,6 @@ impl Default for Config {
             #[cfg(all(stm32f3, not(rcc_f37), adc3_common))]
             adc34: AdcClockSource::Hclk(AdcHclkPrescaler::Div1),
 
-            #[cfg(clock_mux)]
             mux: Default::default(),
         }
     }
@@ -370,7 +369,6 @@ pub(crate) unsafe fn init(config: Config) {
     };
      */
 
-    #[cfg(clock_mux)]
     config.mux.init();
 
     set_clocks!(
diff --git a/embassy-stm32/src/rcc/f247.rs b/embassy-stm32/src/rcc/f247.rs
index 343d075cd..7b252870c 100644
--- a/embassy-stm32/src/rcc/f247.rs
+++ b/embassy-stm32/src/rcc/f247.rs
@@ -95,6 +95,9 @@ pub struct Config {
 
     pub ls: super::LsConfig,
 
+    /// Per-peripheral kernel clock selection muxes
+    pub mux: super::mux::ClockMux,
+
     #[cfg(stm32f2)]
     pub voltage: VoltageScale,
 }
@@ -120,6 +123,7 @@ impl Default for Config {
 
             #[cfg(stm32f2)]
             voltage: VoltageScale::Range3,
+            mux: Default::default(),
         }
     }
 }
@@ -256,6 +260,8 @@ pub(crate) unsafe fn init(config: Config) {
     });
     while RCC.cfgr().read().sws() != config.sys {}
 
+    config.mux.init();
+
     set_clocks!(
         hsi: hsi,
         hse: hse,
@@ -286,7 +292,9 @@ pub(crate) unsafe fn init(config: Config) {
         #[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))]
         pllsai1_r: pllsai.r,
 
-        clk48: pll.q,
+        // TODO workaround until f4 rcc is fixed in stm32-data
+        #[cfg(not(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7)))]
+        pllsai1_q: None,
 
         hsi_div488: hsi.map(|hsi| hsi/488u32),
         hsi_hse: None,
diff --git a/embassy-stm32/src/rcc/g0.rs b/embassy-stm32/src/rcc/g0.rs
index ae502dd9c..5cfe9953b 100644
--- a/embassy-stm32/src/rcc/g0.rs
+++ b/embassy-stm32/src/rcc/g0.rs
@@ -71,22 +71,6 @@ pub enum PllSource {
     HSE(Hertz, HseMode),
 }
 
-/// Sets the source for the 48MHz clock to the USB peripheral.
-#[cfg(any(stm32g0b1, stm32g0c1, stm32g0b0))]
-pub enum UsbSrc {
-    /// Use the High Speed Internal Oscillator. The CRS must be used to calibrate the
-    /// oscillator to comply with the USB specification for oscillator tolerance.
-    #[cfg(any(stm32g0b1, stm32g0c1))]
-    Hsi48(super::Hsi48Config),
-    /// Use the PLLQ output. The PLL must be configured to output a 48MHz clock. The
-    /// PLL needs to be using the HSE source to comply with the USB specification for oscillator
-    /// tolerance.
-    PllQ,
-    /// Use the HSE source directly.  The HSE must be a 48MHz source.  The HSE source must comply
-    /// with the USB specification for oscillator tolerance.
-    HSE,
-}
-
 /// Clocks configutation
 pub struct Config {
     pub sys: Sysclk,
@@ -94,8 +78,10 @@ pub struct Config {
     pub apb_pre: APBPrescaler,
     pub low_power_run: bool,
     pub ls: super::LsConfig,
-    #[cfg(any(stm32g0b1, stm32g0c1, stm32g0b0))]
-    pub usb_src: Option<UsbSrc>,
+    #[cfg(crs)]
+    pub hsi48: Option<super::Hsi48Config>,
+    /// Per-peripheral kernel clock selection muxes
+    pub mux: super::mux::ClockMux,
 }
 
 impl Default for Config {
@@ -107,8 +93,9 @@ impl Default for Config {
             apb_pre: APBPrescaler::DIV1,
             low_power_run: false,
             ls: Default::default(),
-            #[cfg(any(stm32g0b1, stm32g0c1, stm32g0b0))]
-            usb_src: None,
+            #[cfg(crs)]
+            hsi48: Some(Default::default()),
+            mux: Default::default(),
         }
     }
 }
@@ -322,34 +309,12 @@ pub(crate) unsafe fn init(config: Config) {
     let lsi_freq = (sw == Sw::LSI).then_some(super::LSI_FREQ);
     let hse_freq = (sw == Sw::HSE).then_some(sys_clk);
 
-    #[cfg(any(stm32g0b1, stm32g0c1, stm32g0b0))]
-    let hsi48_freq = config.usb_src.and_then(|config| {
-        match config {
-            UsbSrc::PllQ => {
-                // Make sure the PLLQ is enabled and running at 48Mhz
-                assert!(pll1_q_freq.is_some() && pll1_q_freq.unwrap().0 == 48_000_000);
-                RCC.ccipr2()
-                    .modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::PLL1_Q));
-                None
-            }
-            UsbSrc::HSE => {
-                // Make sure the HSE is enabled and running at 48Mhz
-                assert!(hse_freq.is_some() && hse_freq.unwrap().0 == 48_000_000);
-                RCC.ccipr2()
-                    .modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::HSE));
-                None
-            }
-            #[cfg(any(stm32g0b1, stm32g0c1))]
-            UsbSrc::Hsi48(config) => {
-                let freq = super::init_hsi48(config);
-                RCC.ccipr2()
-                    .modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::HSI48));
-                Some(freq)
-            }
-        }
-    });
-    #[cfg(not(any(stm32g0b1, stm32g0c1, stm32g0b0)))]
-    let hsi48_freq: Option<Hertz> = None;
+    #[cfg(crs)]
+    let hsi48 = config.hsi48.map(super::init_hsi48);
+    #[cfg(not(crs))]
+    let hsi48: Option<Hertz> = None;
+
+    config.mux.init();
 
     set_clocks!(
         sys: Some(sys_clk),
@@ -357,7 +322,7 @@ pub(crate) unsafe fn init(config: Config) {
         pclk1: Some(apb_freq),
         pclk1_tim: Some(apb_tim_freq),
         hsi: hsi_freq,
-        hsi48: hsi48_freq,
+        hsi48: hsi48,
         hsi_div_8: hsi_div_8_freq,
         hse: hse_freq,
         lse: lse_freq,
diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs
index 6ed266284..79bdbeb77 100644
--- a/embassy-stm32/src/rcc/g4.rs
+++ b/embassy-stm32/src/rcc/g4.rs
@@ -1,11 +1,10 @@
 use stm32_metapac::flash::vals::Latency;
-use stm32_metapac::rcc::vals::{Adcsel, Sw};
+use stm32_metapac::rcc::vals::Sw;
 use stm32_metapac::FLASH;
 
 pub use crate::pac::rcc::vals::{
-    Adcsel as AdcClockSource, Clk48sel as Clk48Src, Fdcansel as FdCanClockSource, Hpre as AHBPrescaler,
-    Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv, Pllsrc, Ppre as APBPrescaler,
-    Sw as Sysclk,
+    Hpre as AHBPrescaler, Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv, Pllsrc,
+    Ppre as APBPrescaler, Sw as Sysclk,
 };
 use crate::pac::{PWR, RCC};
 use crate::time::Hertz;
@@ -82,24 +81,15 @@ pub struct Config {
 
     pub low_power_run: bool,
 
-    /// Sets the clock source for the 48MHz clock used by the USB and RNG peripherals.
-    pub clk48_src: Clk48Src,
-
     /// Low-Speed Clock Configuration
     pub ls: super::LsConfig,
 
-    /// Clock Source for ADCs 1 and 2
-    pub adc12_clock_source: AdcClockSource,
-
-    /// Clock Source for ADCs 3, 4 and 5
-    pub adc345_clock_source: AdcClockSource,
-
-    /// Clock Source for FDCAN
-    pub fdcan_clock_source: FdCanClockSource,
-
     /// Enable range1 boost mode
     /// Recommended when the SYSCLK frequency is greater than 150MHz.
     pub boost: bool,
+
+    /// Per-peripheral kernel clock selection muxes
+    pub mux: super::mux::ClockMux,
 }
 
 impl Default for Config {
@@ -115,12 +105,9 @@ impl Default for Config {
             apb1_pre: APBPrescaler::DIV1,
             apb2_pre: APBPrescaler::DIV1,
             low_power_run: false,
-            clk48_src: Clk48Src::HSI48,
             ls: Default::default(),
-            adc12_clock_source: Adcsel::DISABLE,
-            adc345_clock_source: Adcsel::DISABLE,
-            fdcan_clock_source: FdCanClockSource::PCLK1,
             boost: false,
+            mux: Default::default(),
         }
     }
 }
@@ -165,9 +152,7 @@ pub(crate) unsafe fn init(config: Config) {
     };
 
     // Configure HSI48 if required
-    if let Some(hsi48_config) = config.hsi48 {
-        super::init_hsi48(hsi48_config);
-    }
+    let hsi48 = config.hsi48.map(super::init_hsi48);
 
     let pll_freq = config.pll.map(|pll_config| {
         let src_freq = match pll_config.source {
@@ -176,13 +161,13 @@ pub(crate) unsafe fn init(config: Config) {
             _ => unreachable!(),
         };
 
-        assert!(max::PLL_IN.contains(&src_freq));
-
         // Disable PLL before configuration
         RCC.cr().modify(|w| w.set_pllon(false));
         while RCC.cr().read().pllrdy() {}
 
-        let internal_freq = src_freq / pll_config.prediv * pll_config.mul;
+        let in_freq = src_freq / pll_config.prediv;
+        assert!(max::PLL_IN.contains(&in_freq));
+        let internal_freq = in_freq * pll_config.mul;
 
         assert!(max::PLL_VCO.contains(&internal_freq));
 
@@ -301,42 +286,6 @@ pub(crate) unsafe fn init(config: Config) {
     let (apb1_freq, apb1_tim_freq) = super::util::calc_pclk(hclk, config.apb1_pre);
     let (apb2_freq, apb2_tim_freq) = super::util::calc_pclk(hclk, config.apb2_pre);
 
-    // Configure the 48MHz clock source for USB and RNG peripherals.
-    RCC.ccipr().modify(|w| {
-        w.set_clk48sel(match config.clk48_src {
-            Clk48Src::PLL1_Q => {
-                // Not checking that PLL1_Q is 48MHz here so as not to require the user to have a 48MHz clock.
-                // Peripherals which require one (USB, RNG) should check that they‘re driven by a valid 48MHz
-                // clock at init.
-                crate::pac::rcc::vals::Clk48sel::PLL1_Q
-            }
-            Clk48Src::HSI48 => {
-                // Make sure HSI48 is enabled
-                assert!(config.hsi48.is_some());
-                crate::pac::rcc::vals::Clk48sel::HSI48
-            }
-            _ => unreachable!(),
-        })
-    });
-
-    RCC.ccipr().modify(|w| w.set_adc12sel(config.adc12_clock_source));
-    RCC.ccipr().modify(|w| w.set_adc345sel(config.adc345_clock_source));
-    RCC.ccipr().modify(|w| w.set_fdcansel(config.fdcan_clock_source));
-
-    let adc12_ck = match config.adc12_clock_source {
-        AdcClockSource::DISABLE => None,
-        AdcClockSource::PLL1_P => pll_freq.as_ref().unwrap().pll_p,
-        AdcClockSource::SYS => Some(sys_clk),
-        _ => unreachable!(),
-    };
-
-    let adc345_ck = match config.adc345_clock_source {
-        AdcClockSource::DISABLE => None,
-        AdcClockSource::PLL1_P => pll_freq.as_ref().unwrap().pll_p,
-        AdcClockSource::SYS => Some(sys_clk),
-        _ => unreachable!(),
-    };
-
     if config.low_power_run {
         assert!(sys_clk <= Hertz(2_000_000));
         PWR.cr1().modify(|w| w.set_lpr(true));
@@ -344,6 +293,8 @@ pub(crate) unsafe fn init(config: Config) {
 
     let rtc = config.ls.init();
 
+    config.mux.init();
+
     set_clocks!(
         sys: Some(sys_clk),
         hclk1: Some(hclk),
@@ -353,12 +304,11 @@ pub(crate) unsafe fn init(config: Config) {
         pclk1_tim: Some(apb1_tim_freq),
         pclk2: Some(apb2_freq),
         pclk2_tim: Some(apb2_tim_freq),
-        adc: adc12_ck,
-        adc34: adc345_ck,
         pll1_p: pll_freq.as_ref().and_then(|pll| pll.pll_p),
         pll1_q: pll_freq.as_ref().and_then(|pll| pll.pll_q),
         pll1_r: pll_freq.as_ref().and_then(|pll| pll.pll_r),
         hse: hse,
+        hsi48: hsi48,
         rtc: rtc,
     );
 }
diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs
index 7b2255cc6..bab8bb19e 100644
--- a/embassy-stm32/src/rcc/h.rs
+++ b/embassy-stm32/src/rcc/h.rs
@@ -2,15 +2,10 @@ use core::ops::RangeInclusive;
 
 use crate::pac;
 use crate::pac::pwr::vals::Vos;
-#[cfg(stm32h5)]
-pub use crate::pac::rcc::vals::Adcdacsel as AdcClockSource;
-#[cfg(stm32h7)]
-pub use crate::pac::rcc::vals::Adcsel as AdcClockSource;
 pub use crate::pac::rcc::vals::{
-    Ckpersel as PerClockSource, Fdcansel as FdCanClockSource, Hsidiv as HSIPrescaler, Plldiv as PllDiv,
-    Pllm as PllPreDiv, Plln as PllMul, Pllsrc as PllSource, Sw as Sysclk,
+    Hsidiv as HSIPrescaler, Plldiv as PllDiv, Pllm as PllPreDiv, Plln as PllMul, Pllsrc as PllSource, Sw as Sysclk,
 };
-use crate::pac::rcc::vals::{Ckpersel, Pllrge, Pllvcosel, Timpre};
+use crate::pac::rcc::vals::{Pllrge, Pllvcosel, Timpre};
 use crate::pac::{FLASH, PWR, RCC};
 use crate::time::Hertz;
 
@@ -194,16 +189,15 @@ pub struct Config {
     #[cfg(stm32h7)]
     pub apb4_pre: APBPrescaler,
 
-    pub per_clock_source: PerClockSource,
-    pub adc_clock_source: AdcClockSource,
-    pub fdcan_clock_source: FdCanClockSource,
-
     pub timer_prescaler: TimerPrescaler,
     pub voltage_scale: VoltageScale,
     pub ls: super::LsConfig,
 
     #[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))]
     pub supply_config: SupplyConfig,
+
+    /// Per-peripheral kernel clock selection muxes
+    pub mux: super::mux::ClockMux,
 }
 
 impl Default for Config {
@@ -227,21 +221,14 @@ impl Default for Config {
             #[cfg(stm32h7)]
             apb4_pre: APBPrescaler::DIV1,
 
-            per_clock_source: PerClockSource::HSI,
-
-            #[cfg(stm32h5)]
-            adc_clock_source: AdcClockSource::HCLK1,
-            #[cfg(stm32h7)]
-            adc_clock_source: AdcClockSource::PER,
-
-            fdcan_clock_source: FdCanClockSource::from_bits(0), // HSE
-
             timer_prescaler: TimerPrescaler::DefaultX2,
             voltage_scale: VoltageScale::Scale0,
             ls: Default::default(),
 
             #[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))]
             supply_config: SupplyConfig::Default,
+
+            mux: Default::default(),
         }
     }
 }
@@ -504,31 +491,6 @@ pub(crate) unsafe fn init(config: Config) {
     #[cfg(stm32h7)]
     assert!(apb4 <= pclk_max);
 
-    let _per_ck = match config.per_clock_source {
-        Ckpersel::HSI => hsi,
-        Ckpersel::CSI => csi,
-        Ckpersel::HSE => hse,
-        _ => unreachable!(),
-    };
-
-    #[cfg(stm32h7)]
-    let adc = match config.adc_clock_source {
-        AdcClockSource::PLL2_P => pll2.p,
-        AdcClockSource::PLL3_R => pll3.r,
-        AdcClockSource::PER => _per_ck,
-        _ => unreachable!(),
-    };
-    #[cfg(stm32h5)]
-    let adc = match config.adc_clock_source {
-        AdcClockSource::HCLK1 => Some(hclk),
-        AdcClockSource::SYS => Some(sys),
-        AdcClockSource::PLL2_R => pll2.r,
-        AdcClockSource::HSE => hse,
-        AdcClockSource::HSI => hsi,
-        AdcClockSource::CSI => csi,
-        _ => unreachable!(),
-    };
-
     flash_setup(hclk, config.voltage_scale);
 
     let rtc = config.ls.init();
@@ -550,16 +512,6 @@ pub(crate) unsafe fn init(config: Config) {
         RCC.d3cfgr().modify(|w| {
             w.set_d3ppre(config.apb4_pre);
         });
-
-        RCC.d1ccipr().modify(|w| {
-            w.set_ckpersel(config.per_clock_source);
-        });
-        RCC.d3ccipr().modify(|w| {
-            w.set_adcsel(config.adc_clock_source);
-        });
-        RCC.d2ccip1r().modify(|w| {
-            w.set_fdcansel(config.fdcan_clock_source);
-        });
     }
     #[cfg(stm32h5)]
     {
@@ -573,12 +525,6 @@ pub(crate) unsafe fn init(config: Config) {
             w.set_ppre2(config.apb2_pre);
             w.set_ppre3(config.apb3_pre);
         });
-
-        RCC.ccipr5().modify(|w| {
-            w.set_ckpersel(config.per_clock_source);
-            w.set_adcdacsel(config.adc_clock_source);
-            w.set_fdcan12sel(config.fdcan_clock_source)
-        });
     }
 
     RCC.cfgr().modify(|w| w.set_timpre(config.timer_prescaler.into()));
@@ -601,6 +547,8 @@ pub(crate) unsafe fn init(config: Config) {
         while !pac::SYSCFG.cccsr().read().ready() {}
     }
 
+    config.mux.init();
+
     set_clocks!(
         sys: Some(sys),
         hclk1: Some(hclk),
@@ -614,7 +562,6 @@ pub(crate) unsafe fn init(config: Config) {
         pclk4: Some(apb4),
         pclk1_tim: Some(apb1_tim),
         pclk2_tim: Some(apb2_tim),
-        adc: adc,
         rtc: rtc,
 
         hsi: hsi,
@@ -646,7 +593,6 @@ pub(crate) unsafe fn init(config: Config) {
 
         #[cfg(stm32h5)]
         audioclk: None,
-        per: None,
         i2s_ckin: None,
     );
 }
diff --git a/embassy-stm32/src/rcc/l.rs b/embassy-stm32/src/rcc/l.rs
index aa4245d4e..9079ddd41 100644
--- a/embassy-stm32/src/rcc/l.rs
+++ b/embassy-stm32/src/rcc/l.rs
@@ -1,10 +1,6 @@
 #[cfg(any(stm32l0, stm32l1))]
 pub use crate::pac::pwr::vals::Vos as VoltageScale;
 use crate::pac::rcc::regs::Cfgr;
-#[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))]
-pub use crate::pac::rcc::vals::Adcsel as AdcClockSource;
-#[cfg(any(rcc_l0_v2, stm32l4, stm32l5, stm32wb))]
-pub use crate::pac::rcc::vals::Clk48sel as Clk48Src;
 #[cfg(any(stm32wb, stm32wl))]
 pub use crate::pac::rcc::vals::Hsepre as HsePrescaler;
 pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Msirange as MSIRange, Ppre as APBPrescaler, Sw as Sysclk};
@@ -59,18 +55,14 @@ pub struct Config {
     #[cfg(any(stm32wl, stm32wb))]
     pub shared_ahb_pre: AHBPrescaler,
 
-    // muxes
-    #[cfg(any(rcc_l0_v2, stm32l4, stm32l5, stm32wb))]
-    pub clk48_src: Clk48Src,
-
     // low speed LSI/LSE/RTC
     pub ls: super::LsConfig,
 
-    #[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))]
-    pub adc_clock_source: AdcClockSource,
-
     #[cfg(any(stm32l0, stm32l1))]
     pub voltage_scale: VoltageScale,
+
+    /// Per-peripheral kernel clock selection muxes
+    pub mux: super::mux::ClockMux,
 }
 
 impl Default for Config {
@@ -95,13 +87,10 @@ impl Default for Config {
             pllsai2: None,
             #[cfg(crs)]
             hsi48: Some(Default::default()),
-            #[cfg(any(rcc_l0_v2, stm32l4, stm32l5, stm32wb))]
-            clk48_src: Clk48Src::HSI48,
             ls: Default::default(),
-            #[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))]
-            adc_clock_source: AdcClockSource::SYS,
             #[cfg(any(stm32l0, stm32l1))]
             voltage_scale: VoltageScale::RANGE1,
+            mux: Default::default(),
         }
     }
 }
@@ -118,7 +107,6 @@ pub const WPAN_DEFAULT: Config = Config {
     hsi48: Some(super::Hsi48Config { sync_from_usb: false }),
     msi: None,
     hsi: false,
-    clk48_src: Clk48Src::PLL1_Q,
 
     ls: super::LsConfig::default_lse(),
 
@@ -137,7 +125,8 @@ pub const WPAN_DEFAULT: Config = Config {
     shared_ahb_pre: AHBPrescaler::DIV1,
     apb1_pre: APBPrescaler::DIV1,
     apb2_pre: APBPrescaler::DIV1,
-    adc_clock_source: AdcClockSource::SYS,
+
+    mux: super::mux::ClockMux::default(),
 };
 
 fn msi_enable(range: MSIRange) {
@@ -267,21 +256,6 @@ pub(crate) unsafe fn init(config: Config) {
         Sysclk::PLL1_R => pll.r.unwrap(),
     };
 
-    #[cfg(any(rcc_l0_v2, stm32l4, stm32l5, stm32wb))]
-    RCC.ccipr().modify(|w| w.set_clk48sel(config.clk48_src));
-    #[cfg(any(rcc_l0_v2))]
-    let clk48 = match config.clk48_src {
-        Clk48Src::HSI48 => hsi48,
-        Clk48Src::PLL1_VCO_DIV_2 => pll.clk48,
-    };
-    #[cfg(any(stm32l4, stm32l5, stm32wb))]
-    let clk48 = match config.clk48_src {
-        Clk48Src::HSI48 => hsi48,
-        Clk48Src::MSI => msi,
-        Clk48Src::PLLSAI1_Q => pllsai1.q,
-        Clk48Src::PLL1_Q => pll.q,
-    };
-
     #[cfg(rcc_l4plus)]
     assert!(sys_clk.0 <= 120_000_000);
     #[cfg(all(stm32l4, not(rcc_l4plus)))]
@@ -357,9 +331,6 @@ pub(crate) unsafe fn init(config: Config) {
     });
     while RCC.cfgr().read().sws() != config.sys {}
 
-    #[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))]
-    RCC.ccipr().modify(|w| w.set_adcsel(config.adc_clock_source));
-
     #[cfg(any(stm32wl, stm32wb))]
     {
         RCC.extcfgr().modify(|w| {
@@ -372,6 +343,8 @@ pub(crate) unsafe fn init(config: Config) {
         while !RCC.extcfgr().read().c2hpref() {}
     }
 
+    config.mux.init();
+
     set_clocks!(
         sys: Some(sys_clk),
         hclk1: Some(hclk1),
@@ -388,10 +361,11 @@ pub(crate) unsafe fn init(config: Config) {
         hsi: hsi,
         hse: hse,
         msi: msi,
-        #[cfg(any(rcc_l0_v2, stm32l4, stm32l5, stm32wb))]
-        clk48: clk48,
         hsi48: hsi48,
 
+        #[cfg(any(stm32l0, stm32l1))]
+        pll1_vco_div_2: pll.vco.map(|c| c/2u32),
+
         #[cfg(not(any(stm32l0, stm32l1)))]
         pll1_p: pll.p,
         #[cfg(not(any(stm32l0, stm32l1)))]
@@ -511,7 +485,7 @@ mod pll {
     #[derive(Default)]
     pub(super) struct PllOutput {
         pub r: Option<Hertz>,
-        pub clk48: Option<Hertz>,
+        pub vco: Option<Hertz>,
     }
 
     pub(super) fn init_pll(instance: PllInstance, config: Option<Pll>, input: &PllInput) -> PllOutput {
@@ -528,7 +502,6 @@ mod pll {
         let vco_freq = pll_src * pll.mul;
 
         let r = vco_freq / pll.div;
-        let clk48 = (vco_freq == Hertz(96_000_000)).then_some(Hertz(48_000_000));
 
         assert!(r <= Hertz(32_000_000));
 
@@ -541,7 +514,10 @@ mod pll {
         // Enable PLL
         pll_enable(instance, true);
 
-        PllOutput { r: Some(r), clk48 }
+        PllOutput {
+            r: Some(r),
+            vco: Some(vco_freq),
+        }
     }
 }
 
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs
index c8ca713de..910ebe205 100644
--- a/embassy-stm32/src/rcc/mod.rs
+++ b/embassy-stm32/src/rcc/mod.rs
@@ -31,9 +31,7 @@ mod _version;
 
 pub use _version::*;
 
-#[cfg(clock_mux)]
-pub use crate::_generated::mux;
-pub use crate::_generated::Clocks;
+pub use crate::_generated::{mux, Clocks};
 
 #[cfg(feature = "low-power")]
 /// Must be written within a critical section
diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs
index c8814ed69..9533e16c4 100644
--- a/embassy-stm32/src/rcc/u5.rs
+++ b/embassy-stm32/src/rcc/u5.rs
@@ -85,6 +85,9 @@ pub struct Config {
     /// See RM0456 § 10.5.4 for a general overview and § 11.4.10 for clock source frequency limits.
     pub voltage_range: VoltageScale,
     pub ls: super::LsConfig,
+
+    /// Per-peripheral kernel clock selection muxes
+    pub mux: super::mux::ClockMux,
 }
 
 impl Default for Config {
@@ -104,6 +107,7 @@ impl Default for Config {
             apb3_pre: APBPrescaler::DIV1,
             voltage_range: VoltageScale::RANGE1,
             ls: Default::default(),
+            mux: Default::default(),
         }
     }
 }
@@ -259,6 +263,8 @@ pub(crate) unsafe fn init(config: Config) {
 
     let rtc = config.ls.init();
 
+    config.mux.init();
+
     set_clocks!(
         sys: Some(sys_clk),
         hclk1: Some(hclk),
@@ -289,7 +295,6 @@ pub(crate) unsafe fn init(config: Config) {
         lse: None,
         lsi: None,
         msik: None,
-        iclk: None,
         shsi: None,
         shsi_div_2: None,
     );
diff --git a/embassy-stm32/src/rcc/wba.rs b/embassy-stm32/src/rcc/wba.rs
index 9d5dcfc4b..8e1779d7c 100644
--- a/embassy-stm32/src/rcc/wba.rs
+++ b/embassy-stm32/src/rcc/wba.rs
@@ -1,8 +1,6 @@
 pub use crate::pac::pwr::vals::Vos as VoltageScale;
 use crate::pac::rcc::regs::Cfgr1;
-pub use crate::pac::rcc::vals::{
-    Adcsel as AdcClockSource, Hpre as AHBPrescaler, Hsepre as HsePrescaler, Ppre as APBPrescaler, Sw as Sysclk,
-};
+pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Hsepre as HsePrescaler, Ppre as APBPrescaler, Sw as Sysclk};
 use crate::pac::{FLASH, RCC};
 use crate::time::Hertz;
 
@@ -32,9 +30,10 @@ pub struct Config {
     // low speed LSI/LSE/RTC
     pub ls: super::LsConfig,
 
-    pub adc_clock_source: AdcClockSource,
-
     pub voltage_scale: VoltageScale,
+
+    /// Per-peripheral kernel clock selection muxes
+    pub mux: super::mux::ClockMux,
 }
 
 impl Default for Config {
@@ -49,8 +48,8 @@ impl Default for Config {
             apb2_pre: APBPrescaler::DIV1,
             apb7_pre: APBPrescaler::DIV1,
             ls: Default::default(),
-            adc_clock_source: AdcClockSource::HCLK4,
             voltage_scale: VoltageScale::RANGE2,
+            mux: Default::default(),
         }
     }
 }
@@ -152,7 +151,7 @@ pub(crate) unsafe fn init(config: Config) {
         w.set_ppre2(config.apb2_pre);
     });
 
-    RCC.ccipr3().modify(|w| w.set_adcsel(config.adc_clock_source));
+    config.mux.init();
 
     set_clocks!(
         sys: Some(sys_clk),
diff --git a/embassy-stm32/src/usb_otg/usb.rs b/embassy-stm32/src/usb_otg/usb.rs
index 190fb274f..373697ec8 100644
--- a/embassy-stm32/src/usb_otg/usb.rs
+++ b/embassy-stm32/src/usb_otg/usb.rs
@@ -606,13 +606,6 @@ impl<'d, T: Instance> Bus<'d, T> {
             // Wait for USB power to stabilize
             while !crate::pac::PWR.cr3().read().usb33rdy() {}
 
-            // Use internal 48MHz HSI clock. Should be enabled in RCC by default.
-            critical_section::with(|_| {
-                crate::pac::RCC
-                    .d2ccip2r()
-                    .modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::HSI48))
-            });
-
             // Enable ULPI clock if external PHY is used
             let ulpien = !self.phy_type.internal();
             critical_section::with(|_| {
@@ -645,13 +638,6 @@ impl<'d, T: Instance> Bus<'d, T> {
 
             // Wait for USB power to stabilize
             while !crate::pac::PWR.svmsr().read().vddusbrdy() {}
-
-            // Select HSI48 as USB clock source.
-            critical_section::with(|_| {
-                crate::pac::RCC.ccipr1().modify(|w| {
-                    w.set_iclksel(crate::pac::rcc::vals::Iclksel::HSI48);
-                })
-            });
         }
 
         <T as RccPeripheral>::enable_and_reset();
diff --git a/examples/stm32f334/src/bin/pwm.rs b/examples/stm32f334/src/bin/pwm.rs
index 7c6d6cd71..e6d1a6c02 100644
--- a/examples/stm32f334/src/bin/pwm.rs
+++ b/examples/stm32f334/src/bin/pwm.rs
@@ -28,7 +28,7 @@ async fn main(_spawner: Spawner) {
         config.rcc.apb1_pre = APBPrescaler::DIV2;
         config.rcc.apb2_pre = APBPrescaler::DIV1;
 
-        config.rcc.mux.hrtim1sw = Some(embassy_stm32::rcc::mux::Timsw::PLL1_P);
+        config.rcc.mux.hrtim1sw = embassy_stm32::rcc::mux::Timsw::PLL1_P;
     }
     let p = embassy_stm32::init(config);
 
diff --git a/examples/stm32g0/src/bin/hf_timer.rs b/examples/stm32g0/src/bin/hf_timer.rs
index 3f63d0dfd..647ff0419 100644
--- a/examples/stm32g0/src/bin/hf_timer.rs
+++ b/examples/stm32g0/src/bin/hf_timer.rs
@@ -4,37 +4,35 @@
 use defmt::info;
 use embassy_executor::Spawner;
 use embassy_stm32::gpio::OutputType;
-use embassy_stm32::pac::rcc::vals::Tim1sel;
-use embassy_stm32::rcc::{Config as RccConfig, PllConfig, PllSource, Pllm, Plln, Pllq, Pllr, Sysclk};
 use embassy_stm32::time::khz;
 use embassy_stm32::timer::complementary_pwm::{ComplementaryPwm, ComplementaryPwmPin};
 use embassy_stm32::timer::simple_pwm::PwmPin;
 use embassy_stm32::timer::Channel;
-use embassy_stm32::{pac, Config as PeripheralConfig};
+use embassy_stm32::Config as PeripheralConfig;
 use {defmt_rtt as _, panic_probe as _};
 
 #[embassy_executor::main]
 async fn main(_spawner: Spawner) {
-    let mut rcc_config = RccConfig::default();
-    rcc_config.sys = Sysclk::PLL(PllConfig {
-        source: PllSource::HSI,
-        m: Pllm::DIV1,
-        n: Plln::MUL16,
-        r: Pllr::DIV4,       // CPU clock comes from PLLR (HSI (16MHz) / 1 * 16 / 4 = 64MHz)
-        q: Some(Pllq::DIV2), // TIM1 or TIM15 can be sourced from PLLQ (HSI (16MHz) / 1 * 16 / 2 = 128MHz)
-        p: None,
-    });
+    let mut config = PeripheralConfig::default();
+    {
+        use embassy_stm32::rcc::*;
 
-    let mut peripheral_config = PeripheralConfig::default();
-    peripheral_config.rcc = rcc_config;
+        config.rcc.sys = Sysclk::PLL(PllConfig {
+            source: PllSource::HSI,
+            m: Pllm::DIV1,
+            n: Plln::MUL16,
+            r: Pllr::DIV4,       // CPU clock comes from PLLR (HSI (16MHz) / 1 * 16 / 4 = 64MHz)
+            q: Some(Pllq::DIV2), // TIM1 or TIM15 can be sourced from PLLQ (HSI (16MHz) / 1 * 16 / 2 = 128MHz)
+            p: None,
+        });
 
-    let p = embassy_stm32::init(peripheral_config);
-
-    // configure TIM1 mux to select PLLQ as clock source
-    // https://www.st.com/resource/en/reference_manual/rm0444-stm32g0x1-advanced-armbased-32bit-mcus-stmicroelectronics.pdf
-    // RM0444 page 210
-    // RCC - Peripherals Independent Clock Control Register - bit 22 -> 1
-    pac::RCC.ccipr().modify(|w| w.set_tim1sel(Tim1sel::PLL1_Q));
+        // configure TIM1 mux to select PLLQ as clock source
+        // https://www.st.com/resource/en/reference_manual/rm0444-stm32g0x1-advanced-armbased-32bit-mcus-stmicroelectronics.pdf
+        // RM0444 page 210
+        // RCC - Peripherals Independent Clock Control Register - bit 22 -> 1
+        config.rcc.mux.tim1sel = embassy_stm32::rcc::mux::Tim1sel::PLL1_Q;
+    }
+    let p = embassy_stm32::init(config);
 
     let ch1 = PwmPin::new_ch1(p.PA8, OutputType::PushPull);
     let ch1n = ComplementaryPwmPin::new_ch1(p.PA7, OutputType::PushPull);
diff --git a/examples/stm32g0/src/bin/usb_serial.rs b/examples/stm32g0/src/bin/usb_serial.rs
index f5aaa5624..8b9915626 100644
--- a/examples/stm32g0/src/bin/usb_serial.rs
+++ b/examples/stm32g0/src/bin/usb_serial.rs
@@ -4,7 +4,6 @@
 use defmt::{panic, *};
 use embassy_executor::Spawner;
 use embassy_futures::join::join;
-use embassy_stm32::rcc::{Hsi48Config, UsbSrc};
 use embassy_stm32::usb::{Driver, Instance};
 use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
 use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
@@ -19,10 +18,11 @@ bind_interrupts!(struct Irqs {
 #[embassy_executor::main]
 async fn main(_spawner: Spawner) {
     let mut config = Config::default();
-    config.rcc.usb_src = Some(UsbSrc::Hsi48(Hsi48Config {
-        sync_from_usb: true,
-        ..Default::default()
-    }));
+    {
+        use embassy_stm32::rcc::*;
+        config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true });
+        config.rcc.mux.usbsel = mux::Usbsel::HSI48;
+    }
     let p = embassy_stm32::init(config);
 
     info!("Hello World!");
diff --git a/examples/stm32g4/src/bin/adc.rs b/examples/stm32g4/src/bin/adc.rs
index 6c6de1ffe..f81335f93 100644
--- a/examples/stm32g4/src/bin/adc.rs
+++ b/examples/stm32g4/src/bin/adc.rs
@@ -4,7 +4,6 @@
 use defmt::*;
 use embassy_executor::Spawner;
 use embassy_stm32::adc::{Adc, SampleTime};
-use embassy_stm32::rcc::{AdcClockSource, Pll, PllMul, PllPreDiv, PllRDiv, Pllsrc, Sysclk};
 use embassy_stm32::Config;
 use embassy_time::{Delay, Timer};
 use {defmt_rtt as _, panic_probe as _};
@@ -12,20 +11,20 @@ use {defmt_rtt as _, panic_probe as _};
 #[embassy_executor::main]
 async fn main(_spawner: Spawner) {
     let mut config = Config::default();
-
-    config.rcc.pll = Some(Pll {
-        source: Pllsrc::HSI,
-        prediv: PllPreDiv::DIV4,
-        mul: PllMul::MUL85,
-        divp: None,
-        divq: None,
-        // Main system clock at 170 MHz
-        divr: Some(PllRDiv::DIV2),
-    });
-
-    config.rcc.adc12_clock_source = AdcClockSource::SYS;
-    config.rcc.sys = Sysclk::PLL1_R;
-
+    {
+        use embassy_stm32::rcc::*;
+        config.rcc.pll = Some(Pll {
+            source: Pllsrc::HSI,
+            prediv: PllPreDiv::DIV4,
+            mul: PllMul::MUL85,
+            divp: None,
+            divq: None,
+            // Main system clock at 170 MHz
+            divr: Some(PllRDiv::DIV2),
+        });
+        config.rcc.mux.adc12sel = mux::Adcsel::SYS;
+        config.rcc.sys = Sysclk::PLL1_R;
+    }
     let mut p = embassy_stm32::init(config);
     info!("Hello World!");
 
diff --git a/examples/stm32g4/src/bin/can.rs b/examples/stm32g4/src/bin/can.rs
index a41f765c1..7551b2a55 100644
--- a/examples/stm32g4/src/bin/can.rs
+++ b/examples/stm32g4/src/bin/can.rs
@@ -3,6 +3,7 @@
 use defmt::*;
 use embassy_executor::Spawner;
 use embassy_stm32::peripherals::*;
+use embassy_stm32::time::Hertz;
 use embassy_stm32::{bind_interrupts, can, Config};
 use embassy_time::Timer;
 use static_cell::StaticCell;
@@ -15,8 +16,24 @@ bind_interrupts!(struct Irqs {
 
 #[embassy_executor::main]
 async fn main(_spawner: Spawner) {
-    let config = Config::default();
-
+    let mut config = Config::default();
+    {
+        use embassy_stm32::rcc::*;
+        config.rcc.hse = Some(Hse {
+            freq: Hertz(24_000_000),
+            mode: HseMode::Oscillator,
+        });
+        config.rcc.pll = Some(Pll {
+            source: Pllsrc::HSE,
+            prediv: PllPreDiv::DIV6,
+            mul: PllMul::MUL85,
+            divp: None,
+            divq: Some(PllQDiv::DIV8), // 42.5 Mhz for fdcan.
+            divr: Some(PllRDiv::DIV2), // Main system clock at 170 MHz
+        });
+        config.rcc.mux.fdcansel = mux::Fdcansel::PLL1_Q;
+        config.rcc.sys = Sysclk::PLL1_R;
+    }
     let peripherals = embassy_stm32::init(config);
 
     let mut can = can::FdcanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs);
diff --git a/examples/stm32g4/src/bin/pll.rs b/examples/stm32g4/src/bin/pll.rs
index 5274de79d..2609abfa2 100644
--- a/examples/stm32g4/src/bin/pll.rs
+++ b/examples/stm32g4/src/bin/pll.rs
@@ -12,6 +12,7 @@ use {defmt_rtt as _, panic_probe as _};
 async fn main(_spawner: Spawner) {
     let mut config = Config::default();
 
+    config.rcc.hsi = true;
     config.rcc.pll = Some(Pll {
         source: Pllsrc::HSI,
         prediv: PllPreDiv::DIV4,
diff --git a/examples/stm32g4/src/bin/usb_serial.rs b/examples/stm32g4/src/bin/usb_serial.rs
index 989fef5b0..90caaae14 100644
--- a/examples/stm32g4/src/bin/usb_serial.rs
+++ b/examples/stm32g4/src/bin/usb_serial.rs
@@ -3,9 +3,6 @@
 
 use defmt::{panic, *};
 use embassy_executor::Spawner;
-use embassy_stm32::rcc::{
-    Clk48Src, Hse, HseMode, Hsi48Config, Pll, PllMul, PllPreDiv, PllQDiv, PllRDiv, Pllsrc, Sysclk,
-};
 use embassy_stm32::time::Hertz;
 use embassy_stm32::usb::{self, Driver, Instance};
 use embassy_stm32::{bind_interrupts, peripherals, Config};
@@ -22,38 +19,27 @@ bind_interrupts!(struct Irqs {
 #[embassy_executor::main]
 async fn main(_spawner: Spawner) {
     let mut config = Config::default();
-
-    // Change this to `false` to use the HSE clock source for the USB. This example assumes an 8MHz HSE.
-    const USE_HSI48: bool = true;
-
-    let plldivq = if USE_HSI48 { None } else { Some(PllQDiv::DIV6) };
-
-    config.rcc.hse = Some(Hse {
-        freq: Hertz(8_000_000),
-        mode: HseMode::Oscillator,
-    });
-
-    config.rcc.pll = Some(Pll {
-        source: Pllsrc::HSE,
-        prediv: PllPreDiv::DIV2,
-        mul: PllMul::MUL72,
-        divp: None,
-        divq: plldivq,
-        // Main system clock at 144 MHz
-        divr: Some(PllRDiv::DIV2),
-    });
-
-    config.rcc.sys = Sysclk::PLL1_R;
-    config.rcc.boost = true; // BOOST!
-
-    if USE_HSI48 {
+    {
+        use embassy_stm32::rcc::*;
         // Sets up the Clock Recovery System (CRS) to use the USB SOF to trim the HSI48 oscillator.
         config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true });
-        config.rcc.clk48_src = Clk48Src::HSI48;
-    } else {
-        config.rcc.clk48_src = Clk48Src::PLL1_Q;
+        config.rcc.hse = Some(Hse {
+            freq: Hertz(8_000_000),
+            mode: HseMode::Oscillator,
+        });
+        config.rcc.pll = Some(Pll {
+            source: Pllsrc::HSE,
+            prediv: PllPreDiv::DIV2,
+            mul: PllMul::MUL72,
+            divp: None,
+            divq: Some(PllQDiv::DIV6), // 48mhz
+            divr: Some(PllRDiv::DIV2), // Main system clock at 144 MHz
+        });
+        config.rcc.sys = Sysclk::PLL1_R;
+        config.rcc.boost = true; // BOOST!
+        config.rcc.mux.clk48sel = mux::Clk48sel::HSI48;
+        //config.rcc.mux.clk48sel = mux::Clk48sel::PLL1_Q; // uncomment to use PLL1_Q instead.
     }
-
     let p = embassy_stm32::init(config);
 
     info!("Hello World!");
diff --git a/examples/stm32h5/src/bin/can.rs b/examples/stm32h5/src/bin/can.rs
index e5ccfe4f7..643df27f9 100644
--- a/examples/stm32h5/src/bin/can.rs
+++ b/examples/stm32h5/src/bin/can.rs
@@ -20,7 +20,7 @@ async fn main(_spawner: Spawner) {
         freq: embassy_stm32::time::Hertz(25_000_000),
         mode: rcc::HseMode::Oscillator,
     });
-    config.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE;
+    config.rcc.mux.fdcan12sel = rcc::mux::Fdcansel::HSE;
 
     let peripherals = embassy_stm32::init(config);
 
diff --git a/examples/stm32h5/src/bin/usb_serial.rs b/examples/stm32h5/src/bin/usb_serial.rs
index 208493d8c..83477c8fa 100644
--- a/examples/stm32h5/src/bin/usb_serial.rs
+++ b/examples/stm32h5/src/bin/usb_serial.rs
@@ -5,7 +5,7 @@ use defmt::{panic, *};
 use embassy_executor::Spawner;
 use embassy_stm32::time::Hertz;
 use embassy_stm32::usb::{Driver, Instance};
-use embassy_stm32::{bind_interrupts, pac, peripherals, usb, Config};
+use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
 use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
 use embassy_usb::driver::EndpointError;
 use embassy_usb::Builder;
@@ -41,15 +41,12 @@ async fn main(_spawner: Spawner) {
         config.rcc.apb3_pre = APBPrescaler::DIV4;
         config.rcc.sys = Sysclk::PLL1_P;
         config.rcc.voltage_scale = VoltageScale::Scale0;
+        config.rcc.mux.usbsel = mux::Usbsel::HSI48;
     }
     let p = embassy_stm32::init(config);
 
     info!("Hello World!");
 
-    pac::RCC.ccipr4().write(|w| {
-        w.set_usbsel(pac::rcc::vals::Usbsel::HSI48);
-    });
-
     // Create the driver, from the HAL.
     let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11);
 
diff --git a/examples/stm32h7/src/bin/adc.rs b/examples/stm32h7/src/bin/adc.rs
index f0278239f..a5594d10c 100644
--- a/examples/stm32h7/src/bin/adc.rs
+++ b/examples/stm32h7/src/bin/adc.rs
@@ -38,7 +38,7 @@ async fn main(_spawner: Spawner) {
         config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
         config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
         config.rcc.voltage_scale = VoltageScale::Scale1;
-        config.rcc.adc_clock_source = AdcClockSource::PLL2_P;
+        config.rcc.mux.adcsel = mux::Adcsel::PLL2_P;
     }
     let mut p = embassy_stm32::init(config);
 
diff --git a/examples/stm32h7/src/bin/can.rs b/examples/stm32h7/src/bin/can.rs
index e5ccfe4f7..13a6a5051 100644
--- a/examples/stm32h7/src/bin/can.rs
+++ b/examples/stm32h7/src/bin/can.rs
@@ -20,7 +20,7 @@ async fn main(_spawner: Spawner) {
         freq: embassy_stm32::time::Hertz(25_000_000),
         mode: rcc::HseMode::Oscillator,
     });
-    config.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE;
+    config.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE;
 
     let peripherals = embassy_stm32::init(config);
 
diff --git a/examples/stm32h7/src/bin/dac.rs b/examples/stm32h7/src/bin/dac.rs
index a9bf46de0..a6f969aba 100644
--- a/examples/stm32h7/src/bin/dac.rs
+++ b/examples/stm32h7/src/bin/dac.rs
@@ -40,7 +40,7 @@ fn main() -> ! {
         config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
         config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
         config.rcc.voltage_scale = VoltageScale::Scale1;
-        config.rcc.adc_clock_source = AdcClockSource::PLL2_P;
+        config.rcc.mux.adcsel = mux::Adcsel::PLL2_P;
     }
     let p = embassy_stm32::init(config);
 
diff --git a/examples/stm32h7/src/bin/dac_dma.rs b/examples/stm32h7/src/bin/dac_dma.rs
index d88bd838f..feec28993 100644
--- a/examples/stm32h7/src/bin/dac_dma.rs
+++ b/examples/stm32h7/src/bin/dac_dma.rs
@@ -42,7 +42,7 @@ async fn main(spawner: Spawner) {
         config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
         config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
         config.rcc.voltage_scale = VoltageScale::Scale1;
-        config.rcc.adc_clock_source = AdcClockSource::PLL2_P;
+        config.rcc.mux.adcsel = mux::Adcsel::PLL2_P;
     }
 
     // Initialize the board and obtain a Peripherals instance
diff --git a/examples/stm32l4/src/bin/adc.rs b/examples/stm32l4/src/bin/adc.rs
index 910944673..a9f4604aa 100644
--- a/examples/stm32l4/src/bin/adc.rs
+++ b/examples/stm32l4/src/bin/adc.rs
@@ -3,7 +3,7 @@
 
 use defmt::*;
 use embassy_stm32::adc::{Adc, Resolution};
-use embassy_stm32::pac;
+use embassy_stm32::Config;
 use embassy_time::Delay;
 use {defmt_rtt as _, panic_probe as _};
 
@@ -11,12 +11,12 @@ use {defmt_rtt as _, panic_probe as _};
 fn main() -> ! {
     info!("Hello World!");
 
-    pac::RCC.ccipr().modify(|w| {
-        w.set_adcsel(pac::rcc::vals::Adcsel::SYS);
-    });
-    pac::RCC.ahb2enr().modify(|w| w.set_adcen(true));
-
-    let p = embassy_stm32::init(Default::default());
+    let mut config = Config::default();
+    {
+        use embassy_stm32::rcc::*;
+        config.rcc.mux.adcsel = mux::Adcsel::SYS;
+    }
+    let p = embassy_stm32::init(config);
 
     let mut adc = Adc::new(p.ADC1, &mut Delay);
     //adc.enable_vref();
diff --git a/tests/stm32/src/bin/fdcan.rs b/tests/stm32/src/bin/fdcan.rs
index f21aa797c..dd78d7fb3 100644
--- a/tests/stm32/src/bin/fdcan.rs
+++ b/tests/stm32/src/bin/fdcan.rs
@@ -33,7 +33,7 @@ fn options() -> TestOptions {
         freq: embassy_stm32::time::Hertz(25_000_000),
         mode: rcc::HseMode::Oscillator,
     });
-    c.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE;
+    c.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE;
     TestOptions {
         config: c,
         max_latency: Duration::from_micros(1200),
@@ -50,7 +50,7 @@ fn options() -> TestOptions {
         freq: embassy_stm32::time::Hertz(25_000_000),
         mode: rcc::HseMode::Oscillator,
     });
-    c.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE;
+    c.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE;
     TestOptions {
         config: c,
         max_latency: Duration::from_micros(1200),
diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs
index 7b9585afd..cf3e04a4b 100644
--- a/tests/stm32/src/common.rs
+++ b/tests/stm32/src/common.rs
@@ -2,6 +2,8 @@
 
 pub use defmt::*;
 #[allow(unused)]
+use embassy_stm32::rcc::*;
+#[allow(unused)]
 use embassy_stm32::time::Hertz;
 use embassy_stm32::Config;
 use {defmt_rtt as _, panic_probe as _};
@@ -265,7 +267,6 @@ pub fn config() -> Config {
 
     #[cfg(feature = "stm32f091rc")]
     {
-        use embassy_stm32::rcc::*;
         config.rcc.hse = Some(Hse {
             freq: Hertz(8_000_000),
             mode: HseMode::Bypass,
@@ -281,7 +282,6 @@ pub fn config() -> Config {
     }
     #[cfg(feature = "stm32f103c8")]
     {
-        use embassy_stm32::rcc::*;
         config.rcc.hse = Some(Hse {
             freq: Hertz(8_000_000),
             mode: HseMode::Oscillator,
@@ -298,7 +298,6 @@ pub fn config() -> Config {
     }
     #[cfg(feature = "stm32f207zg")]
     {
-        use embassy_stm32::rcc::*;
         // By default, HSE on the board comes from a 8 MHz clock signal (not a crystal)
         config.rcc.hse = Some(Hse {
             freq: Hertz(8_000_000),
@@ -327,7 +326,6 @@ pub fn config() -> Config {
 
     #[cfg(feature = "stm32f303ze")]
     {
-        use embassy_stm32::rcc::*;
         config.rcc.hse = Some(Hse {
             freq: Hertz(8_000_000),
             mode: HseMode::Bypass,
@@ -345,7 +343,6 @@ pub fn config() -> Config {
 
     #[cfg(feature = "stm32f429zi")]
     {
-        use embassy_stm32::rcc::*;
         config.rcc.hse = Some(Hse {
             freq: Hertz(8_000_000),
             mode: HseMode::Bypass,
@@ -366,7 +363,6 @@ pub fn config() -> Config {
 
     #[cfg(feature = "stm32f446re")]
     {
-        use embassy_stm32::rcc::*;
         config.rcc.hse = Some(Hse {
             freq: Hertz(8_000_000),
             mode: HseMode::Oscillator,
@@ -387,7 +383,6 @@ pub fn config() -> Config {
 
     #[cfg(feature = "stm32f767zi")]
     {
-        use embassy_stm32::rcc::*;
         config.rcc.hse = Some(Hse {
             freq: Hertz(8_000_000),
             mode: HseMode::Bypass,
@@ -408,7 +403,6 @@ pub fn config() -> Config {
 
     #[cfg(feature = "stm32h563zi")]
     {
-        use embassy_stm32::rcc::*;
         config.rcc.hsi = None;
         config.rcc.hsi48 = Some(Default::default()); // needed for RNG
         config.rcc.hse = Some(Hse {
@@ -433,7 +427,6 @@ pub fn config() -> Config {
 
     #[cfg(feature = "stm32h503rb")]
     {
-        use embassy_stm32::rcc::*;
         config.rcc.hsi = None;
         config.rcc.hsi48 = Some(Default::default()); // needed for RNG
         config.rcc.hse = Some(Hse {
@@ -456,9 +449,26 @@ pub fn config() -> Config {
         config.rcc.voltage_scale = VoltageScale::Scale0;
     }
 
+    #[cfg(feature = "stm32g491re")]
+    {
+        config.rcc.hse = Some(Hse {
+            freq: Hertz(24_000_000),
+            mode: HseMode::Oscillator,
+        });
+        config.rcc.pll = Some(Pll {
+            source: Pllsrc::HSE,
+            prediv: PllPreDiv::DIV6,
+            mul: PllMul::MUL85,
+            divp: None,
+            divq: Some(PllQDiv::DIV8), // 42.5 Mhz for fdcan.
+            divr: Some(PllRDiv::DIV2), // Main system clock at 170 MHz
+        });
+        config.rcc.mux.fdcansel = mux::Fdcansel::PLL1_Q;
+        config.rcc.sys = Sysclk::PLL1_R;
+    }
+
     #[cfg(any(feature = "stm32h755zi", feature = "stm32h753zi"))]
     {
-        use embassy_stm32::rcc::*;
         config.rcc.hsi = Some(HSIPrescaler::DIV1);
         config.rcc.csi = true;
         config.rcc.hsi48 = Some(Default::default()); // needed for RNG
@@ -485,7 +495,7 @@ pub fn config() -> Config {
         config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
         config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
         config.rcc.voltage_scale = VoltageScale::Scale1;
-        config.rcc.adc_clock_source = AdcClockSource::PLL2_P;
+        config.rcc.mux.adcsel = mux::Adcsel::PLL2_P;
         #[cfg(any(feature = "stm32h755zi"))]
         {
             config.rcc.supply_config = SupplyConfig::DirectSMPS;
@@ -494,7 +504,6 @@ pub fn config() -> Config {
 
     #[cfg(any(feature = "stm32h7a3zi"))]
     {
-        use embassy_stm32::rcc::*;
         config.rcc.hsi = Some(HSIPrescaler::DIV1);
         config.rcc.csi = true;
         config.rcc.hsi48 = Some(Default::default()); // needed for RNG
@@ -521,12 +530,11 @@ pub fn config() -> Config {
         config.rcc.apb3_pre = APBPrescaler::DIV2; // 140 Mhz
         config.rcc.apb4_pre = APBPrescaler::DIV2; // 140 Mhz
         config.rcc.voltage_scale = VoltageScale::Scale0;
-        config.rcc.adc_clock_source = AdcClockSource::PLL2_P;
+        config.rcc.mux.adcsel = mux::Adcsel::PLL2_P;
     }
 
     #[cfg(any(feature = "stm32l496zg", feature = "stm32l4a6zg", feature = "stm32l4r5zi"))]
     {
-        use embassy_stm32::rcc::*;
         config.rcc.sys = Sysclk::PLL1_R;
         config.rcc.hsi = true;
         config.rcc.pll = Some(Pll {
@@ -541,7 +549,6 @@ pub fn config() -> Config {
 
     #[cfg(feature = "stm32wl55jc")]
     {
-        use embassy_stm32::rcc::*;
         config.rcc.hse = Some(Hse {
             freq: Hertz(32_000_000),
             mode: HseMode::Bypass,
@@ -560,7 +567,6 @@ pub fn config() -> Config {
 
     #[cfg(any(feature = "stm32l552ze"))]
     {
-        use embassy_stm32::rcc::*;
         config.rcc.hsi = true;
         config.rcc.sys = Sysclk::PLL1_R;
         config.rcc.pll = Some(Pll {
@@ -576,7 +582,6 @@ pub fn config() -> Config {
 
     #[cfg(any(feature = "stm32u585ai", feature = "stm32u5a5zj"))]
     {
-        use embassy_stm32::rcc::*;
         config.rcc.hsi = true;
         config.rcc.pll1 = Some(Pll {
             source: PllSource::HSI, // 16 MHz
@@ -593,17 +598,12 @@ pub fn config() -> Config {
 
     #[cfg(feature = "stm32wba52cg")]
     {
-        use embassy_stm32::rcc::*;
         config.rcc.sys = Sysclk::HSI;
-
-        embassy_stm32::pac::RCC.ccipr2().write(|w| {
-            w.set_rngsel(embassy_stm32::pac::rcc::vals::Rngsel::HSI);
-        });
+        config.rcc.mux.rngsel = mux::Rngsel::HSI;
     }
 
     #[cfg(feature = "stm32l073rz")]
     {
-        use embassy_stm32::rcc::*;
         config.rcc.hsi = true;
         config.rcc.pll = Some(Pll {
             source: PllSource::HSI,
@@ -615,7 +615,6 @@ pub fn config() -> Config {
 
     #[cfg(any(feature = "stm32l152re"))]
     {
-        use embassy_stm32::rcc::*;
         config.rcc.hsi = true;
         config.rcc.pll = Some(Pll {
             source: PllSource::HSI,