From a32e82029a8b6944ef3e9861b09095bae01b37a3 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis <dirbaio@dirbaio.net>
Date: Sun, 5 Mar 2023 22:00:52 +0100
Subject: [PATCH] nrf/spim: switch to new interrupt binding.

---
 embassy-nrf/src/spim.rs                      | 59 +++++++++++---------
 examples/nrf52840/src/bin/lora_p2p_report.rs |  9 ++-
 examples/nrf52840/src/bin/lora_p2p_sense.rs  |  9 ++-
 examples/nrf52840/src/bin/spim.rs            |  9 ++-
 4 files changed, 50 insertions(+), 36 deletions(-)

diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs
index 17e435787..89cbdfee9 100644
--- a/embassy-nrf/src/spim.rs
+++ b/embassy-nrf/src/spim.rs
@@ -3,6 +3,7 @@
 #![macro_use]
 
 use core::future::poll_fn;
+use core::marker::PhantomData;
 use core::sync::atomic::{compiler_fence, Ordering};
 use core::task::Poll;
 
@@ -14,7 +15,7 @@ pub use pac::spim0::frequency::FREQUENCY_A as Frequency;
 use crate::chip::FORCE_COPY_BUFFER_SIZE;
 use crate::gpio::sealed::Pin as _;
 use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits};
-use crate::interrupt::{Interrupt, InterruptExt};
+use crate::interrupt::{self, Interrupt, InterruptExt};
 use crate::util::{slice_in_ram_or, slice_ptr_parts, slice_ptr_parts_mut};
 use crate::{pac, Peripheral};
 
@@ -31,11 +32,6 @@ pub enum Error {
     BufferNotInRAM,
 }
 
-/// SPIM driver.
-pub struct Spim<'d, T: Instance> {
-    _p: PeripheralRef<'d, T>,
-}
-
 /// SPIM configuration.
 #[non_exhaustive]
 pub struct Config {
@@ -62,11 +58,33 @@ impl Default for Config {
     }
 }
 
+/// Interrupt handler.
+pub struct InterruptHandler<T: Instance> {
+    _phantom: PhantomData<T>,
+}
+
+impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
+    unsafe fn on_interrupt() {
+        let r = T::regs();
+        let s = T::state();
+
+        if r.events_end.read().bits() != 0 {
+            s.end_waker.wake();
+            r.intenclr.write(|w| w.end().clear());
+        }
+    }
+}
+
+/// SPIM driver.
+pub struct Spim<'d, T: Instance> {
+    _p: PeripheralRef<'d, T>,
+}
+
 impl<'d, T: Instance> Spim<'d, T> {
     /// Create a new SPIM driver.
     pub fn new(
         spim: impl Peripheral<P = T> + 'd,
-        irq: impl Peripheral<P = T::Interrupt> + 'd,
+        _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
         sck: impl Peripheral<P = impl GpioPin> + 'd,
         miso: impl Peripheral<P = impl GpioPin> + 'd,
         mosi: impl Peripheral<P = impl GpioPin> + 'd,
@@ -75,7 +93,6 @@ impl<'d, T: Instance> Spim<'d, T> {
         into_ref!(sck, miso, mosi);
         Self::new_inner(
             spim,
-            irq,
             sck.map_into(),
             Some(miso.map_into()),
             Some(mosi.map_into()),
@@ -86,36 +103,35 @@ impl<'d, T: Instance> Spim<'d, T> {
     /// Create a new SPIM driver, capable of TX only (MOSI only).
     pub fn new_txonly(
         spim: impl Peripheral<P = T> + 'd,
-        irq: impl Peripheral<P = T::Interrupt> + 'd,
+        _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
         sck: impl Peripheral<P = impl GpioPin> + 'd,
         mosi: impl Peripheral<P = impl GpioPin> + 'd,
         config: Config,
     ) -> Self {
         into_ref!(sck, mosi);
-        Self::new_inner(spim, irq, sck.map_into(), None, Some(mosi.map_into()), config)
+        Self::new_inner(spim, sck.map_into(), None, Some(mosi.map_into()), config)
     }
 
     /// Create a new SPIM driver, capable of RX only (MISO only).
     pub fn new_rxonly(
         spim: impl Peripheral<P = T> + 'd,
-        irq: impl Peripheral<P = T::Interrupt> + 'd,
+        _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
         sck: impl Peripheral<P = impl GpioPin> + 'd,
         miso: impl Peripheral<P = impl GpioPin> + 'd,
         config: Config,
     ) -> Self {
         into_ref!(sck, miso);
-        Self::new_inner(spim, irq, sck.map_into(), Some(miso.map_into()), None, config)
+        Self::new_inner(spim, sck.map_into(), Some(miso.map_into()), None, config)
     }
 
     fn new_inner(
         spim: impl Peripheral<P = T> + 'd,
-        irq: impl Peripheral<P = T::Interrupt> + 'd,
         sck: PeripheralRef<'d, AnyPin>,
         miso: Option<PeripheralRef<'d, AnyPin>>,
         mosi: Option<PeripheralRef<'d, AnyPin>>,
         config: Config,
     ) -> Self {
-        into_ref!(spim, irq);
+        into_ref!(spim);
 
         let r = T::regs();
 
@@ -191,23 +207,12 @@ impl<'d, T: Instance> Spim<'d, T> {
         // Disable all events interrupts
         r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
 
-        irq.set_handler(Self::on_interrupt);
-        irq.unpend();
-        irq.enable();
+        unsafe { T::Interrupt::steal() }.unpend();
+        unsafe { T::Interrupt::steal() }.enable();
 
         Self { _p: spim }
     }
 
-    fn on_interrupt(_: *mut ()) {
-        let r = T::regs();
-        let s = T::state();
-
-        if r.events_end.read().bits() != 0 {
-            s.end_waker.wake();
-            r.intenclr.write(|w| w.end().clear());
-        }
-    }
-
     fn prepare(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> {
         slice_in_ram_or(tx, Error::BufferNotInRAM)?;
         // NOTE: RAM slice check for rx is not necessary, as a mutable
diff --git a/examples/nrf52840/src/bin/lora_p2p_report.rs b/examples/nrf52840/src/bin/lora_p2p_report.rs
index d512b83f6..e24f0db03 100644
--- a/examples/nrf52840/src/bin/lora_p2p_report.rs
+++ b/examples/nrf52840/src/bin/lora_p2p_report.rs
@@ -11,11 +11,15 @@ use defmt::*;
 use embassy_executor::Spawner;
 use embassy_lora::sx126x::*;
 use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pin as _, Pull};
-use embassy_nrf::{interrupt, spim};
+use embassy_nrf::{bind_interrupts, peripherals, spim};
 use embassy_time::{Duration, Timer};
 use lorawan_device::async_device::radio::{Bandwidth, CodingRate, PhyRxTx, RfConfig, SpreadingFactor};
 use {defmt_rtt as _, panic_probe as _};
 
+bind_interrupts!(struct Irqs {
+    SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1 => spim::InterruptHandler<peripherals::TWISPI1>;
+});
+
 #[embassy_executor::main]
 async fn main(_spawner: Spawner) {
     let p = embassy_nrf::init(Default::default());
@@ -23,8 +27,7 @@ async fn main(_spawner: Spawner) {
     spi_config.frequency = spim::Frequency::M16;
 
     let mut radio = {
-        let irq = interrupt::take!(SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
-        let spim = spim::Spim::new(p.TWISPI1, irq, p.P1_11, p.P1_13, p.P1_12, spi_config);
+        let spim = spim::Spim::new(p.TWISPI1, Irqs, p.P1_11, p.P1_13, p.P1_12, spi_config);
 
         let cs = Output::new(p.P1_10.degrade(), Level::High, OutputDrive::Standard);
         let reset = Output::new(p.P1_06.degrade(), Level::High, OutputDrive::Standard);
diff --git a/examples/nrf52840/src/bin/lora_p2p_sense.rs b/examples/nrf52840/src/bin/lora_p2p_sense.rs
index b9768874b..b6f41ffcc 100644
--- a/examples/nrf52840/src/bin/lora_p2p_sense.rs
+++ b/examples/nrf52840/src/bin/lora_p2p_sense.rs
@@ -12,13 +12,17 @@ use defmt::*;
 use embassy_executor::Spawner;
 use embassy_lora::sx126x::*;
 use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pin as _, Pull};
-use embassy_nrf::{interrupt, spim};
+use embassy_nrf::{bind_interrupts, peripherals, spim};
 use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
 use embassy_sync::pubsub::{PubSubChannel, Publisher};
 use embassy_time::{Duration, Timer};
 use lorawan_device::async_device::radio::{Bandwidth, CodingRate, PhyRxTx, RfConfig, SpreadingFactor, TxConfig};
 use {defmt_rtt as _, panic_probe as _, panic_probe as _};
 
+bind_interrupts!(struct Irqs {
+    SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1 => spim::InterruptHandler<peripherals::TWISPI1>;
+});
+
 // Message bus: queue of 2, 1 subscriber (Lora P2P), 2 publishers (temperature, motion detection)
 static MESSAGE_BUS: PubSubChannel<CriticalSectionRawMutex, Message, 2, 1, 2> = PubSubChannel::new();
 
@@ -58,8 +62,7 @@ async fn main(spawner: Spawner) {
     spi_config.frequency = spim::Frequency::M16;
 
     let mut radio = {
-        let irq = interrupt::take!(SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
-        let spim = spim::Spim::new(p.TWISPI1, irq, p.P1_11, p.P1_13, p.P1_12, spi_config);
+        let spim = spim::Spim::new(p.TWISPI1, Irqs, p.P1_11, p.P1_13, p.P1_12, spi_config);
 
         let cs = Output::new(p.P1_10.degrade(), Level::High, OutputDrive::Standard);
         let reset = Output::new(p.P1_06.degrade(), Level::High, OutputDrive::Standard);
diff --git a/examples/nrf52840/src/bin/spim.rs b/examples/nrf52840/src/bin/spim.rs
index 132e01660..9d1843a8f 100644
--- a/examples/nrf52840/src/bin/spim.rs
+++ b/examples/nrf52840/src/bin/spim.rs
@@ -5,9 +5,13 @@
 use defmt::{info, unwrap};
 use embassy_executor::Spawner;
 use embassy_nrf::gpio::{Level, Output, OutputDrive};
-use embassy_nrf::{interrupt, spim};
+use embassy_nrf::{bind_interrupts, peripherals, spim};
 use {defmt_rtt as _, panic_probe as _};
 
+bind_interrupts!(struct Irqs {
+    SPIM3 => spim::InterruptHandler<peripherals::SPI3>;
+});
+
 #[embassy_executor::main]
 async fn main(_spawner: Spawner) {
     let p = embassy_nrf::init(Default::default());
@@ -16,8 +20,7 @@ async fn main(_spawner: Spawner) {
     let mut config = spim::Config::default();
     config.frequency = spim::Frequency::M16;
 
-    let irq = interrupt::take!(SPIM3);
-    let mut spim = spim::Spim::new(p.SPI3, irq, p.P0_29, p.P0_28, p.P0_30, config);
+    let mut spim = spim::Spim::new(p.SPI3, Irqs, p.P0_29, p.P0_28, p.P0_30, config);
 
     let mut ncs = Output::new(p.P0_31, Level::High, OutputDrive::Standard);