diff --git a/CHANGELOG.md b/CHANGELOG.md
index 547c2b9..4ab9990 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
 
 ## [Unreleased]
 
+### Added
+
+- Implement `embedded_hal::digital::blocking::IoPin` for `CdevPin` and `SysfsPin`
+
 ## [v0.4.0-alpha.1] - 2021-09-27
 
 ### Changed
diff --git a/src/cdev_pin.rs b/src/cdev_pin.rs
index 5a11fe1..9d91a95 100644
--- a/src/cdev_pin.rs
+++ b/src/cdev_pin.rs
@@ -5,7 +5,7 @@
 /// Newtype around [`gpio_cdev::LineHandle`] that implements the `embedded-hal` traits
 ///
 /// [`gpio_cdev::LineHandle`]: https://docs.rs/gpio-cdev/0.5.0/gpio_cdev/struct.LineHandle.html
-pub struct CdevPin(pub gpio_cdev::LineHandle, bool);
+pub struct CdevPin(pub gpio_cdev::LineHandle, gpio_cdev::LineInfo);
 
 impl CdevPin {
     /// See [`gpio_cdev::Line::request`][0] for details.
@@ -13,7 +13,43 @@ impl CdevPin {
     /// [0]: https://docs.rs/gpio-cdev/0.5.0/gpio_cdev/struct.Line.html#method.request
     pub fn new(handle: gpio_cdev::LineHandle) -> Result<Self, gpio_cdev::errors::Error> {
         let info = handle.line().info()?;
-        Ok(CdevPin(handle, info.is_active_low()))
+        Ok(CdevPin(handle, info))
+    }
+
+    fn get_input_flags(&self) -> gpio_cdev::LineRequestFlags {
+        if self.1.is_active_low() {
+            return gpio_cdev::LineRequestFlags::INPUT | gpio_cdev::LineRequestFlags::ACTIVE_LOW;
+        }
+        gpio_cdev::LineRequestFlags::INPUT
+    }
+
+    fn get_output_flags(&self) -> gpio_cdev::LineRequestFlags {
+        let mut flags = gpio_cdev::LineRequestFlags::OUTPUT;
+        if self.1.is_active_low() {
+            flags.insert(gpio_cdev::LineRequestFlags::ACTIVE_LOW);
+        }
+        if self.1.is_open_drain() {
+            flags.insert(gpio_cdev::LineRequestFlags::OPEN_DRAIN);
+        } else if self.1.is_open_source() {
+            flags.insert(gpio_cdev::LineRequestFlags::OPEN_SOURCE);
+        }
+        return flags;
+    }
+}
+
+/// Converts a pin state to the gpio_cdev compatible numeric value, accounting
+/// for the active_low condition.
+fn state_to_value(state: embedded_hal::digital::PinState, is_active_low: bool) -> u8 {
+    if is_active_low {
+        match state {
+            embedded_hal::digital::PinState::High => 0,
+            embedded_hal::digital::PinState::Low => 1,
+        }
+    } else {
+        match state {
+            embedded_hal::digital::PinState::High => 1,
+            embedded_hal::digital::PinState::Low => 0,
+        }
     }
 }
 
@@ -21,19 +57,17 @@ impl embedded_hal::digital::blocking::OutputPin for CdevPin {
     type Error = gpio_cdev::errors::Error;
 
     fn set_low(&mut self) -> Result<(), Self::Error> {
-        if self.1 {
-            self.0.set_value(1)
-        } else {
-            self.0.set_value(0)
-        }
+        self.0.set_value(state_to_value(
+            embedded_hal::digital::PinState::Low,
+            self.1.is_active_low(),
+        ))
     }
 
     fn set_high(&mut self) -> Result<(), Self::Error> {
-        if self.1 {
-            self.0.set_value(0)
-        } else {
-            self.0.set_value(1)
-        }
+        self.0.set_value(state_to_value(
+            embedded_hal::digital::PinState::High,
+            self.1.is_active_low(),
+        ))
     }
 }
 
@@ -41,11 +75,12 @@ impl embedded_hal::digital::blocking::InputPin for CdevPin {
     type Error = gpio_cdev::errors::Error;
 
     fn is_high(&self) -> Result<bool, Self::Error> {
-        if !self.1 {
-            self.0.get_value().map(|val| val != 0)
-        } else {
-            self.0.get_value().map(|val| val == 0)
-        }
+        self.0.get_value().map(|val| {
+            val == state_to_value(
+                embedded_hal::digital::PinState::High,
+                self.1.is_active_low(),
+            )
+        })
     }
 
     fn is_low(&self) -> Result<bool, Self::Error> {
@@ -53,6 +88,49 @@ impl embedded_hal::digital::blocking::InputPin for CdevPin {
     }
 }
 
+impl embedded_hal::digital::blocking::IoPin<CdevPin, CdevPin> for CdevPin {
+    type Error = gpio_cdev::errors::Error;
+
+    fn into_input_pin(self) -> Result<CdevPin, Self::Error> {
+        if self.1.direction() == gpio_cdev::LineDirection::In {
+            return Ok(self);
+        }
+        let line = self.0.line().clone();
+        let input_flags = self.get_input_flags();
+        let consumer = self.1.consumer().unwrap_or("").to_owned();
+
+        // Drop self to free the line before re-requesting it in a new mode.
+        std::mem::drop(self);
+
+        CdevPin::new(line.request(input_flags, 0, &consumer)?)
+    }
+
+    fn into_output_pin(
+        self,
+        state: embedded_hal::digital::PinState,
+    ) -> Result<CdevPin, Self::Error> {
+        if self.1.direction() == gpio_cdev::LineDirection::Out {
+            return Ok(self);
+        }
+
+        let line = self.0.line().clone();
+        let output_flags = self.get_output_flags();
+        let consumer = self.1.consumer().unwrap_or("").to_owned();
+
+        // Drop self to free the line before re-requesting it in a new mode.
+        std::mem::drop(self);
+
+        CdevPin::new(line.request(
+            output_flags,
+            state_to_value(
+                state,
+                output_flags.intersects(gpio_cdev::LineRequestFlags::ACTIVE_LOW),
+            ),
+            &consumer,
+        )?)
+    }
+}
+
 impl core::ops::Deref for CdevPin {
     type Target = gpio_cdev::LineHandle;
 
diff --git a/src/sysfs_pin.rs b/src/sysfs_pin.rs
index 3d606ee..f569125 100644
--- a/src/sysfs_pin.rs
+++ b/src/sysfs_pin.rs
@@ -64,6 +64,26 @@ impl embedded_hal::digital::blocking::InputPin for SysfsPin {
     }
 }
 
+impl embedded_hal::digital::blocking::IoPin<SysfsPin, SysfsPin> for SysfsPin {
+    type Error = sysfs_gpio::Error;
+
+    fn into_input_pin(self) -> Result<SysfsPin, Self::Error> {
+        self.set_direction(sysfs_gpio::Direction::In)?;
+        Ok(self)
+    }
+
+    fn into_output_pin(
+        self,
+        state: embedded_hal::digital::PinState,
+    ) -> Result<SysfsPin, Self::Error> {
+        self.set_direction(match state {
+            embedded_hal::digital::PinState::High => sysfs_gpio::Direction::High,
+            embedded_hal::digital::PinState::Low => sysfs_gpio::Direction::Low,
+        })?;
+        Ok(self)
+    }
+}
+
 impl core::ops::Deref for SysfsPin {
     type Target = sysfs_gpio::Pin;