From 2655426cd80b828593c8cd60930da3ebbd60e85c Mon Sep 17 00:00:00 2001
From: Eekle <96976531+Eekle@users.noreply.github.com>
Date: Sun, 23 Jun 2024 16:43:12 +0200
Subject: [PATCH 1/5] Add async wait to TSC

---
 embassy-stm32/src/tsc/mod.rs    | 139 ++++++++++++++++++++++----------
 examples/stm32u5/src/bin/tsc.rs |  12 ++-
 2 files changed, 107 insertions(+), 44 deletions(-)

diff --git a/embassy-stm32/src/tsc/mod.rs b/embassy-stm32/src/tsc/mod.rs
index 8ba208ce7..6497ff0ee 100644
--- a/embassy-stm32/src/tsc/mod.rs
+++ b/embassy-stm32/src/tsc/mod.rs
@@ -71,9 +71,13 @@ use embassy_hal_internal::{into_ref, PeripheralRef};
 pub use enums::*;
 
 use crate::gpio::{AfType, AnyPin, OutputType, Speed};
-use crate::pac::tsc::Tsc as Regs;
+use crate::interrupt;
+use crate::interrupt::typelevel::Interrupt;
 use crate::rcc::{self, RccPeripheral};
 use crate::{peripherals, Peripheral};
+use core::future::poll_fn;
+use core::task::Poll;
+use embassy_sync::waitqueue::AtomicWaker;
 
 #[cfg(tsc_v1)]
 const TSC_NUM_GROUPS: u32 = 6;
@@ -90,6 +94,18 @@ pub enum Error {
     Test,
 }
 
+/// TSC interrupt handler.
+pub struct InterruptHandler<T: Instance> {
+    _phantom: PhantomData<T>,
+}
+
+impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
+    unsafe fn on_interrupt() {
+        T::regs().ier().write(|w| w.set_eoaie(false));
+        T::waker().wake();
+    }
+}
+
 /// Pin type definition to control IO parameters
 pub enum PinType {
     /// Sensing channel pin connected to an electrode
@@ -510,6 +526,7 @@ impl<'d, T: Instance> Tsc<'d, T> {
     /// Create new TSC driver
     pub fn new(
         peri: impl Peripheral<P = T> + 'd,
+        _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
         g1: Option<PinGroup<'d, T, G1>>,
         g2: Option<PinGroup<'d, T, G2>>,
         g3: Option<PinGroup<'d, T, G3>>,
@@ -663,7 +680,7 @@ impl<'d, T: Instance> Tsc<'d, T> {
 
         rcc::enable_and_reset::<T>();
 
-        T::REGS.cr().modify(|w| {
+        T::regs().cr().modify(|w| {
             w.set_tsce(true);
             w.set_ctph(config.ct_pulse_high_length.into());
             w.set_ctpl(config.ct_pulse_low_length.into());
@@ -691,33 +708,39 @@ impl<'d, T: Instance> Tsc<'d, T> {
 
         // Set IO configuration
         // Disable Schmitt trigger hysteresis on all used TSC IOs
-        T::REGS
+        T::regs()
             .iohcr()
             .write(|w| w.0 = !(config.channel_ios | config.shield_ios | config.sampling_ios));
 
         // Set channel and shield IOs
-        T::REGS.ioccr().write(|w| w.0 = config.channel_ios | config.shield_ios);
+        T::regs()
+            .ioccr()
+            .write(|w| w.0 = config.channel_ios | config.shield_ios);
 
         // Set sampling IOs
-        T::REGS.ioscr().write(|w| w.0 = config.sampling_ios);
+        T::regs().ioscr().write(|w| w.0 = config.sampling_ios);
 
         // Set the groups to be acquired
-        T::REGS
+        T::regs()
             .iogcsr()
             .write(|w| w.0 = Self::extract_groups(config.channel_ios));
 
         // Disable interrupts
-        T::REGS.ier().modify(|w| {
+        T::regs().ier().modify(|w| {
             w.set_eoaie(false);
             w.set_mceie(false);
         });
 
         // Clear flags
-        T::REGS.icr().modify(|w| {
+        T::regs().icr().modify(|w| {
             w.set_eoaic(true);
             w.set_mceic(true);
         });
 
+        unsafe {
+            T::Interrupt::enable();
+        }
+
         Self {
             _peri: peri,
             _g1: g1,
@@ -740,24 +763,24 @@ impl<'d, T: Instance> Tsc<'d, T> {
         self.state = State::Busy;
 
         // Disable interrupts
-        T::REGS.ier().modify(|w| {
+        T::regs().ier().modify(|w| {
             w.set_eoaie(false);
             w.set_mceie(false);
         });
 
         // Clear flags
-        T::REGS.icr().modify(|w| {
+        T::regs().icr().modify(|w| {
             w.set_eoaic(true);
             w.set_mceic(true);
         });
 
         // Set the touch sensing IOs not acquired to the default mode
-        T::REGS.cr().modify(|w| {
+        T::regs().cr().modify(|w| {
             w.set_iodef(self.config.io_default_mode);
         });
 
         // Start the acquisition
-        T::REGS.cr().modify(|w| {
+        T::regs().cr().modify(|w| {
             w.set_start(true);
         });
     }
@@ -767,41 +790,41 @@ impl<'d, T: Instance> Tsc<'d, T> {
         self.state = State::Busy;
 
         // Enable interrupts
-        T::REGS.ier().modify(|w| {
+        T::regs().ier().modify(|w| {
             w.set_eoaie(true);
             w.set_mceie(self.config.max_count_interrupt);
         });
 
         // Clear flags
-        T::REGS.icr().modify(|w| {
+        T::regs().icr().modify(|w| {
             w.set_eoaic(true);
             w.set_mceic(true);
         });
 
         // Set the touch sensing IOs not acquired to the default mode
-        T::REGS.cr().modify(|w| {
+        T::regs().cr().modify(|w| {
             w.set_iodef(self.config.io_default_mode);
         });
 
         // Start the acquisition
-        T::REGS.cr().modify(|w| {
+        T::regs().cr().modify(|w| {
             w.set_start(true);
         });
     }
 
     /// Stop charge transfer acquisition
     pub fn stop(&mut self) {
-        T::REGS.cr().modify(|w| {
+        T::regs().cr().modify(|w| {
             w.set_start(false);
         });
 
         // Set the touch sensing IOs in low power mode
-        T::REGS.cr().modify(|w| {
+        T::regs().cr().modify(|w| {
             w.set_iodef(false);
         });
 
         // Clear flags
-        T::REGS.icr().modify(|w| {
+        T::regs().icr().modify(|w| {
             w.set_eoaic(true);
             w.set_mceic(true);
         });
@@ -811,23 +834,23 @@ impl<'d, T: Instance> Tsc<'d, T> {
 
     /// Stop charge transfer acquisition and clear interrupts
     pub fn stop_it(&mut self) {
-        T::REGS.cr().modify(|w| {
+        T::regs().cr().modify(|w| {
             w.set_start(false);
         });
 
         // Set the touch sensing IOs in low power mode
-        T::REGS.cr().modify(|w| {
+        T::regs().cr().modify(|w| {
             w.set_iodef(false);
         });
 
         // Disable interrupts
-        T::REGS.ier().modify(|w| {
+        T::regs().ier().modify(|w| {
             w.set_eoaie(false);
             w.set_mceie(false);
         });
 
         // Clear flags
-        T::REGS.icr().modify(|w| {
+        T::regs().icr().modify(|w| {
             w.set_eoaic(true);
             w.set_mceic(true);
         });
@@ -840,11 +863,31 @@ impl<'d, T: Instance> Tsc<'d, T> {
         while self.get_state() == State::Busy {}
     }
 
+    /// Asyncronously wait for the end of an acquisition
+    pub async fn pend_for_acquisition(&mut self) {
+        poll_fn(|cx| match self.get_state() {
+            State::Busy => {
+                T::waker().register(cx.waker());
+                T::regs().ier().write(|w| w.set_eoaie(true));
+                if self.get_state() != State::Busy {
+                    T::regs().ier().write(|w| w.set_eoaie(false));
+                    return Poll::Ready(());
+                }
+                Poll::Pending
+            }
+            _ => {
+                T::regs().ier().write(|w| w.set_eoaie(false));
+                Poll::Ready(())
+            }
+        })
+        .await;
+    }
+
     /// Get current state of acquisition
     pub fn get_state(&mut self) -> State {
         if self.state == State::Busy {
-            if T::REGS.isr().read().eoaf() {
-                if T::REGS.isr().read().mcef() {
+            if T::regs().isr().read().eoaf() {
+                if T::regs().isr().read().mcef() {
                     self.state = State::Error
                 } else {
                     self.state = State::Ready
@@ -859,16 +902,16 @@ impl<'d, T: Instance> Tsc<'d, T> {
         // Status bits are set by hardware when the acquisition on the corresponding
         // enabled analog IO group is complete, cleared when new acquisition is started
         let status = match index {
-            Group::One => T::REGS.iogcsr().read().g1s(),
-            Group::Two => T::REGS.iogcsr().read().g2s(),
-            Group::Three => T::REGS.iogcsr().read().g3s(),
-            Group::Four => T::REGS.iogcsr().read().g4s(),
-            Group::Five => T::REGS.iogcsr().read().g5s(),
-            Group::Six => T::REGS.iogcsr().read().g6s(),
+            Group::One => T::regs().iogcsr().read().g1s(),
+            Group::Two => T::regs().iogcsr().read().g2s(),
+            Group::Three => T::regs().iogcsr().read().g3s(),
+            Group::Four => T::regs().iogcsr().read().g4s(),
+            Group::Five => T::regs().iogcsr().read().g5s(),
+            Group::Six => T::regs().iogcsr().read().g6s(),
             #[cfg(any(tsc_v2, tsc_v3))]
-            Group::Seven => T::REGS.iogcsr().read().g7s(),
+            Group::Seven => T::regs().iogcsr().read().g7s(),
             #[cfg(tsc_v3)]
-            Group::Eight => T::REGS.iogcsr().read().g8s(),
+            Group::Eight => T::regs().iogcsr().read().g8s(),
         };
         match status {
             true => GroupStatus::Complete,
@@ -878,13 +921,13 @@ impl<'d, T: Instance> Tsc<'d, T> {
 
     /// Get the count for the acquisiton, valid once group status is set
     pub fn group_get_value(&mut self, index: Group) -> u16 {
-        T::REGS.iogcr(index.into()).read().cnt()
+        T::regs().iogcr(index.into()).read().cnt()
     }
 
     /// Discharge the IOs for subsequent acquisition
     pub fn discharge_io(&mut self, status: bool) {
         // Set the touch sensing IOs in low power mode
-        T::REGS.cr().modify(|w| {
+        T::regs().cr().modify(|w| {
             w.set_iodef(!status);
         });
     }
@@ -897,20 +940,32 @@ impl<'d, T: Instance> Drop for Tsc<'d, T> {
 }
 
 pub(crate) trait SealedInstance {
-    const REGS: Regs;
+    fn regs() -> crate::pac::tsc::Tsc;
+    fn waker() -> &'static AtomicWaker;
 }
 
 /// TSC instance trait
 #[allow(private_bounds)]
-pub trait Instance: Peripheral<P = Self> + SealedInstance + RccPeripheral {}
+pub trait Instance: Peripheral<P = Self> + SealedInstance + RccPeripheral {
+    /// Interrupt for this TSC instance
+    type Interrupt: interrupt::typelevel::Interrupt;
+}
 
-foreach_peripheral!(
-    (tsc, $inst:ident) => {
-        impl SealedInstance for peripherals::$inst {
-            const REGS: Regs = crate::pac::$inst;
+foreach_interrupt!(
+    ($inst:ident, tsc, TSC, GLOBAL, $irq:ident) => {
+        impl Instance for peripherals::$inst {
+            type Interrupt = crate::interrupt::typelevel::$irq;
         }
 
-        impl Instance for peripherals::$inst {}
+        impl SealedInstance for peripherals::$inst {
+            fn regs() -> crate::pac::tsc::Tsc {
+                crate::pac::$inst
+            }
+            fn waker() -> &'static AtomicWaker {
+                static WAKER: AtomicWaker = AtomicWaker::new();
+                &WAKER
+            }
+        }
     };
 );
 
diff --git a/examples/stm32u5/src/bin/tsc.rs b/examples/stm32u5/src/bin/tsc.rs
index f5593d1c4..642bbeaca 100644
--- a/examples/stm32u5/src/bin/tsc.rs
+++ b/examples/stm32u5/src/bin/tsc.rs
@@ -2,10 +2,17 @@
 #![no_main]
 
 use defmt::*;
-use embassy_stm32::tsc::{self, *};
+use embassy_stm32::{
+    bind_interrupts,
+    tsc::{self, *},
+};
 use embassy_time::Timer;
 use {defmt_rtt as _, panic_probe as _};
 
+bind_interrupts!(struct Irqs {
+    TSC => InterruptHandler<embassy_stm32::peripherals::TSC>;
+});
+
 #[cortex_m_rt::exception]
 unsafe fn HardFault(_: &cortex_m_rt::ExceptionFrame) -> ! {
     cortex_m::peripheral::SCB::sys_reset();
@@ -47,6 +54,7 @@ async fn main(_spawner: embassy_executor::Spawner) {
 
     let mut touch_controller = tsc::Tsc::new(
         context.TSC,
+        Irqs,
         Some(g1),
         Some(g2),
         None,
@@ -67,7 +75,7 @@ async fn main(_spawner: embassy_executor::Spawner) {
     let mut group_seven_val = 0;
     info!("Starting touch_controller interface");
     loop {
-        touch_controller.poll_for_acquisition();
+        touch_controller.pend_for_acquisition().await;
         touch_controller.discharge_io(true);
         Timer::after_millis(1).await;
 

From 7eb605d1165eaf4cdf90453d1ed2d6976dd514af Mon Sep 17 00:00:00 2001
From: Eekle <96976531+Eekle@users.noreply.github.com>
Date: Sun, 23 Jun 2024 16:54:10 +0200
Subject: [PATCH 2/5] fmt

---
 embassy-stm32/src/tsc/mod.rs    | 9 ++++-----
 examples/stm32u5/src/bin/tsc.rs | 6 ++----
 2 files changed, 6 insertions(+), 9 deletions(-)

diff --git a/embassy-stm32/src/tsc/mod.rs b/embassy-stm32/src/tsc/mod.rs
index 6497ff0ee..d5da2529f 100644
--- a/embassy-stm32/src/tsc/mod.rs
+++ b/embassy-stm32/src/tsc/mod.rs
@@ -65,19 +65,18 @@
 /// Enums defined for peripheral parameters
 pub mod enums;
 
+use core::future::poll_fn;
 use core::marker::PhantomData;
+use core::task::Poll;
 
 use embassy_hal_internal::{into_ref, PeripheralRef};
+use embassy_sync::waitqueue::AtomicWaker;
 pub use enums::*;
 
 use crate::gpio::{AfType, AnyPin, OutputType, Speed};
-use crate::interrupt;
 use crate::interrupt::typelevel::Interrupt;
 use crate::rcc::{self, RccPeripheral};
-use crate::{peripherals, Peripheral};
-use core::future::poll_fn;
-use core::task::Poll;
-use embassy_sync::waitqueue::AtomicWaker;
+use crate::{interrupt, peripherals, Peripheral};
 
 #[cfg(tsc_v1)]
 const TSC_NUM_GROUPS: u32 = 6;
diff --git a/examples/stm32u5/src/bin/tsc.rs b/examples/stm32u5/src/bin/tsc.rs
index 642bbeaca..db85fb158 100644
--- a/examples/stm32u5/src/bin/tsc.rs
+++ b/examples/stm32u5/src/bin/tsc.rs
@@ -2,10 +2,8 @@
 #![no_main]
 
 use defmt::*;
-use embassy_stm32::{
-    bind_interrupts,
-    tsc::{self, *},
-};
+use embassy_stm32::bind_interrupts;
+use embassy_stm32::tsc::{self, *};
 use embassy_time::Timer;
 use {defmt_rtt as _, panic_probe as _};
 

From 1d1fc9afeac268a4b6d2cd9b9e5788226c79eca8 Mon Sep 17 00:00:00 2001
From: Eekle <96976531+Eekle@users.noreply.github.com>
Date: Sun, 30 Jun 2024 11:03:29 +0200
Subject: [PATCH 3/5] Add async and blocking variants

---
 embassy-stm32/src/tsc/mod.rs | 203 +++++++++++++++++++++--------------
 1 file changed, 120 insertions(+), 83 deletions(-)

diff --git a/embassy-stm32/src/tsc/mod.rs b/embassy-stm32/src/tsc/mod.rs
index d5da2529f..cd7ae4a53 100644
--- a/embassy-stm32/src/tsc/mod.rs
+++ b/embassy-stm32/src/tsc/mod.rs
@@ -93,6 +93,23 @@ pub enum Error {
     Test,
 }
 
+/// Async acquisition API marker
+pub struct Async;
+/// Blocking acquisition API marker
+pub struct Blocking;
+
+trait SealedDriverKind {}
+
+impl SealedDriverKind for Async {}
+impl SealedDriverKind for Blocking {}
+
+#[allow(private_bounds)]
+/// Driver variant marker for the TSC peripheral
+pub trait DriverKind: SealedDriverKind {}
+
+impl DriverKind for Async {}
+impl DriverKind for Blocking {}
+
 /// TSC interrupt handler.
 pub struct InterruptHandler<T: Instance> {
     _phantom: PhantomData<T>,
@@ -505,7 +522,7 @@ pub enum G7 {}
 pub enum G8 {}
 
 /// TSC driver
-pub struct Tsc<'d, T: Instance> {
+pub struct Tsc<'d, T: Instance, K: DriverKind> {
     _peri: PeripheralRef<'d, T>,
     _g1: Option<PinGroup<'d, T, G1>>,
     _g2: Option<PinGroup<'d, T, G2>>,
@@ -519,13 +536,103 @@ pub struct Tsc<'d, T: Instance> {
     _g8: Option<PinGroup<'d, T, G8>>,
     state: State,
     config: Config,
+    _kind: PhantomData<K>,
 }
 
-impl<'d, T: Instance> Tsc<'d, T> {
-    /// Create new TSC driver
-    pub fn new(
+impl<'d, T: Instance> Tsc<'d, T, Async> {
+    /// Create a Tsc instance that can be awaited for completion
+    pub fn new_async(
         peri: impl Peripheral<P = T> + 'd,
+        g1: Option<PinGroup<'d, T, G1>>,
+        g2: Option<PinGroup<'d, T, G2>>,
+        g3: Option<PinGroup<'d, T, G3>>,
+        g4: Option<PinGroup<'d, T, G4>>,
+        g5: Option<PinGroup<'d, T, G5>>,
+        g6: Option<PinGroup<'d, T, G6>>,
+        #[cfg(any(tsc_v2, tsc_v3))] g7: Option<PinGroup<'d, T, G7>>,
+        #[cfg(tsc_v3)] g8: Option<PinGroup<'d, T, G8>>,
+        config: Config,
         _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
+    ) -> Self {
+        // Need to check valid pin configuration input
+        let g1 = g1.filter(|b| b.check_group().is_ok());
+        let g2 = g2.filter(|b| b.check_group().is_ok());
+        let g3 = g3.filter(|b| b.check_group().is_ok());
+        let g4 = g4.filter(|b| b.check_group().is_ok());
+        let g5 = g5.filter(|b| b.check_group().is_ok());
+        let g6 = g6.filter(|b| b.check_group().is_ok());
+        #[cfg(any(tsc_v2, tsc_v3))]
+        let g7 = g7.filter(|b| b.check_group().is_ok());
+        #[cfg(tsc_v3)]
+        let g8 = g8.filter(|b| b.check_group().is_ok());
+
+        match Self::check_shields(
+            &g1,
+            &g2,
+            &g3,
+            &g4,
+            &g5,
+            &g6,
+            #[cfg(any(tsc_v2, tsc_v3))]
+            &g7,
+            #[cfg(tsc_v3)]
+            &g8,
+        ) {
+            Ok(()) => Self::new_inner(
+                peri,
+                g1,
+                g2,
+                g3,
+                g4,
+                g5,
+                g6,
+                #[cfg(any(tsc_v2, tsc_v3))]
+                g7,
+                #[cfg(tsc_v3)]
+                g8,
+                config,
+            ),
+            Err(_) => Self::new_inner(
+                peri,
+                None,
+                None,
+                None,
+                None,
+                None,
+                None,
+                #[cfg(any(tsc_v2, tsc_v3))]
+                None,
+                #[cfg(tsc_v3)]
+                None,
+                config,
+            ),
+        }
+    }
+    /// Asyncronously wait for the end of an acquisition
+    pub async fn pend_for_acquisition(&mut self) {
+        poll_fn(|cx| match self.get_state() {
+            State::Busy => {
+                T::waker().register(cx.waker());
+                T::regs().ier().write(|w| w.set_eoaie(true));
+                if self.get_state() != State::Busy {
+                    T::regs().ier().write(|w| w.set_eoaie(false));
+                    return Poll::Ready(());
+                }
+                Poll::Pending
+            }
+            _ => {
+                T::regs().ier().write(|w| w.set_eoaie(false));
+                Poll::Ready(())
+            }
+        })
+        .await;
+    }
+}
+
+impl<'d, T: Instance> Tsc<'d, T, Blocking> {
+    /// Create a Tsc instance that must be polled for completion
+    pub fn new_blocking(
+        peri: impl Peripheral<P = T> + 'd,
         g1: Option<PinGroup<'d, T, G1>>,
         g2: Option<PinGroup<'d, T, G2>>,
         g3: Option<PinGroup<'d, T, G3>>,
@@ -590,7 +697,14 @@ impl<'d, T: Instance> Tsc<'d, T> {
             ),
         }
     }
+    /// Wait for end of acquisition
+    pub fn poll_for_acquisition(&mut self) {
+        while self.get_state() == State::Busy {}
+    }
+}
 
+impl<'d, T: Instance, K: DriverKind> Tsc<'d, T, K> {
+    /// Create new TSC driver
     fn check_shields(
         g1: &Option<PinGroup<'d, T, G1>>,
         g2: &Option<PinGroup<'d, T, G2>>,
@@ -754,6 +868,7 @@ impl<'d, T: Instance> Tsc<'d, T> {
             _g8: g8,
             state: State::Ready,
             config,
+            _kind: PhantomData,
         }
     }
 
@@ -784,33 +899,6 @@ impl<'d, T: Instance> Tsc<'d, T> {
         });
     }
 
-    /// Start charge transfer acquisition with interrupts enabled
-    pub fn start_it(&mut self) {
-        self.state = State::Busy;
-
-        // Enable interrupts
-        T::regs().ier().modify(|w| {
-            w.set_eoaie(true);
-            w.set_mceie(self.config.max_count_interrupt);
-        });
-
-        // Clear flags
-        T::regs().icr().modify(|w| {
-            w.set_eoaic(true);
-            w.set_mceic(true);
-        });
-
-        // Set the touch sensing IOs not acquired to the default mode
-        T::regs().cr().modify(|w| {
-            w.set_iodef(self.config.io_default_mode);
-        });
-
-        // Start the acquisition
-        T::regs().cr().modify(|w| {
-            w.set_start(true);
-        });
-    }
-
     /// Stop charge transfer acquisition
     pub fn stop(&mut self) {
         T::regs().cr().modify(|w| {
@@ -831,57 +919,6 @@ impl<'d, T: Instance> Tsc<'d, T> {
         self.state = State::Ready;
     }
 
-    /// Stop charge transfer acquisition and clear interrupts
-    pub fn stop_it(&mut self) {
-        T::regs().cr().modify(|w| {
-            w.set_start(false);
-        });
-
-        // Set the touch sensing IOs in low power mode
-        T::regs().cr().modify(|w| {
-            w.set_iodef(false);
-        });
-
-        // Disable interrupts
-        T::regs().ier().modify(|w| {
-            w.set_eoaie(false);
-            w.set_mceie(false);
-        });
-
-        // Clear flags
-        T::regs().icr().modify(|w| {
-            w.set_eoaic(true);
-            w.set_mceic(true);
-        });
-
-        self.state = State::Ready;
-    }
-
-    /// Wait for end of acquisition
-    pub fn poll_for_acquisition(&mut self) {
-        while self.get_state() == State::Busy {}
-    }
-
-    /// Asyncronously wait for the end of an acquisition
-    pub async fn pend_for_acquisition(&mut self) {
-        poll_fn(|cx| match self.get_state() {
-            State::Busy => {
-                T::waker().register(cx.waker());
-                T::regs().ier().write(|w| w.set_eoaie(true));
-                if self.get_state() != State::Busy {
-                    T::regs().ier().write(|w| w.set_eoaie(false));
-                    return Poll::Ready(());
-                }
-                Poll::Pending
-            }
-            _ => {
-                T::regs().ier().write(|w| w.set_eoaie(false));
-                Poll::Ready(())
-            }
-        })
-        .await;
-    }
-
     /// Get current state of acquisition
     pub fn get_state(&mut self) -> State {
         if self.state == State::Busy {
@@ -932,7 +969,7 @@ impl<'d, T: Instance> Tsc<'d, T> {
     }
 }
 
-impl<'d, T: Instance> Drop for Tsc<'d, T> {
+impl<'d, T: Instance, K: DriverKind> Drop for Tsc<'d, T, K> {
     fn drop(&mut self) {
         rcc::disable::<T>();
     }

From 67f5b8d974c23854676cff3a6797cf4aaf41a402 Mon Sep 17 00:00:00 2001
From: Eekle <96976531+Eekle@users.noreply.github.com>
Date: Sun, 30 Jun 2024 11:06:32 +0200
Subject: [PATCH 4/5] Update example

---
 examples/stm32u5/src/bin/tsc.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/examples/stm32u5/src/bin/tsc.rs b/examples/stm32u5/src/bin/tsc.rs
index db85fb158..eb15d275a 100644
--- a/examples/stm32u5/src/bin/tsc.rs
+++ b/examples/stm32u5/src/bin/tsc.rs
@@ -50,9 +50,8 @@ async fn main(_spawner: embassy_executor::Spawner) {
     g7.set_io2(context.PE3, PinType::Sample);
     g7.set_io3(context.PE4, PinType::Channel);
 
-    let mut touch_controller = tsc::Tsc::new(
+    let mut touch_controller = tsc::Tsc::new_async(
         context.TSC,
-        Irqs,
         Some(g1),
         Some(g2),
         None,
@@ -62,6 +61,7 @@ async fn main(_spawner: embassy_executor::Spawner) {
         Some(g7),
         None,
         config,
+        Irqs,
     );
 
     touch_controller.discharge_io(true);

From d3f8905e938eecfe7789841c6232cb34b5f43a20 Mon Sep 17 00:00:00 2001
From: Eekle <96976531+Eekle@users.noreply.github.com>
Date: Tue, 2 Jul 2024 20:46:05 +0200
Subject: [PATCH 5/5] Use crate level PeriMode

---
 embassy-stm32/src/tsc/mod.rs | 24 ++++--------------------
 1 file changed, 4 insertions(+), 20 deletions(-)

diff --git a/embassy-stm32/src/tsc/mod.rs b/embassy-stm32/src/tsc/mod.rs
index cd7ae4a53..5cb58e918 100644
--- a/embassy-stm32/src/tsc/mod.rs
+++ b/embassy-stm32/src/tsc/mod.rs
@@ -75,6 +75,7 @@ pub use enums::*;
 
 use crate::gpio::{AfType, AnyPin, OutputType, Speed};
 use crate::interrupt::typelevel::Interrupt;
+use crate::mode::{Async, Blocking, Mode as PeriMode};
 use crate::rcc::{self, RccPeripheral};
 use crate::{interrupt, peripherals, Peripheral};
 
@@ -93,23 +94,6 @@ pub enum Error {
     Test,
 }
 
-/// Async acquisition API marker
-pub struct Async;
-/// Blocking acquisition API marker
-pub struct Blocking;
-
-trait SealedDriverKind {}
-
-impl SealedDriverKind for Async {}
-impl SealedDriverKind for Blocking {}
-
-#[allow(private_bounds)]
-/// Driver variant marker for the TSC peripheral
-pub trait DriverKind: SealedDriverKind {}
-
-impl DriverKind for Async {}
-impl DriverKind for Blocking {}
-
 /// TSC interrupt handler.
 pub struct InterruptHandler<T: Instance> {
     _phantom: PhantomData<T>,
@@ -522,7 +506,7 @@ pub enum G7 {}
 pub enum G8 {}
 
 /// TSC driver
-pub struct Tsc<'d, T: Instance, K: DriverKind> {
+pub struct Tsc<'d, T: Instance, K: PeriMode> {
     _peri: PeripheralRef<'d, T>,
     _g1: Option<PinGroup<'d, T, G1>>,
     _g2: Option<PinGroup<'d, T, G2>>,
@@ -703,7 +687,7 @@ impl<'d, T: Instance> Tsc<'d, T, Blocking> {
     }
 }
 
-impl<'d, T: Instance, K: DriverKind> Tsc<'d, T, K> {
+impl<'d, T: Instance, K: PeriMode> Tsc<'d, T, K> {
     /// Create new TSC driver
     fn check_shields(
         g1: &Option<PinGroup<'d, T, G1>>,
@@ -969,7 +953,7 @@ impl<'d, T: Instance, K: DriverKind> Tsc<'d, T, K> {
     }
 }
 
-impl<'d, T: Instance, K: DriverKind> Drop for Tsc<'d, T, K> {
+impl<'d, T: Instance, K: PeriMode> Drop for Tsc<'d, T, K> {
     fn drop(&mut self) {
         rcc::disable::<T>();
     }