diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index fe5236ed6..ee224da67 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -826,20 +826,20 @@ fn main() {
         (("dcmi", "PIXCLK"), quote!(crate::dcmi::PixClkPin)),
         (("usb", "DP"), quote!(crate::usb::DpPin)),
         (("usb", "DM"), quote!(crate::usb::DmPin)),
-        (("otg", "DP"), quote!(crate::usb_otg::DpPin)),
-        (("otg", "DM"), quote!(crate::usb_otg::DmPin)),
-        (("otg", "ULPI_CK"), quote!(crate::usb_otg::UlpiClkPin)),
-        (("otg", "ULPI_DIR"), quote!(crate::usb_otg::UlpiDirPin)),
-        (("otg", "ULPI_NXT"), quote!(crate::usb_otg::UlpiNxtPin)),
-        (("otg", "ULPI_STP"), quote!(crate::usb_otg::UlpiStpPin)),
-        (("otg", "ULPI_D0"), quote!(crate::usb_otg::UlpiD0Pin)),
-        (("otg", "ULPI_D1"), quote!(crate::usb_otg::UlpiD1Pin)),
-        (("otg", "ULPI_D2"), quote!(crate::usb_otg::UlpiD2Pin)),
-        (("otg", "ULPI_D3"), quote!(crate::usb_otg::UlpiD3Pin)),
-        (("otg", "ULPI_D4"), quote!(crate::usb_otg::UlpiD4Pin)),
-        (("otg", "ULPI_D5"), quote!(crate::usb_otg::UlpiD5Pin)),
-        (("otg", "ULPI_D6"), quote!(crate::usb_otg::UlpiD6Pin)),
-        (("otg", "ULPI_D7"), quote!(crate::usb_otg::UlpiD7Pin)),
+        (("otg", "DP"), quote!(crate::usb::DpPin)),
+        (("otg", "DM"), quote!(crate::usb::DmPin)),
+        (("otg", "ULPI_CK"), quote!(crate::usb::UlpiClkPin)),
+        (("otg", "ULPI_DIR"), quote!(crate::usb::UlpiDirPin)),
+        (("otg", "ULPI_NXT"), quote!(crate::usb::UlpiNxtPin)),
+        (("otg", "ULPI_STP"), quote!(crate::usb::UlpiStpPin)),
+        (("otg", "ULPI_D0"), quote!(crate::usb::UlpiD0Pin)),
+        (("otg", "ULPI_D1"), quote!(crate::usb::UlpiD1Pin)),
+        (("otg", "ULPI_D2"), quote!(crate::usb::UlpiD2Pin)),
+        (("otg", "ULPI_D3"), quote!(crate::usb::UlpiD3Pin)),
+        (("otg", "ULPI_D4"), quote!(crate::usb::UlpiD4Pin)),
+        (("otg", "ULPI_D5"), quote!(crate::usb::UlpiD5Pin)),
+        (("otg", "ULPI_D6"), quote!(crate::usb::UlpiD6Pin)),
+        (("otg", "ULPI_D7"), quote!(crate::usb::UlpiD7Pin)),
         (("can", "TX"), quote!(crate::can::TxPin)),
         (("can", "RX"), quote!(crate::can::RxPin)),
         (("eth", "REF_CLK"), quote!(crate::eth::RefClkPin)),
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index b38b5c29d..9e26a3513 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -79,10 +79,8 @@ pub mod ucpd;
 pub mod uid;
 #[cfg(usart)]
 pub mod usart;
-#[cfg(usb)]
+#[cfg(any(usb, otg))]
 pub mod usb;
-#[cfg(otg)]
-pub mod usb_otg;
 #[cfg(iwdg)]
 pub mod wdg;
 
@@ -107,10 +105,10 @@ pub use crate::_generated::interrupt;
 /// Example of how to bind one interrupt:
 ///
 /// ```rust,ignore
-/// use embassy_stm32::{bind_interrupts, usb_otg, peripherals};
+/// use embassy_stm32::{bind_interrupts, usb, peripherals};
 ///
 /// bind_interrupts!(struct Irqs {
-///     OTG_FS => usb_otg::InterruptHandler<peripherals::USB_OTG_FS>;
+///     OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>;
 /// });
 /// ```
 ///
diff --git a/embassy-stm32/src/usb/mod.rs b/embassy-stm32/src/usb/mod.rs
index 4debd4e54..788f61f16 100644
--- a/embassy-stm32/src/usb/mod.rs
+++ b/embassy-stm32/src/usb/mod.rs
@@ -1,37 +1,69 @@
 //! Universal Serial Bus (USB)
 
-use crate::interrupt;
-use crate::rcc::RccPeripheral;
+#[cfg_attr(usb, path = "usb.rs")]
+#[cfg_attr(otg, path = "otg.rs")]
+mod _version;
+pub use _version::*;
 
-mod usb;
-pub use usb::*;
+use crate::interrupt::typelevel::Interrupt;
+use crate::rcc::sealed::RccPeripheral;
 
-pub(crate) mod sealed {
-    pub trait Instance {
-        fn regs() -> crate::pac::usb::Usb;
+/// clock, power initialization stuff that's common for USB and OTG.
+fn common_init<T: Instance>() {
+    // Check the USB clock is enabled and running at exactly 48 MHz.
+    // frequency() will panic if not enabled
+    let freq = T::frequency();
+    // Check frequency is within the 0.25% tolerance allowed by the spec.
+    // Clock might not be exact 48Mhz due to rounding errors in PLL calculation, or if the user
+    // has tight clock restrictions due to something else (like audio).
+    if freq.0.abs_diff(48_000_000) > 120_000 {
+        panic!(
+            "USB clock should be 48Mhz but is {} Hz. Please double-check your RCC settings.",
+            freq.0
+        )
     }
+
+    #[cfg(any(stm32l4, stm32l5, stm32wb))]
+    critical_section::with(|_| crate::pac::PWR.cr2().modify(|w| w.set_usv(true)));
+
+    #[cfg(pwr_h5)]
+    critical_section::with(|_| crate::pac::PWR.usbscr().modify(|w| w.set_usb33sv(true)));
+
+    #[cfg(stm32h7)]
+    {
+        // If true, VDD33USB is generated by internal regulator from VDD50USB
+        // If false, VDD33USB and VDD50USB must be suplied directly with 3.3V (default on nucleo)
+        // TODO: unhardcode
+        let internal_regulator = false;
+
+        // Enable USB power
+        critical_section::with(|_| {
+            crate::pac::PWR.cr3().modify(|w| {
+                w.set_usb33den(true);
+                w.set_usbregen(internal_regulator);
+            })
+        });
+
+        // Wait for USB power to stabilize
+        while !crate::pac::PWR.cr3().read().usb33rdy() {}
+    }
+
+    #[cfg(stm32u5)]
+    {
+        // Enable USB power
+        critical_section::with(|_| {
+            crate::pac::PWR.svmcr().modify(|w| {
+                w.set_usv(true);
+                w.set_uvmen(true);
+            })
+        });
+
+        // Wait for USB power to stabilize
+        while !crate::pac::PWR.svmsr().read().vddusbrdy() {}
+    }
+
+    T::Interrupt::unpend();
+    unsafe { T::Interrupt::enable() };
+
+    <T as RccPeripheral>::enable_and_reset();
 }
-
-/// USB instance trait.
-pub trait Instance: sealed::Instance + RccPeripheral + 'static {
-    /// Interrupt for this USB instance.
-    type Interrupt: interrupt::typelevel::Interrupt;
-}
-
-// Internal PHY pins
-pin_trait!(DpPin, Instance);
-pin_trait!(DmPin, Instance);
-
-foreach_interrupt!(
-    ($inst:ident, usb, $block:ident, LP, $irq:ident) => {
-        impl sealed::Instance for crate::peripherals::$inst {
-            fn regs() -> crate::pac::usb::Usb {
-                crate::pac::$inst
-            }
-        }
-
-        impl Instance for crate::peripherals::$inst {
-            type Interrupt = crate::interrupt::typelevel::$irq;
-        }
-    };
-);
diff --git a/embassy-stm32/src/usb_otg/usb.rs b/embassy-stm32/src/usb/otg.rs
similarity index 90%
rename from embassy-stm32/src/usb_otg/usb.rs
rename to embassy-stm32/src/usb/otg.rs
index 373697ec8..80a08f3c5 100644
--- a/embassy-stm32/src/usb_otg/usb.rs
+++ b/embassy-stm32/src/usb/otg.rs
@@ -11,7 +11,6 @@ use embassy_usb_driver::{
 };
 use futures::future::poll_fn;
 
-use super::*;
 use crate::gpio::sealed::AFType;
 use crate::interrupt;
 use crate::interrupt::typelevel::Interrupt;
@@ -561,8 +560,7 @@ impl<'d, T: Instance> Bus<'d, T> {
 
 impl<'d, T: Instance> Bus<'d, T> {
     fn init(&mut self) {
-        #[cfg(stm32l4)]
-        critical_section::with(|_| crate::pac::PWR.cr2().modify(|w| w.set_usv(true)));
+        super::common_init::<T>();
 
         #[cfg(stm32f7)]
         {
@@ -590,22 +588,6 @@ impl<'d, T: Instance> Bus<'d, T> {
 
         #[cfg(stm32h7)]
         {
-            // If true, VDD33USB is generated by internal regulator from VDD50USB
-            // If false, VDD33USB and VDD50USB must be suplied directly with 3.3V (default on nucleo)
-            // TODO: unhardcode
-            let internal_regulator = false;
-
-            // Enable USB power
-            critical_section::with(|_| {
-                crate::pac::PWR.cr3().modify(|w| {
-                    w.set_usb33den(true);
-                    w.set_usbregen(internal_regulator);
-                })
-            });
-
-            // Wait for USB power to stabilize
-            while !crate::pac::PWR.cr3().read().usb33rdy() {}
-
             // Enable ULPI clock if external PHY is used
             let ulpien = !self.phy_type.internal();
             critical_section::with(|_| {
@@ -626,25 +608,6 @@ impl<'d, T: Instance> Bus<'d, T> {
             });
         }
 
-        #[cfg(stm32u5)]
-        {
-            // Enable USB power
-            critical_section::with(|_| {
-                crate::pac::PWR.svmcr().modify(|w| {
-                    w.set_usv(true);
-                    w.set_uvmen(true);
-                })
-            });
-
-            // Wait for USB power to stabilize
-            while !crate::pac::PWR.svmsr().read().vddusbrdy() {}
-        }
-
-        <T as RccPeripheral>::enable_and_reset();
-
-        T::Interrupt::unpend();
-        unsafe { T::Interrupt::enable() };
-
         let r = T::regs();
         let core_id = r.cid().read().0;
         trace!("Core id {:08x}", core_id);
@@ -1469,3 +1432,159 @@ fn calculate_trdt(speed: vals::Dspd, ahb_freq: Hertz) -> u8 {
 fn quirk_setup_late_cnak(r: crate::pac::otg::Otg) -> bool {
     r.cid().read().0 & 0xf000 == 0x1000
 }
+
+// Using Instance::ENDPOINT_COUNT requires feature(const_generic_expr) so just define maximum eps
+const MAX_EP_COUNT: usize = 9;
+
+pub(crate) mod sealed {
+    pub trait Instance {
+        const HIGH_SPEED: bool;
+        const FIFO_DEPTH_WORDS: u16;
+        const ENDPOINT_COUNT: usize;
+
+        fn regs() -> crate::pac::otg::Otg;
+        fn state() -> &'static super::State<{ super::MAX_EP_COUNT }>;
+    }
+}
+
+/// USB instance trait.
+pub trait Instance: sealed::Instance + RccPeripheral + 'static {
+    /// Interrupt for this USB instance.
+    type Interrupt: interrupt::typelevel::Interrupt;
+}
+
+// Internal PHY pins
+pin_trait!(DpPin, Instance);
+pin_trait!(DmPin, Instance);
+
+// External PHY pins
+pin_trait!(UlpiClkPin, Instance);
+pin_trait!(UlpiDirPin, Instance);
+pin_trait!(UlpiNxtPin, Instance);
+pin_trait!(UlpiStpPin, Instance);
+pin_trait!(UlpiD0Pin, Instance);
+pin_trait!(UlpiD1Pin, Instance);
+pin_trait!(UlpiD2Pin, Instance);
+pin_trait!(UlpiD3Pin, Instance);
+pin_trait!(UlpiD4Pin, Instance);
+pin_trait!(UlpiD5Pin, Instance);
+pin_trait!(UlpiD6Pin, Instance);
+pin_trait!(UlpiD7Pin, Instance);
+
+foreach_interrupt!(
+    (USB_OTG_FS, otg, $block:ident, GLOBAL, $irq:ident) => {
+        impl sealed::Instance for crate::peripherals::USB_OTG_FS {
+            const HIGH_SPEED: bool = false;
+
+            cfg_if::cfg_if! {
+                if #[cfg(stm32f1)] {
+                    const FIFO_DEPTH_WORDS: u16 = 128;
+                    const ENDPOINT_COUNT: usize = 8;
+                } else if #[cfg(any(
+                    stm32f2,
+                    stm32f401,
+                    stm32f405,
+                    stm32f407,
+                    stm32f411,
+                    stm32f415,
+                    stm32f417,
+                    stm32f427,
+                    stm32f429,
+                    stm32f437,
+                    stm32f439,
+                ))] {
+                    const FIFO_DEPTH_WORDS: u16 = 320;
+                    const ENDPOINT_COUNT: usize = 4;
+                } else if #[cfg(any(
+                    stm32f412,
+                    stm32f413,
+                    stm32f423,
+                    stm32f446,
+                    stm32f469,
+                    stm32f479,
+                    stm32f7,
+                    stm32l4,
+                    stm32u5,
+                ))] {
+                    const FIFO_DEPTH_WORDS: u16 = 320;
+                    const ENDPOINT_COUNT: usize = 6;
+                } else if #[cfg(stm32g0x1)] {
+                    const FIFO_DEPTH_WORDS: u16 = 512;
+                    const ENDPOINT_COUNT: usize = 8;
+                } else if #[cfg(stm32h7)] {
+                    const FIFO_DEPTH_WORDS: u16 = 1024;
+                    const ENDPOINT_COUNT: usize = 9;
+                } else if #[cfg(stm32u5)] {
+                    const FIFO_DEPTH_WORDS: u16 = 320;
+                    const ENDPOINT_COUNT: usize = 6;
+                } else {
+                    compile_error!("USB_OTG_FS peripheral is not supported by this chip.");
+                }
+            }
+
+            fn regs() -> crate::pac::otg::Otg {
+                crate::pac::USB_OTG_FS
+            }
+
+            fn state() -> &'static State<MAX_EP_COUNT> {
+                static STATE: State<MAX_EP_COUNT> = State::new();
+                &STATE
+            }
+        }
+
+        impl Instance for crate::peripherals::USB_OTG_FS {
+            type Interrupt = crate::interrupt::typelevel::$irq;
+        }
+    };
+
+    (USB_OTG_HS, otg, $block:ident, GLOBAL, $irq:ident) => {
+        impl sealed::Instance for crate::peripherals::USB_OTG_HS {
+            const HIGH_SPEED: bool = true;
+
+            cfg_if::cfg_if! {
+                if #[cfg(any(
+                    stm32f2,
+                    stm32f405,
+                    stm32f407,
+                    stm32f415,
+                    stm32f417,
+                    stm32f427,
+                    stm32f429,
+                    stm32f437,
+                    stm32f439,
+                ))] {
+                    const FIFO_DEPTH_WORDS: u16 = 1024;
+                    const ENDPOINT_COUNT: usize = 6;
+                } else if #[cfg(any(
+                    stm32f446,
+                    stm32f469,
+                    stm32f479,
+                    stm32f7,
+                    stm32h7,
+                ))] {
+                    const FIFO_DEPTH_WORDS: u16 = 1024;
+                    const ENDPOINT_COUNT: usize = 9;
+                } else if #[cfg(stm32u5)] {
+                    const FIFO_DEPTH_WORDS: u16 = 1024;
+                    const ENDPOINT_COUNT: usize = 9;
+                } else {
+                    compile_error!("USB_OTG_HS peripheral is not supported by this chip.");
+                }
+            }
+
+            fn regs() -> crate::pac::otg::Otg {
+                // OTG HS registers are a superset of FS registers
+                unsafe { crate::pac::otg::Otg::from_ptr(crate::pac::USB_OTG_HS.as_ptr()) }
+            }
+
+            fn state() -> &'static State<MAX_EP_COUNT> {
+                static STATE: State<MAX_EP_COUNT> = State::new();
+                &STATE
+            }
+        }
+
+        impl Instance for crate::peripherals::USB_OTG_HS {
+            type Interrupt = crate::interrupt::typelevel::$irq;
+        }
+    };
+);
diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs
index be321a19b..1fb2c9ebb 100644
--- a/embassy-stm32/src/usb/usb.rs
+++ b/embassy-stm32/src/usb/usb.rs
@@ -12,8 +12,6 @@ use embassy_usb_driver::{
     Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointInfo, EndpointType, Event, Unsupported,
 };
 
-use super::{DmPin, DpPin, Instance};
-use crate::interrupt::typelevel::Interrupt;
 use crate::pac::usb::regs;
 use crate::pac::usb::vals::{EpType, Stat};
 use crate::pac::USBRAM;
@@ -259,19 +257,11 @@ impl<'d, T: Instance> Driver<'d, T> {
         dm: impl Peripheral<P = impl DmPin<T>> + 'd,
     ) -> Self {
         into_ref!(dp, dm);
-        T::Interrupt::unpend();
-        unsafe { T::Interrupt::enable() };
+
+        super::common_init::<T>();
 
         let regs = T::regs();
 
-        #[cfg(any(stm32l4, stm32l5, stm32wb))]
-        crate::pac::PWR.cr2().modify(|w| w.set_usv(true));
-
-        #[cfg(pwr_h5)]
-        crate::pac::PWR.usbscr().modify(|w| w.set_usb33sv(true));
-
-        <T as RccPeripheral>::enable_and_reset();
-
         regs.cntr().write(|w| {
             w.set_pdwn(false);
             w.set_fres(true);
@@ -1057,3 +1047,33 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
         });
     }
 }
+
+pub(crate) mod sealed {
+    pub trait Instance {
+        fn regs() -> crate::pac::usb::Usb;
+    }
+}
+
+/// USB instance trait.
+pub trait Instance: sealed::Instance + RccPeripheral + 'static {
+    /// Interrupt for this USB instance.
+    type Interrupt: interrupt::typelevel::Interrupt;
+}
+
+// Internal PHY pins
+pin_trait!(DpPin, Instance);
+pin_trait!(DmPin, Instance);
+
+foreach_interrupt!(
+    ($inst:ident, usb, $block:ident, LP, $irq:ident) => {
+        impl sealed::Instance for crate::peripherals::$inst {
+            fn regs() -> crate::pac::usb::Usb {
+                crate::pac::$inst
+            }
+        }
+
+        impl Instance for crate::peripherals::$inst {
+            type Interrupt = crate::interrupt::typelevel::$irq;
+        }
+    };
+);
diff --git a/embassy-stm32/src/usb_otg/mod.rs b/embassy-stm32/src/usb_otg/mod.rs
deleted file mode 100644
index 0649e684b..000000000
--- a/embassy-stm32/src/usb_otg/mod.rs
+++ /dev/null
@@ -1,163 +0,0 @@
-//! USB On The Go (OTG)
-
-use crate::rcc::RccPeripheral;
-use crate::{interrupt, peripherals};
-
-mod usb;
-pub use usb::*;
-
-// Using Instance::ENDPOINT_COUNT requires feature(const_generic_expr) so just define maximum eps
-const MAX_EP_COUNT: usize = 9;
-
-pub(crate) mod sealed {
-    pub trait Instance {
-        const HIGH_SPEED: bool;
-        const FIFO_DEPTH_WORDS: u16;
-        const ENDPOINT_COUNT: usize;
-
-        fn regs() -> crate::pac::otg::Otg;
-        fn state() -> &'static super::State<{ super::MAX_EP_COUNT }>;
-    }
-}
-
-/// USB OTG instance.
-pub trait Instance: sealed::Instance + RccPeripheral {
-    /// Interrupt for this USB OTG instance.
-    type Interrupt: interrupt::typelevel::Interrupt;
-}
-
-// Internal PHY pins
-pin_trait!(DpPin, Instance);
-pin_trait!(DmPin, Instance);
-
-// External PHY pins
-pin_trait!(UlpiClkPin, Instance);
-pin_trait!(UlpiDirPin, Instance);
-pin_trait!(UlpiNxtPin, Instance);
-pin_trait!(UlpiStpPin, Instance);
-pin_trait!(UlpiD0Pin, Instance);
-pin_trait!(UlpiD1Pin, Instance);
-pin_trait!(UlpiD2Pin, Instance);
-pin_trait!(UlpiD3Pin, Instance);
-pin_trait!(UlpiD4Pin, Instance);
-pin_trait!(UlpiD5Pin, Instance);
-pin_trait!(UlpiD6Pin, Instance);
-pin_trait!(UlpiD7Pin, Instance);
-
-foreach_interrupt!(
-    (USB_OTG_FS, otg, $block:ident, GLOBAL, $irq:ident) => {
-        impl sealed::Instance for peripherals::USB_OTG_FS {
-            const HIGH_SPEED: bool = false;
-
-            cfg_if::cfg_if! {
-                if #[cfg(stm32f1)] {
-                    const FIFO_DEPTH_WORDS: u16 = 128;
-                    const ENDPOINT_COUNT: usize = 8;
-                } else if #[cfg(any(
-                    stm32f2,
-                    stm32f401,
-                    stm32f405,
-                    stm32f407,
-                    stm32f411,
-                    stm32f415,
-                    stm32f417,
-                    stm32f427,
-                    stm32f429,
-                    stm32f437,
-                    stm32f439,
-                ))] {
-                    const FIFO_DEPTH_WORDS: u16 = 320;
-                    const ENDPOINT_COUNT: usize = 4;
-                } else if #[cfg(any(
-                    stm32f412,
-                    stm32f413,
-                    stm32f423,
-                    stm32f446,
-                    stm32f469,
-                    stm32f479,
-                    stm32f7,
-                    stm32l4,
-                    stm32u5,
-                ))] {
-                    const FIFO_DEPTH_WORDS: u16 = 320;
-                    const ENDPOINT_COUNT: usize = 6;
-                } else if #[cfg(stm32g0x1)] {
-                    const FIFO_DEPTH_WORDS: u16 = 512;
-                    const ENDPOINT_COUNT: usize = 8;
-                } else if #[cfg(stm32h7)] {
-                    const FIFO_DEPTH_WORDS: u16 = 1024;
-                    const ENDPOINT_COUNT: usize = 9;
-                } else if #[cfg(stm32u5)] {
-                    const FIFO_DEPTH_WORDS: u16 = 320;
-                    const ENDPOINT_COUNT: usize = 6;
-                } else {
-                    compile_error!("USB_OTG_FS peripheral is not supported by this chip.");
-                }
-            }
-
-            fn regs() -> crate::pac::otg::Otg {
-                crate::pac::USB_OTG_FS
-            }
-
-                        fn state() -> &'static State<MAX_EP_COUNT> {
-                static STATE: State<MAX_EP_COUNT> = State::new();
-                &STATE
-            }
-        }
-
-        impl Instance for peripherals::USB_OTG_FS {
-            type Interrupt = crate::interrupt::typelevel::$irq;
-        }
-    };
-
-    (USB_OTG_HS, otg, $block:ident, GLOBAL, $irq:ident) => {
-        impl sealed::Instance for peripherals::USB_OTG_HS {
-            const HIGH_SPEED: bool = true;
-
-            cfg_if::cfg_if! {
-                if #[cfg(any(
-                    stm32f2,
-                    stm32f405,
-                    stm32f407,
-                    stm32f415,
-                    stm32f417,
-                    stm32f427,
-                    stm32f429,
-                    stm32f437,
-                    stm32f439,
-                ))] {
-                    const FIFO_DEPTH_WORDS: u16 = 1024;
-                    const ENDPOINT_COUNT: usize = 6;
-                } else if #[cfg(any(
-                    stm32f446,
-                    stm32f469,
-                    stm32f479,
-                    stm32f7,
-                    stm32h7,
-                ))] {
-                    const FIFO_DEPTH_WORDS: u16 = 1024;
-                    const ENDPOINT_COUNT: usize = 9;
-                } else if #[cfg(stm32u5)] {
-                    const FIFO_DEPTH_WORDS: u16 = 1024;
-                    const ENDPOINT_COUNT: usize = 9;
-                } else {
-                    compile_error!("USB_OTG_HS peripheral is not supported by this chip.");
-                }
-            }
-
-            fn regs() -> crate::pac::otg::Otg {
-                // OTG HS registers are a superset of FS registers
-                unsafe { crate::pac::otg::Otg::from_ptr(crate::pac::USB_OTG_HS.as_ptr()) }
-            }
-
-                        fn state() -> &'static State<MAX_EP_COUNT> {
-                static STATE: State<MAX_EP_COUNT> = State::new();
-                &STATE
-            }
-        }
-
-        impl Instance for peripherals::USB_OTG_HS {
-            type Interrupt = crate::interrupt::typelevel::$irq;
-        }
-    };
-);
diff --git a/examples/stm32f4/src/bin/usb_ethernet.rs b/examples/stm32f4/src/bin/usb_ethernet.rs
index a196259a8..405cce6bc 100644
--- a/examples/stm32f4/src/bin/usb_ethernet.rs
+++ b/examples/stm32f4/src/bin/usb_ethernet.rs
@@ -7,8 +7,8 @@ use embassy_net::tcp::TcpSocket;
 use embassy_net::{Stack, StackResources};
 use embassy_stm32::rng::{self, Rng};
 use embassy_stm32::time::Hertz;
-use embassy_stm32::usb_otg::Driver;
-use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config};
+use embassy_stm32::usb::Driver;
+use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
 use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState};
 use embassy_usb::class::cdc_ncm::{CdcNcmClass, State};
 use embassy_usb::{Builder, UsbDevice};
@@ -36,7 +36,7 @@ async fn net_task(stack: &'static Stack<Device<'static, MTU>>) -> ! {
 }
 
 bind_interrupts!(struct Irqs {
-    OTG_FS => usb_otg::InterruptHandler<peripherals::USB_OTG_FS>;
+    OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>;
     HASH_RNG => rng::InterruptHandler<peripherals::RNG>;
 });
 
@@ -63,13 +63,14 @@ async fn main(spawner: Spawner) {
         config.rcc.apb1_pre = APBPrescaler::DIV4;
         config.rcc.apb2_pre = APBPrescaler::DIV2;
         config.rcc.sys = Sysclk::PLL1_P;
+        config.rcc.mux.clk48sel = mux::Clk48sel::PLL1_Q;
     }
     let p = embassy_stm32::init(config);
 
     // Create the driver, from the HAL.
     static OUTPUT_BUFFER: StaticCell<[u8; 256]> = StaticCell::new();
     let ep_out_buffer = &mut OUTPUT_BUFFER.init([0; 256])[..];
-    let mut config = embassy_stm32::usb_otg::Config::default();
+    let mut config = embassy_stm32::usb::Config::default();
     config.vbus_detection = true;
     let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, ep_out_buffer, config);
 
diff --git a/examples/stm32f4/src/bin/usb_hid_keyboard.rs b/examples/stm32f4/src/bin/usb_hid_keyboard.rs
index 19b5971fb..6c25a0a64 100644
--- a/examples/stm32f4/src/bin/usb_hid_keyboard.rs
+++ b/examples/stm32f4/src/bin/usb_hid_keyboard.rs
@@ -8,8 +8,8 @@ use embassy_executor::Spawner;
 use embassy_stm32::exti::ExtiInput;
 use embassy_stm32::gpio::Pull;
 use embassy_stm32::time::Hertz;
-use embassy_stm32::usb_otg::Driver;
-use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config};
+use embassy_stm32::usb::Driver;
+use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
 use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State};
 use embassy_usb::control::OutResponse;
 use embassy_usb::{Builder, Handler};
@@ -18,7 +18,7 @@ use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor};
 use {defmt_rtt as _, panic_probe as _};
 
 bind_interrupts!(struct Irqs {
-    OTG_FS => usb_otg::InterruptHandler<peripherals::USB_OTG_FS>;
+    OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>;
 });
 
 #[embassy_executor::main]
@@ -42,12 +42,13 @@ async fn main(_spawner: Spawner) {
         config.rcc.apb1_pre = APBPrescaler::DIV4;
         config.rcc.apb2_pre = APBPrescaler::DIV2;
         config.rcc.sys = Sysclk::PLL1_P;
+        config.rcc.mux.clk48sel = mux::Clk48sel::PLL1_Q;
     }
     let p = embassy_stm32::init(config);
 
     // Create the driver, from the HAL.
     let mut ep_out_buffer = [0u8; 256];
-    let mut config = embassy_stm32::usb_otg::Config::default();
+    let mut config = embassy_stm32::usb::Config::default();
     config.vbus_detection = true;
     let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
 
diff --git a/examples/stm32f4/src/bin/usb_hid_mouse.rs b/examples/stm32f4/src/bin/usb_hid_mouse.rs
index c98792880..d4725d597 100644
--- a/examples/stm32f4/src/bin/usb_hid_mouse.rs
+++ b/examples/stm32f4/src/bin/usb_hid_mouse.rs
@@ -4,8 +4,8 @@
 use defmt::*;
 use embassy_executor::Spawner;
 use embassy_stm32::time::Hertz;
-use embassy_stm32::usb_otg::Driver;
-use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config};
+use embassy_stm32::usb::Driver;
+use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
 use embassy_time::Timer;
 use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State};
 use embassy_usb::control::OutResponse;
@@ -15,7 +15,7 @@ use usbd_hid::descriptor::{MouseReport, SerializedDescriptor};
 use {defmt_rtt as _, panic_probe as _};
 
 bind_interrupts!(struct Irqs {
-    OTG_FS => usb_otg::InterruptHandler<peripherals::USB_OTG_FS>;
+    OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>;
 });
 
 #[embassy_executor::main]
@@ -39,12 +39,13 @@ async fn main(_spawner: Spawner) {
         config.rcc.apb1_pre = APBPrescaler::DIV4;
         config.rcc.apb2_pre = APBPrescaler::DIV2;
         config.rcc.sys = Sysclk::PLL1_P;
+        config.rcc.mux.clk48sel = mux::Clk48sel::PLL1_Q;
     }
     let p = embassy_stm32::init(config);
 
     // Create the driver, from the HAL.
     let mut ep_out_buffer = [0u8; 256];
-    let mut config = embassy_stm32::usb_otg::Config::default();
+    let mut config = embassy_stm32::usb::Config::default();
     config.vbus_detection = true;
     let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
 
diff --git a/examples/stm32f4/src/bin/usb_raw.rs b/examples/stm32f4/src/bin/usb_raw.rs
index afff55187..15a98ff8b 100644
--- a/examples/stm32f4/src/bin/usb_raw.rs
+++ b/examples/stm32f4/src/bin/usb_raw.rs
@@ -52,8 +52,8 @@
 use defmt::*;
 use embassy_executor::Spawner;
 use embassy_stm32::time::Hertz;
-use embassy_stm32::usb_otg::Driver;
-use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config};
+use embassy_stm32::usb::Driver;
+use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
 use embassy_usb::control::{InResponse, OutResponse, Recipient, Request, RequestType};
 use embassy_usb::msos::{self, windows_version};
 use embassy_usb::types::InterfaceNumber;
@@ -66,7 +66,7 @@ use {defmt_rtt as _, panic_probe as _};
 const DEVICE_INTERFACE_GUIDS: &[&str] = &["{DAC2087C-63FA-458D-A55D-827C0762DEC7}"];
 
 bind_interrupts!(struct Irqs {
-    OTG_FS => usb_otg::InterruptHandler<peripherals::USB_OTG_FS>;
+    OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>;
 });
 
 #[embassy_executor::main]
@@ -92,12 +92,13 @@ async fn main(_spawner: Spawner) {
         config.rcc.apb1_pre = APBPrescaler::DIV4;
         config.rcc.apb2_pre = APBPrescaler::DIV2;
         config.rcc.sys = Sysclk::PLL1_P;
+        config.rcc.mux.clk48sel = mux::Clk48sel::PLL1_Q;
     }
     let p = embassy_stm32::init(config);
 
     // Create the driver, from the HAL.
     let mut ep_out_buffer = [0u8; 256];
-    let mut config = embassy_stm32::usb_otg::Config::default();
+    let mut config = embassy_stm32::usb::Config::default();
     config.vbus_detection = true;
     let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
 
diff --git a/examples/stm32f4/src/bin/usb_serial.rs b/examples/stm32f4/src/bin/usb_serial.rs
index 58d994a61..6080b34a8 100644
--- a/examples/stm32f4/src/bin/usb_serial.rs
+++ b/examples/stm32f4/src/bin/usb_serial.rs
@@ -4,8 +4,8 @@
 use defmt::{panic, *};
 use embassy_executor::Spawner;
 use embassy_stm32::time::Hertz;
-use embassy_stm32::usb_otg::{Driver, Instance};
-use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config};
+use embassy_stm32::usb::{Driver, Instance};
+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;
@@ -13,7 +13,7 @@ use futures::future::join;
 use {defmt_rtt as _, panic_probe as _};
 
 bind_interrupts!(struct Irqs {
-    OTG_FS => usb_otg::InterruptHandler<peripherals::USB_OTG_FS>;
+    OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>;
 });
 
 #[embassy_executor::main]
@@ -39,12 +39,13 @@ async fn main(_spawner: Spawner) {
         config.rcc.apb1_pre = APBPrescaler::DIV4;
         config.rcc.apb2_pre = APBPrescaler::DIV2;
         config.rcc.sys = Sysclk::PLL1_P;
+        config.rcc.mux.clk48sel = mux::Clk48sel::PLL1_Q;
     }
     let p = embassy_stm32::init(config);
 
     // Create the driver, from the HAL.
     let mut ep_out_buffer = [0u8; 256];
-    let mut config = embassy_stm32::usb_otg::Config::default();
+    let mut config = embassy_stm32::usb::Config::default();
     config.vbus_detection = true;
     let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
 
diff --git a/examples/stm32f7/src/bin/usb_serial.rs b/examples/stm32f7/src/bin/usb_serial.rs
index 97daf6bd1..26ecf3bc8 100644
--- a/examples/stm32f7/src/bin/usb_serial.rs
+++ b/examples/stm32f7/src/bin/usb_serial.rs
@@ -4,8 +4,8 @@
 use defmt::{panic, *};
 use embassy_executor::Spawner;
 use embassy_stm32::time::Hertz;
-use embassy_stm32::usb_otg::{Driver, Instance};
-use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config};
+use embassy_stm32::usb::{Driver, Instance};
+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;
@@ -13,7 +13,7 @@ use futures::future::join;
 use {defmt_rtt as _, panic_probe as _};
 
 bind_interrupts!(struct Irqs {
-    OTG_FS => usb_otg::InterruptHandler<peripherals::USB_OTG_FS>;
+    OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>;
 });
 
 #[embassy_executor::main]
@@ -39,12 +39,13 @@ async fn main(_spawner: Spawner) {
         config.rcc.apb1_pre = APBPrescaler::DIV4;
         config.rcc.apb2_pre = APBPrescaler::DIV2;
         config.rcc.sys = Sysclk::PLL1_P;
+        config.rcc.mux.clk48sel = mux::Clk48sel::PLL1_Q;
     }
     let p = embassy_stm32::init(config);
 
     // Create the driver, from the HAL.
     let mut ep_out_buffer = [0u8; 256];
-    let mut config = embassy_stm32::usb_otg::Config::default();
+    let mut config = embassy_stm32::usb::Config::default();
     config.vbus_detection = true;
     let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
 
diff --git a/examples/stm32h7/src/bin/usb_serial.rs b/examples/stm32h7/src/bin/usb_serial.rs
index d81efb541..c3ddda72a 100644
--- a/examples/stm32h7/src/bin/usb_serial.rs
+++ b/examples/stm32h7/src/bin/usb_serial.rs
@@ -3,8 +3,8 @@
 
 use defmt::{panic, *};
 use embassy_executor::Spawner;
-use embassy_stm32::usb_otg::{Driver, Instance};
-use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config};
+use embassy_stm32::usb::{Driver, Instance};
+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;
@@ -12,7 +12,7 @@ use futures::future::join;
 use {defmt_rtt as _, panic_probe as _};
 
 bind_interrupts!(struct Irqs {
-    OTG_FS => usb_otg::InterruptHandler<peripherals::USB_OTG_FS>;
+    OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>;
 });
 
 #[embassy_executor::main]
@@ -40,12 +40,13 @@ 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.mux.usbsel = mux::Usbsel::HSI48;
     }
     let p = embassy_stm32::init(config);
 
     // Create the driver, from the HAL.
     let mut ep_out_buffer = [0u8; 256];
-    let mut config = embassy_stm32::usb_otg::Config::default();
+    let mut config = embassy_stm32::usb::Config::default();
     config.vbus_detection = true;
     let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
 
diff --git a/examples/stm32l4/src/bin/usb_serial.rs b/examples/stm32l4/src/bin/usb_serial.rs
index 9247e56a1..047234d60 100644
--- a/examples/stm32l4/src/bin/usb_serial.rs
+++ b/examples/stm32l4/src/bin/usb_serial.rs
@@ -4,9 +4,8 @@
 use defmt::{panic, *};
 use defmt_rtt as _; // global logger
 use embassy_executor::Spawner;
-use embassy_stm32::rcc::*;
-use embassy_stm32::usb_otg::{Driver, Instance};
-use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config};
+use embassy_stm32::usb::{Driver, Instance};
+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;
@@ -14,7 +13,7 @@ use futures::future::join;
 use panic_probe as _;
 
 bind_interrupts!(struct Irqs {
-    OTG_FS => usb_otg::InterruptHandler<peripherals::USB_OTG_FS>;
+    OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>;
 });
 
 #[embassy_executor::main]
@@ -22,23 +21,26 @@ async fn main(_spawner: Spawner) {
     info!("Hello World!");
 
     let mut config = Config::default();
-    config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB
-    config.rcc.sys = Sysclk::PLL1_R;
-    config.rcc.hsi = true;
-    config.rcc.pll = Some(Pll {
-        source: PllSource::HSI,
-        prediv: PllPreDiv::DIV1,
-        mul: PllMul::MUL10,
-        divp: None,
-        divq: None,
-        divr: Some(PllRDiv::DIV2), // sysclk 80Mhz (16 / 1 * 10 / 2)
-    });
-
+    {
+        use embassy_stm32::rcc::*;
+        config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB
+        config.rcc.sys = Sysclk::PLL1_R;
+        config.rcc.hsi = true;
+        config.rcc.pll = Some(Pll {
+            source: PllSource::HSI,
+            prediv: PllPreDiv::DIV1,
+            mul: PllMul::MUL10,
+            divp: None,
+            divq: None,
+            divr: Some(PllRDiv::DIV2), // sysclk 80Mhz (16 / 1 * 10 / 2)
+        });
+        config.rcc.mux.clk48sel = mux::Clk48sel::HSI48;
+    }
     let p = embassy_stm32::init(config);
 
     // Create the driver, from the HAL.
     let mut ep_out_buffer = [0u8; 256];
-    let mut config = embassy_stm32::usb_otg::Config::default();
+    let mut config = embassy_stm32::usb::Config::default();
     config.vbus_detection = true;
     let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
 
diff --git a/examples/stm32l5/src/bin/usb_ethernet.rs b/examples/stm32l5/src/bin/usb_ethernet.rs
index f6d8b16d0..dc1e7022d 100644
--- a/examples/stm32l5/src/bin/usb_ethernet.rs
+++ b/examples/stm32l5/src/bin/usb_ethernet.rs
@@ -5,7 +5,6 @@ use defmt::*;
 use embassy_executor::Spawner;
 use embassy_net::tcp::TcpSocket;
 use embassy_net::{Stack, StackResources};
-use embassy_stm32::rcc::*;
 use embassy_stm32::rng::Rng;
 use embassy_stm32::usb::Driver;
 use embassy_stm32::{bind_interrupts, peripherals, rng, usb, Config};
@@ -44,17 +43,22 @@ async fn net_task(stack: &'static Stack<Device<'static, MTU>>) -> ! {
 #[embassy_executor::main]
 async fn main(spawner: Spawner) {
     let mut config = Config::default();
-    config.rcc.hsi = true;
-    config.rcc.sys = Sysclk::PLL1_R;
-    config.rcc.pll = Some(Pll {
-        // 80Mhz clock (16 / 1 * 10 / 2)
-        source: PllSource::HSI,
-        prediv: PllPreDiv::DIV1,
-        mul: PllMul::MUL10,
-        divp: None,
-        divq: None,
-        divr: Some(PllRDiv::DIV2),
-    });
+    {
+        use embassy_stm32::rcc::*;
+        config.rcc.hsi = true;
+        config.rcc.sys = Sysclk::PLL1_R;
+        config.rcc.pll = Some(Pll {
+            // 80Mhz clock (16 / 1 * 10 / 2)
+            source: PllSource::HSI,
+            prediv: PllPreDiv::DIV1,
+            mul: PllMul::MUL10,
+            divp: None,
+            divq: None,
+            divr: Some(PllRDiv::DIV2),
+        });
+        config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB
+        config.rcc.mux.clk48sel = mux::Clk48sel::HSI48;
+    }
     let p = embassy_stm32::init(config);
 
     // Create the driver, from the HAL.
diff --git a/examples/stm32l5/src/bin/usb_hid_mouse.rs b/examples/stm32l5/src/bin/usb_hid_mouse.rs
index c51ed96e0..b86fba455 100644
--- a/examples/stm32l5/src/bin/usb_hid_mouse.rs
+++ b/examples/stm32l5/src/bin/usb_hid_mouse.rs
@@ -4,7 +4,6 @@
 use defmt::*;
 use embassy_executor::Spawner;
 use embassy_futures::join::join;
-use embassy_stm32::rcc::*;
 use embassy_stm32::usb::Driver;
 use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
 use embassy_time::Timer;
@@ -21,17 +20,22 @@ bind_interrupts!(struct Irqs {
 #[embassy_executor::main]
 async fn main(_spawner: Spawner) {
     let mut config = Config::default();
-    config.rcc.hsi = true;
-    config.rcc.sys = Sysclk::PLL1_R;
-    config.rcc.pll = Some(Pll {
-        // 80Mhz clock (16 / 1 * 10 / 2)
-        source: PllSource::HSI,
-        prediv: PllPreDiv::DIV1,
-        mul: PllMul::MUL10,
-        divp: None,
-        divq: None,
-        divr: Some(PllRDiv::DIV2),
-    });
+    {
+        use embassy_stm32::rcc::*;
+        config.rcc.hsi = true;
+        config.rcc.sys = Sysclk::PLL1_R;
+        config.rcc.pll = Some(Pll {
+            // 80Mhz clock (16 / 1 * 10 / 2)
+            source: PllSource::HSI,
+            prediv: PllPreDiv::DIV1,
+            mul: PllMul::MUL10,
+            divp: None,
+            divq: None,
+            divr: Some(PllRDiv::DIV2),
+        });
+        config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB
+        config.rcc.mux.clk48sel = mux::Clk48sel::HSI48;
+    }
     let p = embassy_stm32::init(config);
 
     // Create the driver, from the HAL.
diff --git a/examples/stm32l5/src/bin/usb_serial.rs b/examples/stm32l5/src/bin/usb_serial.rs
index 87987f2ce..5e2378b58 100644
--- a/examples/stm32l5/src/bin/usb_serial.rs
+++ b/examples/stm32l5/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::*;
 use embassy_stm32::usb::{Driver, Instance};
 use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
 use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
@@ -19,17 +18,22 @@ bind_interrupts!(struct Irqs {
 #[embassy_executor::main]
 async fn main(_spawner: Spawner) {
     let mut config = Config::default();
-    config.rcc.hsi = true;
-    config.rcc.sys = Sysclk::PLL1_R;
-    config.rcc.pll = Some(Pll {
-        // 80Mhz clock (16 / 1 * 10 / 2)
-        source: PllSource::HSI,
-        prediv: PllPreDiv::DIV1,
-        mul: PllMul::MUL10,
-        divp: None,
-        divq: None,
-        divr: Some(PllRDiv::DIV2),
-    });
+    {
+        use embassy_stm32::rcc::*;
+        config.rcc.hsi = true;
+        config.rcc.sys = Sysclk::PLL1_R;
+        config.rcc.pll = Some(Pll {
+            // 80Mhz clock (16 / 1 * 10 / 2)
+            source: PllSource::HSI,
+            prediv: PllPreDiv::DIV1,
+            mul: PllMul::MUL10,
+            divp: None,
+            divq: None,
+            divr: Some(PllRDiv::DIV2),
+        });
+        config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB
+        config.rcc.mux.clk48sel = mux::Clk48sel::HSI48;
+    }
     let p = embassy_stm32::init(config);
 
     info!("Hello World!");
diff --git a/examples/stm32u5/src/bin/usb_serial.rs b/examples/stm32u5/src/bin/usb_serial.rs
index 61851e5a2..33e02ce3b 100644
--- a/examples/stm32u5/src/bin/usb_serial.rs
+++ b/examples/stm32u5/src/bin/usb_serial.rs
@@ -4,8 +4,8 @@
 use defmt::{panic, *};
 use defmt_rtt as _; // global logger
 use embassy_executor::Spawner;
-use embassy_stm32::usb_otg::{Driver, Instance};
-use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config};
+use embassy_stm32::usb::{Driver, Instance};
+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;
@@ -13,7 +13,7 @@ use futures::future::join;
 use panic_probe as _;
 
 bind_interrupts!(struct Irqs {
-    OTG_FS => usb_otg::InterruptHandler<peripherals::USB_OTG_FS>;
+    OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>;
 });
 
 #[embassy_executor::main]
@@ -35,13 +35,14 @@ async fn main(_spawner: Spawner) {
         config.rcc.sys = Sysclk::PLL1_R;
         config.rcc.voltage_range = VoltageScale::RANGE1;
         config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB
+        config.rcc.mux.iclksel = mux::Iclksel::HSI48; // USB uses ICLK
     }
 
     let p = embassy_stm32::init(config);
 
     // Create the driver, from the HAL.
     let mut ep_out_buffer = [0u8; 256];
-    let mut config = embassy_stm32::usb_otg::Config::default();
+    let mut config = embassy_stm32::usb::Config::default();
     config.vbus_detection = false;
     let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);