1use atsamd_hal_macros::{hal_cfg, hal_macro_helper};
14
15use super::super::dma_controller::ChId;
16use core::marker::PhantomData;
17use paste::paste;
18
19use crate::pac::{
20    self, Dmac, Peripherals,
21    dmac::{Busych, Intstatus, Pendch, Swtrigctrl},
22    dmac::{
23        busych::BusychSpec, intstatus::IntstatusSpec, pendch::PendchSpec,
24        swtrigctrl::SwtrigctrlSpec,
25    },
26};
27
28#[hal_cfg(any("dmac-d11", "dmac-d21"))]
29use pac::dmac as channel_regs;
30
31#[hal_cfg("dmac-d5x")]
32use pac::dmac::channel as channel_regs;
33
34use channel_regs::{
35    Chctrla, Chctrlb, Chintenclr, Chintenset, Chintflag, Chstatus, chctrla::ChctrlaSpec,
36    chctrlb::ChctrlbSpec, chintenclr::ChintenclrSpec, chintenset::ChintensetSpec,
37    chintflag::ChintflagSpec, chstatus::ChstatusSpec,
38};
39
40#[hal_cfg("dmac-d5x")]
41use pac::dmac::channel::{Chprilvl, chprilvl::ChprilvlSpec};
42
43pub(super) trait Register<Id: ChId> {
48    fn dmac(&self) -> &Dmac;
50
51    #[hal_cfg(any("dmac-d11", "dmac-d21"))]
58    #[inline]
59    fn with_chid<F: FnOnce(&Dmac) -> R, R>(&mut self, fun: F) -> R {
60        let dmac = self.dmac();
69
70        let mut old_id = 0;
71
72        dmac.chid().modify(|r, w| {
73            old_id = r.id().bits();
75            unsafe { w.id().bits(Id::U8) }
77        });
78
79        let ret = fun(dmac);
81        unsafe { dmac.chid().write(|w| w.id().bits(old_id)) };
85
86        ret
87    }
88
89    #[hal_cfg("dmac-d5x")]
94    #[inline]
95    fn with_chid<F: FnOnce(&pac::dmac::Channel) -> R, R>(&mut self, fun: F) -> R {
96        let ch = &self.dmac().channel(Id::USIZE);
104        fun(ch)
105    }
106}
107
108macro_rules! reg_proxy {
109    (@new $reg:ident) => {
110        paste! {
111            pub(super) struct [< $reg:camel Proxy >]<Id: ChId, REG> {
113                #[allow(unused)]
114                dmac: Dmac,
115                _id: PhantomData<Id>,
116                _reg: PhantomData<REG>,
117            }
118
119            impl<Id: ChId> [< $reg:camel Proxy >]<Id, [< $reg:camel >]> {
120                #[inline]
122                pub fn new() -> Self {
123                    Self {
124                        dmac: unsafe { Peripherals::steal().dmac },
128                        _id: PhantomData,
129                        _reg: PhantomData,
130                    }
131                }
132            }
133        }
134    };
135
136    (@read_reg $reg:ident) => {
138        paste! {
139            impl<Id: ChId> Register<Id> for [< $reg:camel Proxy >]<Id, [< $reg:camel >]> {
140                fn dmac(&self) -> &Dmac {
141                    &self.dmac
142                }
143            }
144
145            impl<Id> [< $reg:camel Proxy >]<Id, [< $reg:camel >]> where Id: ChId, [< $reg:camel Spec>]: pac::generic::Readable {
146                #[inline]
147                #[allow(dead_code)]
148                pub fn read(&mut self) -> channel_regs::[< $reg:lower >]::R {
149                    self.with_chid(|d| d.[< $reg:lower >]().read())
150                }
151            }
152        }
153    };
154
155    ($reg:ident, register, r) => {
157        paste! {
158
159            reg_proxy!(@new $reg);
160            reg_proxy!(@read_reg $reg);
161        }
162    };
163
164    ($reg:ident, register, rw) => {
166        paste! {
167            reg_proxy!(@new $reg);
168            reg_proxy!(@read_reg $reg);
169
170            impl<Id> [< $reg:camel Proxy >]<Id, [< $reg:camel >]> where Id: ChId, [< $reg:camel Spec >]: pac::generic::Writable {
171                #[inline]
172                #[allow(dead_code)]
173                pub fn write<F>(&mut self, func: F)
174                where
175                    for<'w> F: FnOnce(&'w mut channel_regs::[< $reg:lower >]::W) -> &'w mut channel_regs::[< $reg:lower >]::W,
176                {
177                    self.with_chid(|d| d.[< $reg:lower >]().write(|w| func(w)));
178                }
179            }
180
181            impl<Id>[< $reg:camel Proxy >]<Id, [< $reg:camel >]> where
182                Id: ChId,
183                [< $reg:camel Spec >]: pac::generic::Writable + pac::generic::Readable
184            {
185                #[inline]
186                #[allow(dead_code)]
187                pub fn modify<F>(&mut self, func: F)
188                where
189                    for<'w> F: FnOnce(
190                        &channel_regs::[< $reg:lower >]::R,
191                        &'w mut channel_regs::[< $reg:lower >]::W
192                    ) -> &'w mut channel_regs::[< $reg:lower >]::W,
193                {
194                    self.with_chid(|d| d.[< $reg:lower >]().modify(|r, w| func(r, w)));
195                }
196            }
197        }
198    };
199
200    (@read_bit $reg:ident) => {
202        paste! {
203            impl<Id: ChId> Register<Id> for [< $reg:camel Proxy >]<Id, [< $reg:camel >]> {
204                fn dmac(&self) -> &Dmac {
205                    &self.dmac
206                }
207            }
208
209            impl<Id> [< $reg:camel Proxy >]<Id, [< $reg:camel >]> where Id: ChId, [< $reg:camel Spec >]: pac::generic::Readable {
210                #[inline]
211                #[allow(dead_code)]
212                pub fn read_bit(&self) -> bool {
213                    self.dmac.[< $reg:lower >]().read().bits() & (1 << Id::U8) != 0
214                }
215            }
216        }
217    };
218
219    ($reg:ident, bit, r) => {
221        paste! {
222            reg_proxy!(@new $reg);
223            reg_proxy!(@read_bit $reg);
224        }
225    };
226
227    ($reg:ident, bit, rw) => {
229        paste! {
230            reg_proxy!(@new $reg);
231            reg_proxy!(@read_bit $reg);
232
233            impl<Id> [< $reg:camel Proxy >]<Id, [< $reg:camel >]> where
234                Id: ChId,
235                [< $reg:camel Spec >]: pac::generic::Readable + pac::generic::Writable
236            {
237                #[inline]
238                #[allow(dead_code)]
239                pub fn set_bit(&mut self) {
240                    unsafe {
243                        self.dmac.[< $reg:lower >]().modify(|r, w| w.bits(r.bits() | (1 << Id::U8)));
244                    }
245                }
246
247                #[inline]
248                #[allow(dead_code)]
249                pub fn clear_bit(&mut self) {
250                    unsafe {
253                        self.dmac.[< $reg:lower >]().modify(|r, w| w.bits(r.bits() & !(1 << Id::U8)));
254                    }
255                }
256            }
257        }
258    };
259}
260
261reg_proxy!(chctrla, register, rw);
262reg_proxy!(chctrlb, register, rw);
263reg_proxy!(chintenclr, register, rw);
264reg_proxy!(chintenset, register, rw);
265reg_proxy!(chintflag, register, rw);
266reg_proxy!(chstatus, register, r);
267#[hal_cfg("dmac-d5x")]
268reg_proxy!(chprilvl, register, rw);
269
270reg_proxy!(intstatus, bit, r);
271reg_proxy!(busych, bit, r);
272reg_proxy!(pendch, bit, r);
273reg_proxy!(swtrigctrl, bit, rw);
274
275#[allow(dead_code)]
282#[hal_macro_helper]
283pub(super) struct RegisterBlock<Id: ChId> {
284    pub chctrla: ChctrlaProxy<Id, Chctrla>,
285    pub chctrlb: ChctrlbProxy<Id, Chctrlb>,
286    pub chintenclr: ChintenclrProxy<Id, Chintenclr>,
287    pub chintenset: ChintensetProxy<Id, Chintenset>,
288    pub chintflag: ChintflagProxy<Id, Chintflag>,
289    pub chstatus: ChstatusProxy<Id, Chstatus>,
290    pub intstatus: IntstatusProxy<Id, Intstatus>,
291    pub busych: BusychProxy<Id, Busych>,
292    pub pendch: PendchProxy<Id, Pendch>,
293    pub swtrigctrl: SwtrigctrlProxy<Id, Swtrigctrl>,
294    #[hal_cfg("dmac-d5x")]
295    pub chprilvl: ChprilvlProxy<Id, Chprilvl>,
296}
297
298impl<Id: ChId> RegisterBlock<Id> {
299    #[hal_macro_helper]
300    pub(super) fn new(_id: PhantomData<Id>) -> Self {
301        Self {
302            chctrla: ChctrlaProxy::new(),
303            chctrlb: ChctrlbProxy::new(),
304            chintenclr: ChintenclrProxy::new(),
305            chintenset: ChintensetProxy::new(),
306            chintflag: ChintflagProxy::new(),
307            chstatus: ChstatusProxy::new(),
308            intstatus: IntstatusProxy::new(),
309            busych: BusychProxy::new(),
310            pendch: PendchProxy::new(),
311            swtrigctrl: SwtrigctrlProxy::new(),
312            #[hal_cfg("dmac-d5x")]
313            chprilvl: ChprilvlProxy::new(),
314        }
315    }
316}
317
318impl<Id: ChId> Drop for RegisterBlock<Id> {
319    fn drop(&mut self) {
320        self.chctrla.modify(|_, w| w.enable().clear_bit());
322
323        while self.chctrla.read().enable().bit_is_set() {
324            core::hint::spin_loop();
325        }
326
327        core::sync::atomic::fence(core::sync::atomic::Ordering::Acquire); }
332}