diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs
index 0bf57ef8a..6d12af2cc 100644
--- a/embassy-stm32/src/i2c/mod.rs
+++ b/embassy-stm32/src/i2c/mod.rs
@@ -9,16 +9,16 @@ use core::future::Future;
 use core::iter;
 use core::marker::PhantomData;
 
-use embassy_hal_internal::{into_ref, Peripheral};
+use embassy_hal_internal::{Peripheral, PeripheralRef};
 use embassy_sync::waitqueue::AtomicWaker;
 #[cfg(feature = "time")]
 use embassy_time::{Duration, Instant};
 
 use crate::dma::ChannelAndRequest;
-use crate::gpio::{AFType, Pull};
+use crate::gpio::{AFType, AnyPin, Pull, SealedPin as _, Speed};
 use crate::interrupt::typelevel::Interrupt;
 use crate::mode::{Async, Blocking, Mode};
-use crate::rcc::{self, RccInfo, SealedRccPeripheral};
+use crate::rcc::{RccInfo, SealedRccPeripheral};
 use crate::time::Hertz;
 use crate::{interrupt, peripherals};
 
@@ -72,11 +72,29 @@ impl Default for Config {
     }
 }
 
+impl Config {
+    fn scl_pull_mode(&self) -> Pull {
+        match self.scl_pullup {
+            true => Pull::Up,
+            false => Pull::Down,
+        }
+    }
+
+    fn sda_pull_mode(&self) -> Pull {
+        match self.sda_pullup {
+            true => Pull::Up,
+            false => Pull::Down,
+        }
+    }
+}
+
 /// I2C driver.
 pub struct I2c<'d, M: Mode> {
     info: &'static Info,
     state: &'static State,
     kernel_clock: Hertz,
+    scl: Option<PeripheralRef<'d, AnyPin>>,
+    sda: Option<PeripheralRef<'d, AnyPin>>,
     tx_dma: Option<ChannelAndRequest<'d>>,
     rx_dma: Option<ChannelAndRequest<'d>>,
     #[cfg(feature = "time")]
@@ -98,7 +116,15 @@ impl<'d> I2c<'d, Async> {
         freq: Hertz,
         config: Config,
     ) -> Self {
-        Self::new_inner(peri, scl, sda, new_dma!(tx_dma), new_dma!(rx_dma), freq, config)
+        Self::new_inner(
+            peri,
+            new_pin!(scl, AFType::OutputOpenDrain, Speed::Medium, config.scl_pull_mode()),
+            new_pin!(sda, AFType::OutputOpenDrain, Speed::Medium, config.sda_pull_mode()),
+            new_dma!(tx_dma),
+            new_dma!(rx_dma),
+            freq,
+            config,
+        )
     }
 }
 
@@ -111,7 +137,15 @@ impl<'d> I2c<'d, Blocking> {
         freq: Hertz,
         config: Config,
     ) -> Self {
-        Self::new_inner(peri, scl, sda, None, None, freq, config)
+        Self::new_inner(
+            peri,
+            new_pin!(scl, AFType::OutputOpenDrain, Speed::Medium, config.scl_pull_mode()),
+            new_pin!(sda, AFType::OutputOpenDrain, Speed::Medium, config.sda_pull_mode()),
+            None,
+            None,
+            freq,
+            config,
+        )
     }
 }
 
@@ -119,34 +153,13 @@ impl<'d, M: Mode> I2c<'d, M> {
     /// Create a new I2C driver.
     fn new_inner<T: Instance>(
         _peri: impl Peripheral<P = T> + 'd,
-        scl: impl Peripheral<P = impl SclPin<T>> + 'd,
-        sda: impl Peripheral<P = impl SdaPin<T>> + 'd,
+        scl: Option<PeripheralRef<'d, AnyPin>>,
+        sda: Option<PeripheralRef<'d, AnyPin>>,
         tx_dma: Option<ChannelAndRequest<'d>>,
         rx_dma: Option<ChannelAndRequest<'d>>,
         freq: Hertz,
         config: Config,
     ) -> Self {
-        into_ref!(scl, sda);
-
-        rcc::enable_and_reset::<T>();
-
-        scl.set_as_af_pull(
-            scl.af_num(),
-            AFType::OutputOpenDrain,
-            match config.scl_pullup {
-                true => Pull::Up,
-                false => Pull::None,
-            },
-        );
-        sda.set_as_af_pull(
-            sda.af_num(),
-            AFType::OutputOpenDrain,
-            match config.sda_pullup {
-                true => Pull::Up,
-                false => Pull::None,
-            },
-        );
-
         unsafe { T::EventInterrupt::enable() };
         unsafe { T::ErrorInterrupt::enable() };
 
@@ -154,18 +167,23 @@ impl<'d, M: Mode> I2c<'d, M> {
             info: T::info(),
             state: T::state(),
             kernel_clock: T::frequency(),
+            scl,
+            sda,
             tx_dma,
             rx_dma,
             #[cfg(feature = "time")]
             timeout: config.timeout,
             _phantom: PhantomData,
         };
-
-        this.init(freq, config);
-
+        this.enable_and_init(freq, config);
         this
     }
 
+    fn enable_and_init(&mut self, freq: Hertz, config: Config) {
+        self.info.rcc.enable_and_reset();
+        self.init(freq, config);
+    }
+
     fn timeout(&self) -> Timeout {
         Timeout {
             #[cfg(feature = "time")]
@@ -174,6 +192,15 @@ impl<'d, M: Mode> I2c<'d, M> {
     }
 }
 
+impl<'d, M: Mode> Drop for I2c<'d, M> {
+    fn drop(&mut self) {
+        self.scl.as_ref().map(|x| x.set_as_disconnected());
+        self.sda.as_ref().map(|x| x.set_as_disconnected());
+
+        self.info.rcc.disable()
+    }
+}
+
 #[derive(Copy, Clone)]
 struct Timeout {
     #[cfg(feature = "time")]
diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs
index 0e2bd2e40..28026f83c 100644
--- a/embassy-stm32/src/i2c/v1.rs
+++ b/embassy-stm32/src/i2c/v1.rs
@@ -700,12 +700,6 @@ impl<'d> I2c<'d, Async> {
     }
 }
 
-impl<'d, M: PeriMode> Drop for I2c<'d, M> {
-    fn drop(&mut self) {
-        self.info.rcc.disable()
-    }
-}
-
 enum Mode {
     Fast,
     Standard,
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs
index 193f29733..80163c287 100644
--- a/embassy-stm32/src/i2c/v2.rs
+++ b/embassy-stm32/src/i2c/v2.rs
@@ -671,12 +671,6 @@ impl<'d> I2c<'d, Async> {
     }
 }
 
-impl<'d, M: Mode> Drop for I2c<'d, M> {
-    fn drop(&mut self) {
-        self.info.rcc.disable();
-    }
-}
-
 /// I2C Stop Configuration
 ///
 /// Peripheral options for generating the STOP condition