diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index 7bf6ffba2..6c524ced6 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -367,9 +367,6 @@ fn main() {
         .filter_map(|p| p.registers.as_ref())
         .find(|r| r.kind == "rcc")
         .unwrap();
-    for b in rcc_registers.ir.blocks {
-        eprintln!("{}", b.name);
-    }
     let rcc_block = rcc_registers.ir.blocks.iter().find(|b| b.name == "Rcc").unwrap();
 
     // ========
@@ -388,7 +385,6 @@ fn main() {
         rcc_registers: &'a PeripheralRegisters,
         chained_muxes: HashMap<&'a str, &'a PeripheralRccRegister>,
 
-        refcount_statics: BTreeSet<Ident>,
         clock_names: BTreeSet<String>,
         muxes: BTreeSet<(Ident, Ident, Ident)>,
     }
@@ -397,7 +393,6 @@ fn main() {
         rcc_registers,
         chained_muxes: HashMap::new(),
 
-        refcount_statics: BTreeSet::new(),
         clock_names: BTreeSet::new(),
         muxes: BTreeSet::new(),
     };
@@ -516,80 +511,64 @@ fn main() {
         }
     }
 
+    let mut refcount_idxs = HashMap::new();
+
     for p in METADATA.peripherals {
         if !singletons.contains(&p.name.to_string()) {
             continue;
         }
 
         if let Some(rcc) = &p.rcc {
-            let en = rcc.enable.as_ref().unwrap();
-
-            let (start_rst, end_rst) = match &rcc.reset {
-                Some(rst) => {
-                    let rst_reg = format_ident!("{}", rst.register.to_ascii_lowercase());
-                    let set_rst_field = format_ident!("set_{}", rst.field.to_ascii_lowercase());
-                    (
-                        quote! {
-                            crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(true));
-                        },
-                        quote! {
-                            crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(false));
-                        },
-                    )
-                }
-                None => (TokenStream::new(), TokenStream::new()),
-            };
-
+            let rst_reg = rcc.reset.as_ref();
+            let en_reg = rcc.enable.as_ref().unwrap();
             let pname = format_ident!("{}", p.name);
-            let en_reg = format_ident!("{}", en.register.to_ascii_lowercase());
-            let set_en_field = format_ident!("set_{}", en.field.to_ascii_lowercase());
-            let en_reg_offs = rcc_block
-                .items
-                .iter()
-                .find(|i| i.name.eq_ignore_ascii_case(en.register))
-                .unwrap()
-                .byte_offset;
-            let en_reg_offs: u8 = (en_reg_offs / 4).try_into().unwrap();
 
-            let en_bit_offs = &rcc_registers
-                .ir
-                .fieldsets
-                .iter()
-                .find(|i| i.name.eq_ignore_ascii_case(en.register))
-                .unwrap()
-                .fields
-                .iter()
-                .find(|i| i.name.eq_ignore_ascii_case(en.field))
-                .unwrap()
-                .bit_offset;
-            let BitOffset::Regular(en_bit_offs) = en_bit_offs else {
-                panic!("cursed bit offset")
+            let get_offset_and_bit = |reg: &PeripheralRccRegister| -> TokenStream {
+                let reg_offset = rcc_block
+                    .items
+                    .iter()
+                    .find(|i| i.name.eq_ignore_ascii_case(reg.register))
+                    .unwrap()
+                    .byte_offset;
+                let reg_offset: u8 = (reg_offset / 4).try_into().unwrap();
+
+                let bit_offset = &rcc_registers
+                    .ir
+                    .fieldsets
+                    .iter()
+                    .find(|i| i.name.eq_ignore_ascii_case(reg.register))
+                    .unwrap()
+                    .fields
+                    .iter()
+                    .find(|i| i.name.eq_ignore_ascii_case(reg.field))
+                    .unwrap()
+                    .bit_offset;
+                let BitOffset::Regular(bit_offset) = bit_offset else {
+                    panic!("cursed bit offset")
+                };
+                let bit_offset: u8 = bit_offset.offset.try_into().unwrap();
+
+                quote! { (#reg_offset, #bit_offset) }
             };
-            let en_bit_offs: u8 = en_bit_offs.offset.try_into().unwrap();
 
-            let refcount = *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());
+            let reset_offset_and_bit = match rst_reg {
+                Some(rst_reg) => {
+                    let reset_offset_and_bit = get_offset_and_bit(rst_reg);
+                    quote! { Some(#reset_offset_and_bit) }
+                }
+                None => quote! { None },
+            };
+            let enable_offset_and_bit = get_offset_and_bit(en_reg);
 
-                clock_gen.refcount_statics.insert(refcount_static.clone());
-
-                (
-                    quote! {
-                        unsafe { refcount_statics::#refcount_static += 1 };
-                        if unsafe { refcount_statics::#refcount_static } > 1 {
-                            return;
-                        }
-                    },
-                    quote! {
-                        unsafe { refcount_statics::#refcount_static -= 1 };
-                        if unsafe { refcount_statics::#refcount_static } > 0  {
-                            return;
-                        }
-                    },
-                )
+            let needs_refcount = *rcc_field_count.get(&(en_reg.register, en_reg.field)).unwrap() > 1;
+            let refcount_idx = if needs_refcount {
+                let next_refcount_idx = refcount_idxs.len() as u8;
+                let refcount_idx = *refcount_idxs
+                    .entry((en_reg.register, en_reg.field))
+                    .or_insert(next_refcount_idx);
+                quote! { Some(#refcount_idx) }
             } else {
-                (TokenStream::new(), TokenStream::new())
+                quote! { None }
             };
 
             let clock_frequency = match &rcc.kernel_clock {
@@ -599,24 +578,10 @@ fn main() {
 
             // 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 }),
-                StopMode::Stop1 => Some(quote! { REFCOUNT_STOP1 }),
-            };
-
-            let (incr_stop_refcount, decr_stop_refcount) = match stop_refcount {
-                Some(stop_refcount) => (
-                    quote! {
-                        #[cfg(feature = "low-power")]
-                        unsafe { crate::rcc::#stop_refcount += 1 };
-                    },
-                    quote! {
-                        #[cfg(feature = "low-power")]
-                        unsafe { crate::rcc::#stop_refcount -= 1 };
-                    },
-                ),
-                None => (TokenStream::new(), TokenStream::new()),
+            let stop_mode = match rcc.stop_mode {
+                StopMode::Standby => quote! { crate::rcc::StopMode::Standby },
+                StopMode::Stop2 => quote! { crate::rcc::StopMode::Stop2 },
+                StopMode::Stop1 => quote! { crate::rcc::StopMode::Stop1 },
             };
 
             g.extend(quote! {
@@ -624,34 +589,16 @@ fn main() {
                     fn frequency() -> crate::time::Hertz {
                         #clock_frequency
                     }
-                    fn enable_and_reset_with_cs(_cs: critical_section::CriticalSection) {
-                        #before_enable
-                        #incr_stop_refcount
 
-                        #start_rst
-
-                        crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(true));
-
-                        // we must wait two peripheral clock cycles before the clock is active
-                        // this seems to work, but might be incorrect
-                        // see http://efton.sk/STM32/gotcha/g183.html
-
-                        // dummy read (like in the ST HALs)
-                        let _ = crate::pac::RCC.#en_reg().read();
-
-                        // DSB for good measure
-                        cortex_m::asm::dsb();
-
-                        #end_rst
-                    }
-                    fn disable_with_cs(_cs: critical_section::CriticalSection) {
-                        #before_disable
-                        crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(false));
-                        #decr_stop_refcount
-                    }
-
-                    const ENABLE_BIT: crate::rcc::ClockEnableBit =
-                        unsafe { crate::rcc::ClockEnableBit::new(#en_reg_offs, #en_bit_offs) };
+                    const RCC_INFO: crate::rcc::RccInfo = unsafe {
+                        crate::rcc::RccInfo::new(
+                            #reset_offset_and_bit,
+                            #enable_offset_and_bit,
+                            #refcount_idx,
+                            #[cfg(feature = "low-power")]
+                            #stop_mode,
+                        )
+                    };
                 }
 
                 impl crate::rcc::RccPeripheral for peripherals::#pname {}
@@ -659,6 +606,14 @@ fn main() {
         }
     }
 
+    g.extend({
+        let refcounts_len = refcount_idxs.len();
+        let refcount_zeros: TokenStream = refcount_idxs.iter().map(|_| quote! { 0u8, }).collect();
+        quote! {
+            pub(crate) static mut REFCOUNTS: [u8; #refcounts_len] = [#refcount_zeros];
+        }
+    });
+
     let struct_fields: Vec<_> = clock_gen
         .muxes
         .iter()
@@ -762,22 +717,6 @@ fn main() {
         }
     );
 
-    let refcount_mod: TokenStream = clock_gen
-        .refcount_statics
-        .iter()
-        .map(|refcount_static| {
-            quote! {
-                pub(crate) static mut #refcount_static: u8 = 0;
-            }
-        })
-        .collect();
-
-    g.extend(quote! {
-        mod refcount_statics {
-            #refcount_mod
-        }
-    });
-
     // ========
     // Generate fns to enable GPIO, DMA in RCC
 
diff --git a/embassy-stm32/src/adc/f1.rs b/embassy-stm32/src/adc/f1.rs
index 3822d5032..b37ec260f 100644
--- a/embassy-stm32/src/adc/f1.rs
+++ b/embassy-stm32/src/adc/f1.rs
@@ -7,7 +7,7 @@ use embassy_hal_internal::into_ref;
 use super::blocking_delay_us;
 use crate::adc::{Adc, AdcChannel, Instance, SampleTime};
 use crate::time::Hertz;
-use crate::{interrupt, Peripheral};
+use crate::{interrupt, rcc, Peripheral};
 
 pub const VDDA_CALIB_MV: u32 = 3300;
 pub const ADC_MAX: u32 = (1 << 12) - 1;
@@ -50,7 +50,7 @@ impl<T: Instance> super::SealedAdcChannel<T> for Temperature {
 impl<'d, T: Instance> Adc<'d, T> {
     pub fn new(adc: impl Peripheral<P = T> + 'd) -> Self {
         into_ref!(adc);
-        T::enable_and_reset();
+        rcc::enable_and_reset::<T>();
         T::regs().cr2().modify(|reg| reg.set_adon(true));
 
         // 11.4: Before starting a calibration, the ADC must have been in power-on state (ADON bit = ‘1’)
@@ -169,6 +169,6 @@ impl<'d, T: Instance> Drop for Adc<'d, T> {
     fn drop(&mut self) {
         T::regs().cr2().modify(|reg| reg.set_adon(false));
 
-        T::disable();
+        rcc::disable::<T>();
     }
 }
diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs
index 3f076d64b..ac88c9742 100644
--- a/embassy-stm32/src/adc/f3.rs
+++ b/embassy-stm32/src/adc/f3.rs
@@ -8,7 +8,7 @@ use super::blocking_delay_us;
 use crate::adc::{Adc, AdcChannel, Instance, SampleTime};
 use crate::interrupt::typelevel::Interrupt;
 use crate::time::Hertz;
-use crate::{interrupt, Peripheral};
+use crate::{interrupt, rcc, Peripheral};
 
 pub const VDDA_CALIB_MV: u32 = 3300;
 pub const ADC_MAX: u32 = (1 << 12) - 1;
@@ -63,7 +63,7 @@ impl<'d, T: Instance> Adc<'d, T> {
 
         into_ref!(adc);
 
-        T::enable_and_reset();
+        rcc::enable_and_reset::<T>();
 
         // Enable the adc regulator
         T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::INTERMEDIATE));
@@ -188,6 +188,6 @@ impl<'d, T: Instance> Drop for Adc<'d, T> {
         T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::INTERMEDIATE));
         T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::DISABLED));
 
-        T::disable();
+        rcc::disable::<T>();
     }
 }
diff --git a/embassy-stm32/src/adc/f3_v1_1.rs b/embassy-stm32/src/adc/f3_v1_1.rs
index 106956989..689c2871d 100644
--- a/embassy-stm32/src/adc/f3_v1_1.rs
+++ b/embassy-stm32/src/adc/f3_v1_1.rs
@@ -10,7 +10,7 @@ use super::Resolution;
 use crate::adc::{Adc, AdcChannel, Instance, SampleTime};
 use crate::interrupt::typelevel::Interrupt;
 use crate::time::Hertz;
-use crate::{interrupt, Peripheral};
+use crate::{interrupt, rcc, Peripheral};
 
 const ADC_FREQ: Hertz = crate::rcc::HSI_FREQ;
 
@@ -143,7 +143,7 @@ impl<'d, T: Instance> Adc<'d, T> {
     ) -> Self {
         into_ref!(adc);
 
-        T::enable_and_reset();
+        rcc::enable_and_reset::<T>();
 
         //let r = T::regs();
         //r.cr2().write(|w| w.set_align(true));
@@ -403,6 +403,6 @@ impl<'d, T: Instance> Drop for Adc<'d, T> {
 
         T::regs().cr2().modify(|w| w.set_adon(false));
 
-        T::disable();
+        rcc::disable::<T>();
     }
 }
diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs
index ce7f5db70..6569361fe 100644
--- a/embassy-stm32/src/adc/g4.rs
+++ b/embassy-stm32/src/adc/g4.rs
@@ -4,7 +4,7 @@ use pac::adccommon::vals::Presc;
 
 use super::{blocking_delay_us, Adc, AdcChannel, Instance, Resolution, SampleTime};
 use crate::time::Hertz;
-use crate::{pac, Peripheral};
+use crate::{pac, rcc, Peripheral};
 
 /// Default VREF voltage used for sample conversion to millivolts.
 pub const VREF_DEFAULT_MV: u32 = 3300;
@@ -130,7 +130,7 @@ impl<'d, T: Instance> Adc<'d, T> {
     /// Create a new ADC driver.
     pub fn new(adc: impl Peripheral<P = T> + 'd) -> Self {
         embassy_hal_internal::into_ref!(adc);
-        T::enable_and_reset();
+        rcc::enable_and_reset::<T>();
 
         let prescaler = Prescaler::from_ker_ck(T::frequency());
 
diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs
index 090790c39..9bec2e13b 100644
--- a/embassy-stm32/src/adc/v1.rs
+++ b/embassy-stm32/src/adc/v1.rs
@@ -10,7 +10,7 @@ use super::blocking_delay_us;
 use crate::adc::{Adc, AdcChannel, Instance, Resolution, SampleTime};
 use crate::interrupt::typelevel::Interrupt;
 use crate::peripherals::ADC1;
-use crate::{interrupt, Peripheral};
+use crate::{interrupt, rcc, Peripheral};
 
 pub const VDDA_CALIB_MV: u32 = 3300;
 pub const VREF_INT: u32 = 1230;
@@ -67,7 +67,7 @@ impl<'d, T: Instance> Adc<'d, T> {
         _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
     ) -> Self {
         into_ref!(adc);
-        T::enable_and_reset();
+        rcc::enable_and_reset::<T>();
 
         // Delay 1μs when using HSI14 as the ADC clock.
         //
@@ -199,6 +199,6 @@ impl<'d, T: Instance> Drop for Adc<'d, T> {
         T::regs().cr().modify(|reg| reg.set_addis(true));
         while T::regs().cr().read().aden() {}
 
-        T::disable();
+        rcc::disable::<T>();
     }
 }
diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs
index 033108195..77e8bb56f 100644
--- a/embassy-stm32/src/adc/v2.rs
+++ b/embassy-stm32/src/adc/v2.rs
@@ -4,7 +4,7 @@ use super::blocking_delay_us;
 use crate::adc::{Adc, AdcChannel, Instance, Resolution, SampleTime};
 use crate::peripherals::ADC1;
 use crate::time::Hertz;
-use crate::Peripheral;
+use crate::{rcc, Peripheral};
 
 /// Default VREF voltage used for sample conversion to millivolts.
 pub const VREF_DEFAULT_MV: u32 = 3300;
@@ -96,7 +96,7 @@ where
 {
     pub fn new(adc: impl Peripheral<P = T> + 'd) -> Self {
         into_ref!(adc);
-        T::enable_and_reset();
+        rcc::enable_and_reset::<T>();
 
         let presc = Prescaler::from_pclk2(T::frequency());
         T::common_regs().ccr().modify(|w| w.set_adcpre(presc.adcpre()));
@@ -206,6 +206,6 @@ impl<'d, T: Instance> Drop for Adc<'d, T> {
             reg.set_adon(false);
         });
 
-        T::disable();
+        rcc::disable::<T>();
     }
 }
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs
index be857f4dd..398c57a92 100644
--- a/embassy-stm32/src/adc/v3.rs
+++ b/embassy-stm32/src/adc/v3.rs
@@ -3,7 +3,7 @@ use embassy_hal_internal::into_ref;
 
 use super::blocking_delay_us;
 use crate::adc::{Adc, AdcChannel, Instance, Resolution, SampleTime};
-use crate::Peripheral;
+use crate::{rcc, Peripheral};
 
 /// Default VREF voltage used for sample conversion to millivolts.
 pub const VREF_DEFAULT_MV: u32 = 3300;
@@ -94,7 +94,7 @@ cfg_if! {
 impl<'d, T: Instance> Adc<'d, T> {
     pub fn new(adc: impl Peripheral<P = T> + 'd) -> Self {
         into_ref!(adc);
-        T::enable_and_reset();
+        rcc::enable_and_reset::<T>();
         T::regs().cr().modify(|reg| {
             #[cfg(not(any(adc_g0, adc_u0)))]
             reg.set_deeppwd(false);
diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs
index f564114c2..50db646fe 100644
--- a/embassy-stm32/src/adc/v4.rs
+++ b/embassy-stm32/src/adc/v4.rs
@@ -4,7 +4,7 @@ use pac::adccommon::vals::Presc;
 
 use super::{blocking_delay_us, Adc, AdcChannel, Instance, Resolution, SampleTime};
 use crate::time::Hertz;
-use crate::{pac, Peripheral};
+use crate::{pac, rcc, Peripheral};
 
 /// Default VREF voltage used for sample conversion to millivolts.
 pub const VREF_DEFAULT_MV: u32 = 3300;
@@ -130,7 +130,7 @@ impl<'d, T: Instance> Adc<'d, T> {
     /// Create a new ADC driver.
     pub fn new(adc: impl Peripheral<P = T> + 'd) -> Self {
         embassy_hal_internal::into_ref!(adc);
-        T::enable_and_reset();
+        rcc::enable_and_reset::<T>();
 
         let prescaler = Prescaler::from_ker_ck(T::frequency());
 
diff --git a/embassy-stm32/src/can/bxcan/mod.rs b/embassy-stm32/src/can/bxcan/mod.rs
index 0ac4cdab6..ac225d7d2 100644
--- a/embassy-stm32/src/can/bxcan/mod.rs
+++ b/embassy-stm32/src/can/bxcan/mod.rs
@@ -19,7 +19,7 @@ use super::util;
 use crate::can::enums::{BusError, TryReadError};
 use crate::gpio::AFType;
 use crate::interrupt::typelevel::Interrupt;
-use crate::rcc::RccPeripheral;
+use crate::rcc::{self, RccPeripheral};
 use crate::{interrupt, peripherals, Peripheral};
 
 /// Interrupt handler.
@@ -183,7 +183,7 @@ impl<'d, T: Instance> Can<'d, T> {
         rx.set_as_af(rx.af_num(), AFType::Input);
         tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
 
-        T::enable_and_reset();
+        rcc::enable_and_reset::<T>();
 
         {
             T::regs().ier().write(|w| {
@@ -759,7 +759,7 @@ impl<'d, T: Instance> Drop for Can<'d, T> {
         // Cannot call `free()` because it moves the instance.
         // Manually reset the peripheral.
         T::regs().mcr().write(|w| w.set_reset(true));
-        T::disable();
+        rcc::disable::<T>();
     }
 }
 
diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs
index d0c8db090..a838d0412 100644
--- a/embassy-stm32/src/can/fdcan.rs
+++ b/embassy-stm32/src/can/fdcan.rs
@@ -12,7 +12,7 @@ use embassy_sync::waitqueue::AtomicWaker;
 use crate::can::fd::peripheral::Registers;
 use crate::gpio::AFType;
 use crate::interrupt::typelevel::Interrupt;
-use crate::rcc::RccPeripheral;
+use crate::rcc::{self, RccPeripheral};
 use crate::{interrupt, peripherals, Peripheral};
 
 pub(crate) mod fd;
@@ -184,7 +184,7 @@ impl<'d, T: Instance> CanConfigurator<'d, T> {
         rx.set_as_af(rx.af_num(), AFType::Input);
         tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
 
-        T::enable_and_reset();
+        rcc::enable_and_reset::<T>();
 
         let mut config = crate::can::fd::config::FdCanConfig::default();
         config.timestamp_source = TimestampSource::Prescaler(TimestampPrescaler::_1);
diff --git a/embassy-stm32/src/cordic/mod.rs b/embassy-stm32/src/cordic/mod.rs
index 29b11735e..fb342d2e7 100644
--- a/embassy-stm32/src/cordic/mod.rs
+++ b/embassy-stm32/src/cordic/mod.rs
@@ -4,7 +4,7 @@ use embassy_hal_internal::drop::OnDrop;
 use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
 
 use crate::pac::cordic::vals;
-use crate::{dma, peripherals};
+use crate::{dma, peripherals, rcc};
 
 mod enums;
 pub use enums::*;
@@ -199,7 +199,7 @@ impl<'d, T: Instance> Cordic<'d, T> {
     /// If you need a peripheral -> CORDIC -> peripheral mode,  
     /// you may want to set Cordic into [Mode::ZeroOverhead] mode, and add extra arguments with [Self::extra_config]
     pub fn new(peri: impl Peripheral<P = T> + 'd, config: Config) -> Self {
-        T::enable_and_reset();
+        rcc::enable_and_reset::<T>();
 
         into_ref!(peri);
 
@@ -259,7 +259,7 @@ impl<'d, T: Instance> Cordic<'d, T> {
 
 impl<'d, T: Instance> Drop for Cordic<'d, T> {
     fn drop(&mut self) {
-        T::disable();
+        rcc::disable::<T>();
     }
 }
 
diff --git a/embassy-stm32/src/crc/v1.rs b/embassy-stm32/src/crc/v1.rs
index e8e0270af..f3d13de7c 100644
--- a/embassy-stm32/src/crc/v1.rs
+++ b/embassy-stm32/src/crc/v1.rs
@@ -2,8 +2,7 @@ use embassy_hal_internal::{into_ref, PeripheralRef};
 
 use crate::pac::CRC as PAC_CRC;
 use crate::peripherals::CRC;
-use crate::rcc::SealedRccPeripheral;
-use crate::Peripheral;
+use crate::{rcc, Peripheral};
 
 /// CRC driver.
 pub struct Crc<'d> {
@@ -17,7 +16,7 @@ impl<'d> Crc<'d> {
 
         // Note: enable and reset come from RccPeripheral.
         // enable CRC clock in RCC.
-        CRC::enable_and_reset();
+        rcc::enable_and_reset::<CRC>();
         // Peripheral the peripheral
         let mut instance = Self { _peri: peripheral };
         instance.reset();
diff --git a/embassy-stm32/src/crc/v2v3.rs b/embassy-stm32/src/crc/v2v3.rs
index ad7c79f12..09d956d7c 100644
--- a/embassy-stm32/src/crc/v2v3.rs
+++ b/embassy-stm32/src/crc/v2v3.rs
@@ -3,8 +3,7 @@ use embassy_hal_internal::{into_ref, PeripheralRef};
 use crate::pac::crc::vals;
 use crate::pac::CRC as PAC_CRC;
 use crate::peripherals::CRC;
-use crate::rcc::SealedRccPeripheral;
-use crate::Peripheral;
+use crate::{rcc, Peripheral};
 
 /// CRC driver.
 pub struct Crc<'d> {
@@ -84,7 +83,7 @@ impl<'d> Crc<'d> {
     pub fn new(peripheral: impl Peripheral<P = CRC> + 'd, config: Config) -> Self {
         // Note: enable and reset come from RccPeripheral.
         // reset to default values and enable CRC clock in RCC.
-        CRC::enable_and_reset();
+        rcc::enable_and_reset::<CRC>();
         into_ref!(peripheral);
         let mut instance = Self {
             _peripheral: peripheral,
diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs
index e7808b454..ad118ef6e 100644
--- a/embassy-stm32/src/cryp/mod.rs
+++ b/embassy-stm32/src/cryp/mod.rs
@@ -9,7 +9,7 @@ use embassy_sync::waitqueue::AtomicWaker;
 
 use crate::dma::{NoDma, Transfer, TransferOptions};
 use crate::interrupt::typelevel::Interrupt;
-use crate::{interrupt, pac, peripherals, Peripheral};
+use crate::{interrupt, pac, peripherals, rcc, Peripheral};
 
 const DES_BLOCK_SIZE: usize = 8; // 64 bits
 const AES_BLOCK_SIZE: usize = 16; // 128 bits
@@ -1021,7 +1021,7 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> {
         outdma: impl Peripheral<P = DmaOut> + 'd,
         _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
     ) -> Self {
-        T::enable_and_reset();
+        rcc::enable_and_reset::<T>();
         into_ref!(peri, indma, outdma);
         let instance = Self {
             _peripheral: peri,
diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs
index 489342a4a..8bba5ded0 100644
--- a/embassy-stm32/src/dac/mod.rs
+++ b/embassy-stm32/src/dac/mod.rs
@@ -8,7 +8,7 @@ use embassy_hal_internal::{into_ref, PeripheralRef};
 use crate::dma::NoDma;
 #[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))]
 use crate::pac::dac;
-use crate::rcc::RccPeripheral;
+use crate::rcc::{self, RccPeripheral};
 use crate::{peripherals, Peripheral};
 
 mod tsel;
@@ -131,7 +131,7 @@ impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> {
     ) -> Self {
         into_ref!(dma, pin);
         pin.set_as_analog();
-        T::enable_and_reset();
+        rcc::enable_and_reset::<T>();
         let mut dac = Self {
             phantom: PhantomData,
             dma,
@@ -157,7 +157,7 @@ impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> {
     #[cfg(all(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7), not(any(stm32h56x, stm32h57x))))]
     pub fn new_internal(_peri: impl Peripheral<P = T> + 'd, dma: impl Peripheral<P = DMA> + 'd) -> Self {
         into_ref!(dma);
-        T::enable_and_reset();
+        rcc::enable_and_reset::<T>();
         let mut dac = Self {
             phantom: PhantomData,
             dma,
@@ -356,7 +356,7 @@ impl_dma_methods!(2, DacDma2);
 
 impl<'d, T: Instance, const N: u8, DMA> Drop for DacChannel<'d, T, N, DMA> {
     fn drop(&mut self) {
-        T::disable();
+        rcc::disable::<T>();
     }
 }
 
@@ -400,8 +400,8 @@ impl<'d, T: Instance, DMACh1, DMACh2> Dac<'d, T, DMACh1, DMACh2> {
         pin_ch2.set_as_analog();
 
         // Enable twice to increment the DAC refcount for each channel.
-        T::enable_and_reset();
-        T::enable_and_reset();
+        rcc::enable_and_reset::<T>();
+        rcc::enable_and_reset::<T>();
 
         let mut ch1 = DacCh1 {
             phantom: PhantomData,
@@ -444,8 +444,8 @@ impl<'d, T: Instance, DMACh1, DMACh2> Dac<'d, T, DMACh1, DMACh2> {
     ) -> Self {
         into_ref!(dma_ch1, dma_ch2);
         // Enable twice to increment the DAC refcount for each channel.
-        T::enable_and_reset();
-        T::enable_and_reset();
+        rcc::enable_and_reset::<T>();
+        rcc::enable_and_reset::<T>();
 
         let mut ch1 = DacCh1 {
             phantom: PhantomData,
diff --git a/embassy-stm32/src/dcmi.rs b/embassy-stm32/src/dcmi.rs
index 646ee2ce2..858ae49ca 100644
--- a/embassy-stm32/src/dcmi.rs
+++ b/embassy-stm32/src/dcmi.rs
@@ -9,7 +9,7 @@ use embassy_sync::waitqueue::AtomicWaker;
 use crate::dma::Transfer;
 use crate::gpio::{AFType, Speed};
 use crate::interrupt::typelevel::Interrupt;
-use crate::{interrupt, Peripheral};
+use crate::{interrupt, rcc, Peripheral};
 
 /// Interrupt handler.
 pub struct InterruptHandler<T: Instance> {
@@ -350,7 +350,7 @@ where
         use_embedded_synchronization: bool,
         edm: u8,
     ) -> Self {
-        T::enable_and_reset();
+        rcc::enable_and_reset::<T>();
 
         peri.regs().cr().modify(|r| {
             r.set_cm(true); // disable continuous mode (snapshot mode)
diff --git a/embassy-stm32/src/dsihost.rs b/embassy-stm32/src/dsihost.rs
index 253939394..dc58bca92 100644
--- a/embassy-stm32/src/dsihost.rs
+++ b/embassy-stm32/src/dsihost.rs
@@ -6,7 +6,7 @@ use embassy_hal_internal::{into_ref, PeripheralRef};
 
 //use crate::gpio::{AnyPin, SealedPin};
 use crate::gpio::{AFType, AnyPin, Pull, Speed};
-use crate::rcc::RccPeripheral;
+use crate::rcc::{self, RccPeripheral};
 use crate::{peripherals, Peripheral};
 
 /// Performs a busy-wait delay for a specified number of microseconds.
@@ -77,7 +77,7 @@ impl<'d, T: Instance> DsiHost<'d, T> {
     pub fn new(_peri: impl Peripheral<P = T> + 'd, te: impl Peripheral<P = impl TePin<T>> + 'd) -> Self {
         into_ref!(te);
 
-        T::enable_and_reset();
+        rcc::enable_and_reset::<T>();
 
         // Set Tearing Enable pin according to CubeMx example
         te.set_as_af_pull(te.af_num(), AFType::OutputPushPull, Pull::None);
diff --git a/embassy-stm32/src/fmc.rs b/embassy-stm32/src/fmc.rs
index aced69878..0df64f711 100644
--- a/embassy-stm32/src/fmc.rs
+++ b/embassy-stm32/src/fmc.rs
@@ -4,7 +4,7 @@ use core::marker::PhantomData;
 use embassy_hal_internal::into_ref;
 
 use crate::gpio::{AFType, Pull, Speed};
-use crate::Peripheral;
+use crate::{rcc, Peripheral};
 
 /// FMC driver
 pub struct Fmc<'d, T: Instance> {
@@ -27,7 +27,7 @@ where
 
     /// Enable the FMC peripheral and reset it.
     pub fn enable(&mut self) {
-        T::enable_and_reset();
+        rcc::enable_and_reset::<T>();
     }
 
     /// Enable the memory controller on applicable chips.
@@ -54,7 +54,7 @@ where
     const REGISTERS: *const () = T::REGS.as_ptr() as *const _;
 
     fn enable(&mut self) {
-        T::enable_and_reset();
+        rcc::enable_and_reset::<T>();
     }
 
     fn memory_controller_enable(&mut self) {
@@ -200,7 +200,7 @@ impl<'d, T: Instance> Fmc<'d, T> {
     ));
 }
 
-trait SealedInstance: crate::rcc::SealedRccPeripheral {
+trait SealedInstance: crate::rcc::RccPeripheral {
     const REGS: crate::pac::fmc::Fmc;
 }
 
diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs
index d60a857ef..de08127cf 100644
--- a/embassy-stm32/src/gpio.rs
+++ b/embassy-stm32/src/gpio.rs
@@ -822,7 +822,7 @@ foreach_pin!(
 
 pub(crate) unsafe fn init(_cs: CriticalSection) {
     #[cfg(afio)]
-    <crate::peripherals::AFIO as crate::rcc::SealedRccPeripheral>::enable_and_reset_with_cs(_cs);
+    crate::rcc::enable_and_reset_with_cs::<crate::peripherals::AFIO>(_cs);
 
     crate::_generated::init_gpio();
 }
diff --git a/embassy-stm32/src/hash/mod.rs b/embassy-stm32/src/hash/mod.rs
index 787d5b1c9..4d4a8ec5b 100644
--- a/embassy-stm32/src/hash/mod.rs
+++ b/embassy-stm32/src/hash/mod.rs
@@ -17,8 +17,7 @@ use crate::dma::NoDma;
 use crate::dma::Transfer;
 use crate::interrupt::typelevel::Interrupt;
 use crate::peripherals::HASH;
-use crate::rcc::SealedRccPeripheral;
-use crate::{interrupt, pac, peripherals, Peripheral};
+use crate::{interrupt, pac, peripherals, rcc, Peripheral};
 
 #[cfg(hash_v1)]
 const NUM_CONTEXT_REGS: usize = 51;
@@ -130,7 +129,7 @@ impl<'d, T: Instance, D> Hash<'d, T, D> {
         dma: impl Peripheral<P = D> + 'd,
         _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
     ) -> Self {
-        HASH::enable_and_reset();
+        rcc::enable_and_reset::<HASH>();
         into_ref!(peripheral, dma);
         let instance = Self {
             _peripheral: peripheral,
diff --git a/embassy-stm32/src/hrtim/mod.rs b/embassy-stm32/src/hrtim/mod.rs
index 02e45819c..c9d5bff17 100644
--- a/embassy-stm32/src/hrtim/mod.rs
+++ b/embassy-stm32/src/hrtim/mod.rs
@@ -9,7 +9,7 @@ pub use traits::Instance;
 
 use crate::gpio::{AFType, AnyPin};
 use crate::time::Hertz;
-use crate::Peripheral;
+use crate::{rcc, Peripheral};
 
 /// HRTIM burst controller instance.
 pub struct BurstController<T: Instance> {
@@ -172,7 +172,7 @@ impl<'d, T: Instance> AdvancedPwm<'d, T> {
     fn new_inner(tim: impl Peripheral<P = T> + 'd) -> Self {
         into_ref!(tim);
 
-        T::enable_and_reset();
+        rcc::enable_and_reset::<T>();
 
         #[cfg(stm32f334)]
         if crate::pac::RCC.cfgr3().read().hrtim1sw() == crate::pac::rcc::vals::Timsw::PLL1_P {
diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs
index ef5fd0972..0bf57ef8a 100644
--- a/embassy-stm32/src/i2c/mod.rs
+++ b/embassy-stm32/src/i2c/mod.rs
@@ -18,7 +18,7 @@ use crate::dma::ChannelAndRequest;
 use crate::gpio::{AFType, Pull};
 use crate::interrupt::typelevel::Interrupt;
 use crate::mode::{Async, Blocking, Mode};
-use crate::rcc::{ClockEnableBit, SealedRccPeripheral};
+use crate::rcc::{self, RccInfo, SealedRccPeripheral};
 use crate::time::Hertz;
 use crate::{interrupt, peripherals};
 
@@ -128,7 +128,7 @@ impl<'d, M: Mode> I2c<'d, M> {
     ) -> Self {
         into_ref!(scl, sda);
 
-        T::enable_and_reset();
+        rcc::enable_and_reset::<T>();
 
         scl.set_as_af_pull(
             scl.af_num(),
@@ -224,7 +224,7 @@ impl State {
 
 struct Info {
     regs: crate::pac::i2c::I2c,
-    pub(crate) enable_bit: ClockEnableBit,
+    rcc: RccInfo,
 }
 
 peri_trait!(
@@ -265,7 +265,7 @@ foreach_peripheral!(
             fn info() -> &'static Info {
                 static INFO: Info = Info{
                     regs: crate::pac::$inst,
-                    enable_bit: crate::peripherals::$inst::ENABLE_BIT,
+                    rcc: crate::peripherals::$inst::RCC_INFO,
                 };
                 &INFO
             }
diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs
index 0269e53aa..0e2bd2e40 100644
--- a/embassy-stm32/src/i2c/v1.rs
+++ b/embassy-stm32/src/i2c/v1.rs
@@ -702,7 +702,7 @@ impl<'d> I2c<'d, Async> {
 
 impl<'d, M: PeriMode> Drop for I2c<'d, M> {
     fn drop(&mut self) {
-        self.info.enable_bit.disable()
+        self.info.rcc.disable()
     }
 }
 
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs
index aa6daf786..193f29733 100644
--- a/embassy-stm32/src/i2c/v2.rs
+++ b/embassy-stm32/src/i2c/v2.rs
@@ -673,7 +673,7 @@ impl<'d> I2c<'d, Async> {
 
 impl<'d, M: Mode> Drop for I2c<'d, M> {
     fn drop(&mut self) {
-        self.info.enable_bit.disable();
+        self.info.rcc.disable();
     }
 }
 
diff --git a/embassy-stm32/src/ipcc.rs b/embassy-stm32/src/ipcc.rs
index 4d535cce2..6c8347311 100644
--- a/embassy-stm32/src/ipcc.rs
+++ b/embassy-stm32/src/ipcc.rs
@@ -6,10 +6,9 @@ use core::task::Poll;
 
 use embassy_sync::waitqueue::AtomicWaker;
 
-use crate::interrupt;
 use crate::interrupt::typelevel::Interrupt;
 use crate::peripherals::IPCC;
-use crate::rcc::SealedRccPeripheral;
+use crate::{interrupt, rcc};
 
 /// Interrupt handler.
 pub struct ReceiveInterruptHandler {}
@@ -102,7 +101,7 @@ pub struct Ipcc;
 impl Ipcc {
     /// Enable IPCC.
     pub fn enable(_config: Config) {
-        IPCC::enable_and_reset();
+        rcc::enable_and_reset::<IPCC>();
         IPCC::set_cpu2(true);
 
         // set RF wake-up clock = LSE
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index 81ee60c1c..fe9c0dcb5 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -194,7 +194,6 @@ pub(crate) use stm32_metapac as pac;
 use crate::interrupt::Priority;
 #[cfg(feature = "rt")]
 pub use crate::pac::NVIC_PRIO_BITS;
-use crate::rcc::SealedRccPeripheral;
 
 /// `embassy-stm32` global configuration.
 #[non_exhaustive]
@@ -310,11 +309,11 @@ pub fn init(config: Config) -> Peripherals {
         });
 
         #[cfg(not(any(stm32f1, stm32wb, stm32wl)))]
-        peripherals::SYSCFG::enable_and_reset_with_cs(cs);
+        rcc::enable_and_reset_with_cs::<peripherals::SYSCFG>(cs);
         #[cfg(not(any(stm32h5, stm32h7, stm32h7rs, stm32wb, stm32wl)))]
-        peripherals::PWR::enable_and_reset_with_cs(cs);
+        rcc::enable_and_reset_with_cs::<peripherals::PWR>(cs);
         #[cfg(not(any(stm32f2, stm32f4, stm32f7, stm32l0, stm32h5, stm32h7, stm32h7rs)))]
-        peripherals::FLASH::enable_and_reset_with_cs(cs);
+        rcc::enable_and_reset_with_cs::<peripherals::FLASH>(cs);
 
         // Enable the VDDIO2 power supply on chips that have it.
         // Note that this requires the PWR peripheral to be enabled first.
diff --git a/embassy-stm32/src/ltdc.rs b/embassy-stm32/src/ltdc.rs
index a2d6a3cee..c262e7a0c 100644
--- a/embassy-stm32/src/ltdc.rs
+++ b/embassy-stm32/src/ltdc.rs
@@ -1,7 +1,7 @@
 //! LTDC
 use core::marker::PhantomData;
 
-use crate::rcc::RccPeripheral;
+use crate::rcc::{self, RccPeripheral};
 use crate::{peripherals, Peripheral};
 
 /// LTDC driver.
@@ -60,7 +60,7 @@ impl<'d, T: Instance> Ltdc<'d, T> {
                 .modify(|w| w.set_pllsaidivr(stm32_metapac::rcc::vals::Pllsaidivr::DIV2));
         });
 
-        T::enable_and_reset();
+        rcc::enable_and_reset::<T>();
 
         //new_pin!(clk, AFType::OutputPushPull, Speed::VeryHigh,  Pull::None);
 
diff --git a/embassy-stm32/src/ospi/mod.rs b/embassy-stm32/src/ospi/mod.rs
index 536da4ca0..882781cce 100644
--- a/embassy-stm32/src/ospi/mod.rs
+++ b/embassy-stm32/src/ospi/mod.rs
@@ -16,7 +16,7 @@ use crate::dma::{word, ChannelAndRequest};
 use crate::gpio::{AFType, AnyPin, Pull, SealedPin as _, Speed};
 use crate::mode::{Async, Blocking, Mode as PeriMode};
 use crate::pac::octospi::{vals, Octospi as Regs};
-use crate::rcc::RccPeripheral;
+use crate::rcc::{self, RccPeripheral};
 use crate::{peripherals, Peripheral};
 
 /// OPSI driver config.
@@ -198,7 +198,7 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> {
         into_ref!(peri);
 
         // System configuration
-        T::enable_and_reset();
+        rcc::enable_and_reset::<T>();
         while T::REGS.sr().read().busy() {}
 
         // Device configuration
@@ -1013,7 +1013,7 @@ impl<'d, T: Instance, M: PeriMode> Drop for Ospi<'d, T, M> {
         self.nss.as_ref().map(|x| x.set_as_disconnected());
         self.dqs.as_ref().map(|x| x.set_as_disconnected());
 
-        T::disable();
+        rcc::disable::<T>();
     }
 }
 
diff --git a/embassy-stm32/src/qspi/mod.rs b/embassy-stm32/src/qspi/mod.rs
index a82e93b5b..06c8f4812 100644
--- a/embassy-stm32/src/qspi/mod.rs
+++ b/embassy-stm32/src/qspi/mod.rs
@@ -13,7 +13,7 @@ use crate::dma::ChannelAndRequest;
 use crate::gpio::{AFType, AnyPin, Pull, Speed};
 use crate::mode::{Async, Blocking, Mode as PeriMode};
 use crate::pac::quadspi::Quadspi as Regs;
-use crate::rcc::RccPeripheral;
+use crate::rcc::{self, RccPeripheral};
 use crate::{peripherals, Peripheral};
 
 /// QSPI transfer configuration.
@@ -102,7 +102,7 @@ impl<'d, T: Instance, M: PeriMode> Qspi<'d, T, M> {
     ) -> Self {
         into_ref!(peri);
 
-        T::enable_and_reset();
+        rcc::enable_and_reset::<T>();
 
         while T::REGS.sr().read().busy() {}
 
diff --git a/embassy-stm32/src/rcc/hsi48.rs b/embassy-stm32/src/rcc/hsi48.rs
index da81abc34..efabd059f 100644
--- a/embassy-stm32/src/rcc/hsi48.rs
+++ b/embassy-stm32/src/rcc/hsi48.rs
@@ -2,7 +2,7 @@
 
 use crate::pac::crs::vals::Syncsrc;
 use crate::pac::{CRS, RCC};
-use crate::rcc::SealedRccPeripheral;
+use crate::rcc::{self, SealedRccPeripheral};
 use crate::time::Hertz;
 
 /// HSI48 speed
@@ -44,7 +44,7 @@ pub(crate) fn init_hsi48(config: Hsi48Config) -> Hertz {
     while r.read().hsi48rdy() == false {}
 
     if config.sync_from_usb {
-        crate::peripherals::CRS::enable_and_reset();
+        rcc::enable_and_reset::<crate::peripherals::CRS>();
 
         CRS.cfgr().modify(|w| {
             w.set_syncsrc(Syncsrc::USB);
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs
index 28816256c..0bf344c40 100644
--- a/embassy-stm32/src/rcc/mod.rs
+++ b/embassy-stm32/src/rcc/mod.rs
@@ -67,23 +67,185 @@ pub(crate) unsafe fn get_freqs() -> &'static Clocks {
 }
 
 pub(crate) trait SealedRccPeripheral {
-    const ENABLE_BIT: ClockEnableBit;
-
     fn frequency() -> Hertz;
-    fn enable_and_reset_with_cs(cs: CriticalSection);
-    fn disable_with_cs(cs: CriticalSection);
-
-    fn enable_and_reset() {
-        critical_section::with(|cs| Self::enable_and_reset_with_cs(cs))
-    }
-    fn disable() {
-        critical_section::with(|cs| Self::disable_with_cs(cs))
-    }
+    const RCC_INFO: RccInfo;
 }
 
 #[allow(private_bounds)]
 pub trait RccPeripheral: SealedRccPeripheral + 'static {}
 
+/// Runtime information necessary to reset, enable and disable a peripheral.
+pub(crate) struct RccInfo {
+    /// Offset in 32-bit words of the xxxRSTR register into the RCC register block, or 0xff if the
+    /// peripheral has no reset bit (we don't use an `Option` to save one byte of storage).
+    reset_offset_or_0xff: u8,
+    /// Position of the xxxRST bit within the xxxRSTR register (0..=31).
+    reset_bit: u8,
+    /// Offset in 32-bit words of the xxxENR register into the RCC register block.
+    enable_offset: u8,
+    /// Position of the xxxEN bit within the xxxENR register (0..=31).
+    enable_bit: u8,
+    /// If this peripheral shares the same xxxRSTR bit and xxxEN bit with other peripherals, we
+    /// maintain a refcount in `crate::_generated::REFCOUNTS` at this index. If the bit is not
+    /// shared, this is 0xff (we don't use an `Option` to save one byte of storage).
+    refcount_idx_or_0xff: u8,
+    /// Stop mode of the peripheral, used to maintain `REFCOUNT_STOP1` and `REFCOUNT_STOP2`.
+    #[cfg(feature = "low-power")]
+    stop_mode: StopMode,
+}
+
+#[cfg(feature = "low-power")]
+#[allow(dead_code)]
+pub(crate) enum StopMode {
+    Standby,
+    Stop2,
+    Stop1,
+}
+
+impl RccInfo {
+    /// Safety:
+    /// - `reset_offset_and_bit`, if set, must correspond to valid xxxRST bit
+    /// - `enable_offset_and_bit` must correspond to valid xxxEN bit
+    /// - `refcount_idx`, if set, must correspond to valid refcount in `_generated::REFCOUNTS`
+    /// - `stop_mode` must be valid
+    pub(crate) const unsafe fn new(
+        reset_offset_and_bit: Option<(u8, u8)>,
+        enable_offset_and_bit: (u8, u8),
+        refcount_idx: Option<u8>,
+        #[cfg(feature = "low-power")] stop_mode: StopMode,
+    ) -> Self {
+        let (reset_offset_or_0xff, reset_bit) = match reset_offset_and_bit {
+            Some((offset, bit)) => (offset, bit),
+            None => (0xff, 0xff),
+        };
+        let (enable_offset, enable_bit) = enable_offset_and_bit;
+        let refcount_idx_or_0xff = match refcount_idx {
+            Some(idx) => idx,
+            None => 0xff,
+        };
+        Self {
+            reset_offset_or_0xff,
+            reset_bit,
+            enable_offset,
+            enable_bit,
+            refcount_idx_or_0xff,
+            #[cfg(feature = "low-power")]
+            stop_mode,
+        }
+    }
+
+    // TODO: should this be `unsafe`?
+    pub(crate) fn enable_and_reset_with_cs(&self, _cs: CriticalSection) {
+        if self.refcount_idx_or_0xff != 0xff {
+            let refcount_idx = self.refcount_idx_or_0xff as usize;
+            unsafe {
+                crate::_generated::REFCOUNTS[refcount_idx] += 1;
+            }
+            if unsafe { crate::_generated::REFCOUNTS[refcount_idx] } > 1 {
+                return;
+            }
+        }
+
+        #[cfg(feature = "low-power")]
+        match self.stop_mode {
+            StopMode::Standby => {}
+            StopMode::Stop2 => unsafe {
+                REFCOUNT_STOP2 += 1;
+            },
+            StopMode::Stop1 => unsafe {
+                REFCOUNT_STOP1 += 1;
+            },
+        }
+
+        // set the xxxRST bit
+        let reset_ptr = self.reset_ptr();
+        if let Some(reset_ptr) = reset_ptr {
+            unsafe {
+                let val = reset_ptr.read_volatile();
+                reset_ptr.write_volatile(val | 1u32 << self.reset_bit);
+            }
+        }
+
+        // set the xxxEN bit
+        let enable_ptr = self.enable_ptr();
+        unsafe {
+            let val = enable_ptr.read_volatile();
+            enable_ptr.write_volatile(val | 1u32 << self.enable_bit);
+        }
+
+        // we must wait two peripheral clock cycles before the clock is active
+        // this seems to work, but might be incorrect
+        // see http://efton.sk/STM32/gotcha/g183.html
+
+        // dummy read (like in the ST HALs)
+        let _ = unsafe { enable_ptr.read_volatile() };
+
+        // DSB for good measure
+        cortex_m::asm::dsb();
+
+        // clear the xxxRST bit
+        if let Some(reset_ptr) = reset_ptr {
+            unsafe {
+                let val = reset_ptr.read_volatile();
+                reset_ptr.write_volatile(val & !(1u32 << self.reset_bit));
+            }
+        }
+    }
+
+    // TODO: should this be `unsafe`?
+    pub(crate) fn disable_with_cs(&self, _cs: CriticalSection) {
+        if self.refcount_idx_or_0xff != 0xff {
+            let refcount_idx = self.refcount_idx_or_0xff as usize;
+            unsafe {
+                crate::_generated::REFCOUNTS[refcount_idx] -= 1;
+            }
+            if unsafe { crate::_generated::REFCOUNTS[refcount_idx] } > 0 {
+                return;
+            }
+        }
+
+        #[cfg(feature = "low-power")]
+        match self.stop_mode {
+            StopMode::Standby => {}
+            StopMode::Stop2 => unsafe {
+                REFCOUNT_STOP2 -= 1;
+            },
+            StopMode::Stop1 => unsafe {
+                REFCOUNT_STOP1 -= 1;
+            },
+        }
+
+        // clear the xxxEN bit
+        let enable_ptr = self.enable_ptr();
+        unsafe {
+            let val = enable_ptr.read_volatile();
+            enable_ptr.write_volatile(val & !(1u32 << self.enable_bit));
+        }
+    }
+
+    // TODO: should this be `unsafe`?
+    pub(crate) fn enable_and_reset(&self) {
+        critical_section::with(|cs| self.enable_and_reset_with_cs(cs))
+    }
+
+    // TODO: should this be `unsafe`?
+    pub(crate) fn disable(&self) {
+        critical_section::with(|cs| self.disable_with_cs(cs))
+    }
+
+    fn reset_ptr(&self) -> Option<*mut u32> {
+        if self.reset_offset_or_0xff != 0xff {
+            Some(unsafe { (RCC.as_ptr() as *mut u32).add(self.reset_offset_or_0xff as _) })
+        } else {
+            None
+        }
+    }
+
+    fn enable_ptr(&self) -> *mut u32 {
+        unsafe { (RCC.as_ptr() as *mut u32).add(self.enable_offset as _) }
+    }
+}
+
 #[allow(unused)]
 mod util {
     use crate::time::Hertz;
@@ -128,8 +290,9 @@ pub fn frequency<T: RccPeripheral>() -> Hertz {
 /// # Safety
 ///
 /// Peripheral must not be in use.
-pub unsafe fn enable_and_reset<T: RccPeripheral>() {
-    T::enable_and_reset();
+// TODO: should this be `unsafe`?
+pub fn enable_and_reset_with_cs<T: RccPeripheral>(cs: CriticalSection) {
+    T::RCC_INFO.enable_and_reset_with_cs(cs);
 }
 
 /// Disables peripheral `T`.
@@ -137,52 +300,27 @@ pub unsafe fn enable_and_reset<T: RccPeripheral>() {
 /// # Safety
 ///
 /// Peripheral must not be in use.
-pub unsafe fn disable<T: RccPeripheral>() {
-    T::disable();
+// TODO: should this be `unsafe`?
+pub fn disable_with_cs<T: RccPeripheral>(cs: CriticalSection) {
+    T::RCC_INFO.disable_with_cs(cs);
 }
 
-/// Struct representing some clock enable bit (xxxENR.xxEN), only known at runtime.
-#[derive(Clone, Copy)]
-pub(crate) struct ClockEnableBit {
-    /// offset in 32bit words of the xxxENR register into the RCC register block.
-    offset: u8,
-    /// bit within the register (0..=31)
-    bit: u8,
+/// Enables and resets peripheral `T`.
+///
+/// # Safety
+///
+/// Peripheral must not be in use.
+// TODO: should this be `unsafe`?
+pub fn enable_and_reset<T: RccPeripheral>() {
+    T::RCC_INFO.enable_and_reset();
 }
 
-impl ClockEnableBit {
-    /// Safety: offset+bit must correspond to a valid xxxEN bit.
-    pub(crate) const unsafe fn new(offset: u8, bit: u8) -> Self {
-        Self { offset, bit }
-    }
-
-    fn ptr(self) -> *mut u32 {
-        unsafe { (RCC.as_ptr() as *mut u32).add(self.offset as _) }
-    }
-
-    #[allow(unused)]
-    pub(crate) fn enable_with_cs(self, _cs: CriticalSection) {
-        let p = self.ptr();
-        unsafe {
-            let val = p.read_volatile();
-            p.write_volatile(val | 1u32 << self.bit);
-        }
-    }
-
-    pub(crate) fn disable_with_cs(self, _cs: CriticalSection) {
-        let p = self.ptr();
-        unsafe {
-            let val = p.read_volatile();
-            p.write_volatile(val & !(1u32 << self.bit));
-        }
-    }
-
-    #[allow(unused)]
-    pub(crate) fn enable(self) {
-        critical_section::with(|cs| self.enable_with_cs(cs))
-    }
-
-    pub(crate) fn disable(self) {
-        critical_section::with(|cs| self.disable_with_cs(cs))
-    }
+/// Disables peripheral `T`.
+///
+/// # Safety
+///
+/// Peripheral must not be in use.
+// TODO: should this be `unsafe`?
+pub fn disable<T: RccPeripheral>() {
+    T::RCC_INFO.disable();
 }
diff --git a/embassy-stm32/src/rng.rs b/embassy-stm32/src/rng.rs
index 7a228e4a4..94491c32f 100644
--- a/embassy-stm32/src/rng.rs
+++ b/embassy-stm32/src/rng.rs
@@ -10,7 +10,7 @@ use embassy_sync::waitqueue::AtomicWaker;
 use rand_core::{CryptoRng, RngCore};
 
 use crate::interrupt::typelevel::Interrupt;
-use crate::{interrupt, pac, peripherals, Peripheral};
+use crate::{interrupt, pac, peripherals, rcc, Peripheral};
 
 static RNG_WAKER: AtomicWaker = AtomicWaker::new();
 
@@ -52,7 +52,7 @@ impl<'d, T: Instance> Rng<'d, T> {
         inner: impl Peripheral<P = T> + 'd,
         _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
     ) -> Self {
-        T::enable_and_reset();
+        rcc::enable_and_reset::<T>();
         into_ref!(inner);
         let mut random = Self { _inner: inner };
         random.reset();
diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs
index cb9c10676..a7f70b153 100644
--- a/embassy-stm32/src/rtc/mod.rs
+++ b/embassy-stm32/src/rtc/mod.rs
@@ -142,7 +142,7 @@ impl Rtc {
     /// Create a new RTC instance.
     pub fn new(_rtc: impl Peripheral<P = RTC>, rtc_config: RtcConfig) -> Self {
         #[cfg(not(any(stm32l0, stm32f3, stm32l1, stm32f0, stm32f2)))]
-        <RTC as crate::rcc::SealedRccPeripheral>::enable_and_reset();
+        crate::rcc::enable_and_reset::<RTC>();
 
         let mut this = Self {
             #[cfg(feature = "low-power")]
diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs
index 54dd81524..3faecdc33 100644
--- a/embassy-stm32/src/sai/mod.rs
+++ b/embassy-stm32/src/sai/mod.rs
@@ -11,7 +11,7 @@ pub use crate::dma::word;
 use crate::dma::{ringbuffer, Channel, ReadableRingBuffer, Request, TransferOptions, WritableRingBuffer};
 use crate::gpio::{AFType, AnyPin, SealedPin as _};
 use crate::pac::sai::{vals, Sai as Regs};
-use crate::rcc::RccPeripheral;
+use crate::rcc::{self, RccPeripheral};
 use crate::{peripherals, Peripheral};
 
 /// SAI error
@@ -722,7 +722,7 @@ pub struct SubBlock<'d, T, S: SubBlockInstance> {
 /// You can then create a [`Sai`] driver for each each half.
 pub fn split_subblocks<'d, T: Instance>(peri: impl Peripheral<P = T> + 'd) -> (SubBlock<'d, T, A>, SubBlock<'d, T, B>) {
     into_ref!(peri);
-    T::enable_and_reset();
+    rcc::enable_and_reset::<T>();
 
     (
         SubBlock {
@@ -978,7 +978,7 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> {
 
     /// Reset SAI operation.
     pub fn reset() {
-        T::enable_and_reset();
+        rcc::enable_and_reset::<T>();
     }
 
     /// Flush.
diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs
index f79a11606..9c14837e1 100644
--- a/embassy-stm32/src/sdmmc/mod.rs
+++ b/embassy-stm32/src/sdmmc/mod.rs
@@ -16,7 +16,7 @@ use crate::dma::NoDma;
 use crate::gpio::{AFType, AnyPin, Pull, SealedPin, Speed};
 use crate::interrupt::typelevel::Interrupt;
 use crate::pac::sdmmc::Sdmmc as RegBlock;
-use crate::rcc::RccPeripheral;
+use crate::rcc::{self, RccPeripheral};
 use crate::time::Hertz;
 use crate::{interrupt, peripherals, Peripheral};
 
@@ -468,7 +468,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
     ) -> Self {
         into_ref!(sdmmc, dma);
 
-        T::enable_and_reset();
+        rcc::enable_and_reset::<T>();
 
         T::Interrupt::unpend();
         unsafe { T::Interrupt::enable() };
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs
index 7fb8da5ac..af8e3fc30 100644
--- a/embassy-stm32/src/spi/mod.rs
+++ b/embassy-stm32/src/spi/mod.rs
@@ -13,7 +13,7 @@ use crate::dma::{slice_ptr_parts, word, ChannelAndRequest};
 use crate::gpio::{AFType, AnyPin, Pull, SealedPin as _, Speed};
 use crate::mode::{Async, Blocking, Mode as PeriMode};
 use crate::pac::spi::{regs, vals, Spi as Regs};
-use crate::rcc::{ClockEnableBit, SealedRccPeripheral};
+use crate::rcc::{self, RccInfo, SealedRccPeripheral};
 use crate::time::Hertz;
 use crate::Peripheral;
 
@@ -129,7 +129,7 @@ impl<'d, M: PeriMode> Spi<'d, M> {
 
         let lsbfirst = config.raw_byte_order();
 
-        T::enable_and_reset();
+        rcc::enable_and_reset::<T>();
 
         #[cfg(any(spi_v1, spi_f1))]
         {
@@ -830,7 +830,7 @@ impl<'d, M: PeriMode> Drop for Spi<'d, M> {
         self.mosi.as_ref().map(|x| x.set_as_disconnected());
         self.miso.as_ref().map(|x| x.set_as_disconnected());
 
-        self.info.enable_bit.disable();
+        self.info.rcc.disable();
     }
 }
 
@@ -1216,7 +1216,7 @@ mod word_impl {
 
 pub(crate) struct Info {
     pub(crate) regs: Regs,
-    pub(crate) enable_bit: ClockEnableBit,
+    pub(crate) rcc: RccInfo,
 }
 
 struct State {}
@@ -1243,7 +1243,7 @@ foreach_peripheral!(
     (spi, $inst:ident) => {
         peri_trait_impl!($inst, Info {
             regs: crate::pac::$inst,
-            enable_bit: crate::peripherals::$inst::ENABLE_BIT,
+            rcc: crate::peripherals::$inst::RCC_INFO,
         });
     };
 );
diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs
index e592fbf7d..f8041bf1e 100644
--- a/embassy-stm32/src/time_driver.rs
+++ b/embassy-stm32/src/time_driver.rs
@@ -12,7 +12,7 @@ use stm32_metapac::timer::{regs, TimGp16};
 
 use crate::interrupt::typelevel::Interrupt;
 use crate::pac::timer::vals;
-use crate::rcc::SealedRccPeripheral;
+use crate::rcc::{self, SealedRccPeripheral};
 #[cfg(feature = "low-power")]
 use crate::rtc::Rtc;
 use crate::timer::{CoreInstance, GeneralInstance1Channel};
@@ -276,7 +276,7 @@ impl RtcDriver {
     fn init(&'static self, cs: critical_section::CriticalSection) {
         let r = regs_gp16();
 
-        <T as SealedRccPeripheral>::enable_and_reset_with_cs(cs);
+        rcc::enable_and_reset_with_cs::<T>(cs);
 
         let timer_freq = T::frequency();
 
diff --git a/embassy-stm32/src/timer/low_level.rs b/embassy-stm32/src/timer/low_level.rs
index 7f533b75c..9932c04cd 100644
--- a/embassy-stm32/src/timer/low_level.rs
+++ b/embassy-stm32/src/timer/low_level.rs
@@ -10,6 +10,7 @@ use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
 
 use super::*;
 use crate::pac::timer::vals;
+use crate::rcc;
 use crate::time::Hertz;
 
 /// Input capture mode.
@@ -181,7 +182,7 @@ pub struct Timer<'d, T: CoreInstance> {
 
 impl<'d, T: CoreInstance> Drop for Timer<'d, T> {
     fn drop(&mut self) {
-        T::disable()
+        rcc::disable::<T>();
     }
 }
 
@@ -190,7 +191,7 @@ impl<'d, T: CoreInstance> Timer<'d, T> {
     pub fn new(tim: impl Peripheral<P = T> + 'd) -> Self {
         into_ref!(tim);
 
-        T::enable_and_reset();
+        rcc::enable_and_reset::<T>();
 
         Self { tim }
     }
diff --git a/embassy-stm32/src/tsc/mod.rs b/embassy-stm32/src/tsc/mod.rs
index bf583f04c..045d6317c 100644
--- a/embassy-stm32/src/tsc/mod.rs
+++ b/embassy-stm32/src/tsc/mod.rs
@@ -72,7 +72,7 @@ pub use enums::*;
 
 use crate::gpio::{AFType, AnyPin};
 use crate::pac::tsc::Tsc as Regs;
-use crate::rcc::RccPeripheral;
+use crate::rcc::{self, RccPeripheral};
 use crate::{peripherals, Peripheral};
 
 #[cfg(tsc_v1)]
@@ -649,7 +649,7 @@ impl<'d, T: Instance> Tsc<'d, T> {
     ) -> Self {
         into_ref!(peri);
 
-        T::enable_and_reset();
+        rcc::enable_and_reset::<T>();
 
         T::REGS.cr().modify(|w| {
             w.set_tsce(true);
@@ -880,7 +880,7 @@ impl<'d, T: Instance> Tsc<'d, T> {
 
 impl<'d, T: Instance> Drop for Tsc<'d, T> {
     fn drop(&mut self) {
-        T::disable();
+        rcc::disable::<T>();
     }
 }
 
diff --git a/embassy-stm32/src/ucpd.rs b/embassy-stm32/src/ucpd.rs
index d6d0682b9..89e2f5d49 100644
--- a/embassy-stm32/src/ucpd.rs
+++ b/embassy-stm32/src/ucpd.rs
@@ -28,7 +28,7 @@ use crate::interrupt;
 use crate::interrupt::typelevel::Interrupt;
 use crate::pac::ucpd::vals::{Anamode, Ccenable, PscUsbpdclk, Txmode};
 pub use crate::pac::ucpd::vals::{Phyccsel as CcSel, TypecVstateCc as CcVState};
-use crate::rcc::RccPeripheral;
+use crate::rcc::{self, RccPeripheral};
 
 pub(crate) fn init(
     _cs: critical_section::CriticalSection,
@@ -103,7 +103,7 @@ impl<'d, T: Instance> Ucpd<'d, T> {
         cc1.set_as_analog();
         cc2.set_as_analog();
 
-        T::enable_and_reset();
+        rcc::enable_and_reset::<T>();
         T::Interrupt::unpend();
         unsafe { T::Interrupt::enable() };
 
@@ -212,7 +212,7 @@ impl<'d, T: Instance> Drop for CcPhy<'d, T> {
             drop_not_ready.store(true, Ordering::Relaxed);
         } else {
             r.cfgr1().write(|w| w.set_ucpden(false));
-            T::disable();
+            rcc::disable::<T>();
             T::Interrupt::disable();
         }
     }
@@ -325,7 +325,7 @@ impl<'d, T: Instance> Drop for PdPhy<'d, T> {
             drop_not_ready.store(true, Ordering::Relaxed);
         } else {
             T::REGS.cfgr1().write(|w| w.set_ucpden(false));
-            T::disable();
+            rcc::disable::<T>();
             T::Interrupt::disable();
         }
     }
diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs
index 492ad334b..eacf95002 100644
--- a/embassy-stm32/src/usart/buffered.rs
+++ b/embassy-stm32/src/usart/buffered.rs
@@ -18,6 +18,7 @@ use super::{
 use crate::gpio::AFType;
 use crate::interrupt::typelevel::Interrupt as _;
 use crate::interrupt::{self, InterruptExt};
+use crate::rcc;
 use crate::time::Hertz;
 
 /// Interrupt handler.
@@ -206,7 +207,7 @@ impl<'d> BufferedUart<'d> {
         rx_buffer: &'d mut [u8],
         config: Config,
     ) -> Result<Self, ConfigError> {
-        T::enable_and_reset();
+        rcc::enable_and_reset::<T>();
 
         Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config)
     }
@@ -225,7 +226,7 @@ impl<'d> BufferedUart<'d> {
     ) -> Result<Self, ConfigError> {
         into_ref!(cts, rts);
 
-        T::enable_and_reset();
+        rcc::enable_and_reset::<T>();
 
         rts.set_as_af(rts.af_num(), AFType::OutputPushPull);
         cts.set_as_af(cts.af_num(), AFType::Input);
@@ -251,7 +252,7 @@ impl<'d> BufferedUart<'d> {
     ) -> Result<Self, ConfigError> {
         into_ref!(de);
 
-        T::enable_and_reset();
+        rcc::enable_and_reset::<T>();
 
         de.set_as_af(de.af_num(), AFType::OutputPushPull);
         T::info().regs.cr3().write(|w| {
@@ -545,7 +546,7 @@ fn drop_tx_rx(info: &Info, state: &State) {
         refcount == 1
     });
     if is_last_drop {
-        info.enable_bit.disable();
+        info.rcc.disable();
     }
 }
 
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs
index b24335f3a..2a39c6301 100644
--- a/embassy-stm32/src/usart/mod.rs
+++ b/embassy-stm32/src/usart/mod.rs
@@ -28,7 +28,7 @@ use crate::pac::usart::Lpuart as Regs;
 #[cfg(any(usart_v1, usart_v2))]
 use crate::pac::usart::Usart as Regs;
 use crate::pac::usart::{regs, vals};
-use crate::rcc::{ClockEnableBit, SealedRccPeripheral};
+use crate::rcc::{self, RccInfo, SealedRccPeripheral};
 use crate::time::Hertz;
 use crate::Peripheral;
 
@@ -429,7 +429,7 @@ impl<'d, M: Mode> UartTx<'d, M> {
         tx_dma: Option<ChannelAndRequest<'d>>,
         config: Config,
     ) -> Result<Self, ConfigError> {
-        T::enable_and_reset();
+        rcc::enable_and_reset::<T>();
 
         let info = T::info();
         let state = T::state();
@@ -775,7 +775,7 @@ impl<'d, M: Mode> UartRx<'d, M> {
         rx_dma: Option<ChannelAndRequest<'d>>,
         config: Config,
     ) -> Result<Self, ConfigError> {
-        T::enable_and_reset();
+        rcc::enable_and_reset::<T>();
 
         let info = T::info();
         let state = T::state();
@@ -916,7 +916,7 @@ fn drop_tx_rx(info: &Info, state: &State) {
         refcount == 1
     });
     if is_last_drop {
-        info.enable_bit.disable();
+        info.rcc.disable();
     }
 }
 
@@ -1228,7 +1228,7 @@ impl<'d, M: Mode> Uart<'d, M> {
         rx_dma: Option<ChannelAndRequest<'d>>,
         config: Config,
     ) -> Result<Self, ConfigError> {
-        T::enable_and_reset();
+        rcc::enable_and_reset::<T>();
 
         let info = T::info();
         let state = T::state();
@@ -1718,7 +1718,7 @@ impl State {
 
 struct Info {
     regs: Regs,
-    enable_bit: ClockEnableBit,
+    rcc: RccInfo,
     interrupt: Interrupt,
     kind: Kind,
 }
@@ -1754,7 +1754,7 @@ macro_rules! impl_usart {
             fn info() -> &'static Info {
                 static INFO: Info = Info {
                     regs: unsafe { Regs::from_ptr(crate::pac::$inst.as_ptr()) },
-                    enable_bit: crate::peripherals::$inst::ENABLE_BIT,
+                    rcc: crate::peripherals::$inst::RCC_INFO,
                     interrupt: crate::interrupt::typelevel::$irq::IRQ,
                     kind: $kind,
                 };
diff --git a/embassy-stm32/src/usb/mod.rs b/embassy-stm32/src/usb/mod.rs
index 349438ec5..ce9fe0a9b 100644
--- a/embassy-stm32/src/usb/mod.rs
+++ b/embassy-stm32/src/usb/mod.rs
@@ -6,7 +6,7 @@ mod _version;
 pub use _version::*;
 
 use crate::interrupt::typelevel::Interrupt;
-use crate::rcc::SealedRccPeripheral;
+use crate::rcc;
 
 /// clock, power initialization stuff that's common for USB and OTG.
 fn common_init<T: Instance>() {
@@ -65,5 +65,5 @@ fn common_init<T: Instance>() {
     T::Interrupt::unpend();
     unsafe { T::Interrupt::enable() };
 
-    <T as SealedRccPeripheral>::enable_and_reset();
+    rcc::enable_and_reset::<T>();
 }
diff --git a/embassy-stm32/src/usb/otg.rs b/embassy-stm32/src/usb/otg.rs
index 3debd5079..e5131250a 100644
--- a/embassy-stm32/src/usb/otg.rs
+++ b/embassy-stm32/src/usb/otg.rs
@@ -13,7 +13,7 @@ use embassy_usb_synopsys_otg::{
 use crate::gpio::AFType;
 use crate::interrupt;
 use crate::interrupt::typelevel::Interrupt;
-use crate::rcc::{RccPeripheral, SealedRccPeripheral};
+use crate::rcc::{self, RccPeripheral};
 
 const MAX_EP_COUNT: usize = 9;
 
@@ -246,7 +246,7 @@ impl<'d, T: Instance> Bus<'d, T> {
     fn disable(&mut self) {
         T::Interrupt::disable();
 
-        <T as SealedRccPeripheral>::disable();
+        rcc::disable::<T>();
         self.inited = false;
 
         #[cfg(stm32l4)]