1use enumset::EnumSet;
2use portable_atomic::{AtomicBool, Ordering};
3
4use crate::{
5 RegisterToggle,
6 asynch::AtomicWaker,
7 dma::{
8 BurstConfig,
9 DmaChannel,
10 DmaPeripheral,
11 DmaRxChannel,
12 DmaRxInterrupt,
13 DmaTxChannel,
14 DmaTxInterrupt,
15 InterruptAccess,
16 PdmaChannel,
17 RegisterAccess,
18 RxRegisterAccess,
19 TxRegisterAccess,
20 },
21 interrupt::InterruptHandler,
22 peripherals::Interrupt,
23 system::Peripheral,
24};
25
26pub(super) type I2sRegisterBlock = crate::pac::i2s0::RegisterBlock;
27
28#[derive(Debug)]
30#[cfg_attr(feature = "defmt", derive(defmt::Format))]
31pub struct AnyI2sDmaRxChannel<'d>(pub(crate) AnyI2sDmaChannel<'d>);
32
33impl AnyI2sDmaRxChannel<'_> {
34 fn regs(&self) -> &I2sRegisterBlock {
35 self.0.register_block()
36 }
37}
38
39impl crate::private::Sealed for AnyI2sDmaRxChannel<'_> {}
40impl DmaRxChannel for AnyI2sDmaRxChannel<'_> {}
41
42#[derive(Debug)]
44#[cfg_attr(feature = "defmt", derive(defmt::Format))]
45pub struct AnyI2sDmaTxChannel<'d>(pub(crate) AnyI2sDmaChannel<'d>);
46
47impl AnyI2sDmaTxChannel<'_> {
48 fn regs(&self) -> &I2sRegisterBlock {
49 self.0.register_block()
50 }
51}
52
53impl crate::private::Sealed for AnyI2sDmaTxChannel<'_> {}
54impl DmaTxChannel for AnyI2sDmaTxChannel<'_> {}
55
56impl RegisterAccess for AnyI2sDmaTxChannel<'_> {
57 fn peripheral_clock(&self) -> Option<Peripheral> {
58 None
59 }
60
61 fn reset(&self) {
62 self.regs().lc_conf().toggle(|w, bit| w.out_rst().bit(bit));
63 }
64
65 fn set_burst_mode(&self, burst_mode: BurstConfig) {
66 self.regs()
67 .lc_conf()
68 .modify(|_, w| w.out_data_burst_en().bit(burst_mode.is_burst_enabled()));
69 }
70
71 fn set_descr_burst_mode(&self, burst_mode: bool) {
72 self.regs()
73 .lc_conf()
74 .modify(|_, w| w.outdscr_burst_en().bit(burst_mode));
75 }
76
77 fn set_link_addr(&self, address: u32) {
78 self.regs()
79 .out_link()
80 .modify(|_, w| unsafe { w.outlink_addr().bits(address) });
81 }
82
83 fn set_peripheral(&self, _peripheral: u8) {
84 }
86
87 fn start(&self) {
88 self.regs()
89 .out_link()
90 .modify(|_, w| w.outlink_start().set_bit());
91 }
92
93 fn stop(&self) {
94 self.regs()
95 .out_link()
96 .modify(|_, w| w.outlink_stop().set_bit());
97 }
98
99 fn restart(&self) {
100 self.regs()
101 .out_link()
102 .modify(|_, w| w.outlink_restart().set_bit());
103 }
104
105 fn set_check_owner(&self, check_owner: Option<bool>) {
106 self.regs()
107 .lc_conf()
108 .modify(|_, w| w.check_owner().bit(check_owner.unwrap_or(true)));
109 }
110
111 fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool {
112 self.0.is_compatible_with(peripheral)
113 }
114
115 #[cfg(dma_ext_mem_configurable_block_size)]
116 fn set_ext_mem_block_size(&self, size: crate::dma::DmaExtMemBKSize) {
117 self.regs()
118 .lc_conf()
119 .modify(|_, w| unsafe { w.ext_mem_bk_size().bits(size as u8) });
120 }
121
122 #[cfg(dma_can_access_psram)]
123 fn can_access_psram(&self) -> bool {
124 matches!(self.0, AnyI2sDmaChannel(any::Inner::I2s0(_)))
125 }
126}
127
128impl TxRegisterAccess for AnyI2sDmaTxChannel<'_> {
129 fn is_fifo_empty(&self) -> bool {
130 cfg_if::cfg_if! {
131 if #[cfg(esp32)] {
132 self.regs().lc_state0().read().bits() & 0x80000000 != 0
133 } else {
134 self.regs().lc_state0().read().out_empty().bit_is_set()
135 }
136 }
137 }
138
139 fn set_auto_write_back(&self, enable: bool) {
140 self.regs()
141 .lc_conf()
142 .modify(|_, w| w.out_auto_wrback().bit(enable));
143 }
144
145 fn last_dscr_address(&self) -> usize {
146 self.regs()
147 .out_eof_des_addr()
148 .read()
149 .out_eof_des_addr()
150 .bits() as usize
151 }
152
153 fn peripheral_interrupt(&self) -> Option<Interrupt> {
154 Some(self.0.peripheral_interrupt())
155 }
156
157 fn async_handler(&self) -> Option<InterruptHandler> {
158 Some(self.0.async_handler())
159 }
160}
161
162impl InterruptAccess<DmaTxInterrupt> for AnyI2sDmaTxChannel<'_> {
163 fn enable_listen(&self, interrupts: EnumSet<DmaTxInterrupt>, enable: bool) {
164 self.regs().int_ena().modify(|_, w| {
165 for interrupt in interrupts {
166 match interrupt {
167 DmaTxInterrupt::TotalEof => w.out_total_eof().bit(enable),
168 DmaTxInterrupt::DescriptorError => w.out_dscr_err().bit(enable),
169 DmaTxInterrupt::Eof => w.out_eof().bit(enable),
170 DmaTxInterrupt::Done => w.out_done().bit(enable),
171 };
172 }
173 w
174 });
175 }
176
177 fn is_listening(&self) -> EnumSet<DmaTxInterrupt> {
178 let mut result = EnumSet::new();
179
180 let int_ena = self.regs().int_ena().read();
181 if int_ena.out_total_eof().bit_is_set() {
182 result |= DmaTxInterrupt::TotalEof;
183 }
184 if int_ena.out_dscr_err().bit_is_set() {
185 result |= DmaTxInterrupt::DescriptorError;
186 }
187 if int_ena.out_eof().bit_is_set() {
188 result |= DmaTxInterrupt::Eof;
189 }
190 if int_ena.out_done().bit_is_set() {
191 result |= DmaTxInterrupt::Done;
192 }
193
194 result
195 }
196
197 fn pending_interrupts(&self) -> EnumSet<DmaTxInterrupt> {
198 let mut result = EnumSet::new();
199
200 let int_raw = self.regs().int_raw().read();
201 if int_raw.out_total_eof().bit_is_set() {
202 result |= DmaTxInterrupt::TotalEof;
203 }
204 if int_raw.out_dscr_err().bit_is_set() {
205 result |= DmaTxInterrupt::DescriptorError;
206 }
207 if int_raw.out_eof().bit_is_set() {
208 result |= DmaTxInterrupt::Eof;
209 }
210 if int_raw.out_done().bit_is_set() {
211 result |= DmaTxInterrupt::Done;
212 }
213
214 result
215 }
216
217 fn clear(&self, interrupts: impl Into<EnumSet<DmaTxInterrupt>>) {
218 self.regs().int_clr().write(|w| {
219 for interrupt in interrupts.into() {
220 match interrupt {
221 DmaTxInterrupt::TotalEof => w.out_total_eof().clear_bit_by_one(),
222 DmaTxInterrupt::DescriptorError => w.out_dscr_err().clear_bit_by_one(),
223 DmaTxInterrupt::Eof => w.out_eof().clear_bit_by_one(),
224 DmaTxInterrupt::Done => w.out_done().clear_bit_by_one(),
225 };
226 }
227 w
228 });
229 }
230
231 fn waker(&self) -> &'static AtomicWaker {
232 self.0.tx_waker()
233 }
234
235 fn is_async(&self) -> bool {
236 self.0.tx_async_flag().load(Ordering::Relaxed)
237 }
238
239 fn set_async(&self, _is_async: bool) {
240 self.0.tx_async_flag().store(_is_async, Ordering::Relaxed);
241 }
242}
243
244impl RegisterAccess for AnyI2sDmaRxChannel<'_> {
245 fn peripheral_clock(&self) -> Option<Peripheral> {
246 None
247 }
248
249 fn reset(&self) {
250 self.regs().lc_conf().toggle(|w, bit| w.in_rst().bit(bit));
251 }
252
253 fn set_burst_mode(&self, _burst_mode: BurstConfig) {}
254
255 fn set_descr_burst_mode(&self, burst_mode: bool) {
256 self.regs()
257 .lc_conf()
258 .modify(|_, w| w.indscr_burst_en().bit(burst_mode));
259 }
260
261 fn set_link_addr(&self, address: u32) {
262 self.regs()
263 .in_link()
264 .modify(|_, w| unsafe { w.inlink_addr().bits(address) });
265 }
266
267 fn set_peripheral(&self, _peripheral: u8) {
268 }
270
271 fn start(&self) {
272 self.regs()
273 .in_link()
274 .modify(|_, w| w.inlink_start().set_bit());
275 }
276
277 fn stop(&self) {
278 self.regs()
279 .in_link()
280 .modify(|_, w| w.inlink_stop().set_bit());
281 }
282
283 fn restart(&self) {
284 self.regs()
285 .in_link()
286 .modify(|_, w| w.inlink_restart().set_bit());
287 }
288
289 fn set_check_owner(&self, check_owner: Option<bool>) {
290 self.regs()
291 .lc_conf()
292 .modify(|_, w| w.check_owner().bit(check_owner.unwrap_or(true)));
293 }
294
295 fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool {
296 self.0.is_compatible_with(peripheral)
297 }
298
299 #[cfg(dma_ext_mem_configurable_block_size)]
300 fn set_ext_mem_block_size(&self, size: crate::dma::DmaExtMemBKSize) {
301 self.regs()
302 .lc_conf()
303 .modify(|_, w| unsafe { w.ext_mem_bk_size().bits(size as u8) });
304 }
305
306 #[cfg(dma_can_access_psram)]
307 fn can_access_psram(&self) -> bool {
308 matches!(self.0, AnyI2sDmaChannel(any::Inner::I2s0(_)))
309 }
310}
311
312impl RxRegisterAccess for AnyI2sDmaRxChannel<'_> {
313 fn peripheral_interrupt(&self) -> Option<Interrupt> {
314 Some(self.0.peripheral_interrupt())
315 }
316
317 fn async_handler(&self) -> Option<InterruptHandler> {
318 Some(self.0.async_handler())
319 }
320}
321
322impl InterruptAccess<DmaRxInterrupt> for AnyI2sDmaRxChannel<'_> {
323 fn enable_listen(&self, interrupts: EnumSet<DmaRxInterrupt>, enable: bool) {
324 self.regs().int_ena().modify(|_, w| {
325 for interrupt in interrupts {
326 match interrupt {
327 DmaRxInterrupt::SuccessfulEof => w.in_suc_eof().bit(enable),
328 DmaRxInterrupt::ErrorEof => w.in_err_eof().bit(enable),
329 DmaRxInterrupt::DescriptorError => w.in_dscr_err().bit(enable),
330 DmaRxInterrupt::DescriptorEmpty => w.in_dscr_empty().bit(enable),
331 DmaRxInterrupt::Done => w.in_done().bit(enable),
332 };
333 }
334 w
335 });
336 }
337
338 fn is_listening(&self) -> EnumSet<DmaRxInterrupt> {
339 let mut result = EnumSet::new();
340
341 let int_ena = self.regs().int_ena().read();
342 if int_ena.in_dscr_err().bit_is_set() {
343 result |= DmaRxInterrupt::DescriptorError;
344 }
345 if int_ena.in_dscr_empty().bit_is_set() {
346 result |= DmaRxInterrupt::DescriptorEmpty;
347 }
348 if int_ena.in_suc_eof().bit_is_set() {
349 result |= DmaRxInterrupt::SuccessfulEof;
350 }
351 if int_ena.in_err_eof().bit_is_set() {
352 result |= DmaRxInterrupt::ErrorEof;
353 }
354 if int_ena.in_done().bit_is_set() {
355 result |= DmaRxInterrupt::Done;
356 }
357
358 result
359 }
360
361 fn pending_interrupts(&self) -> EnumSet<DmaRxInterrupt> {
362 let mut result = EnumSet::new();
363
364 let int_raw = self.regs().int_raw().read();
365 if int_raw.in_dscr_err().bit_is_set() {
366 result |= DmaRxInterrupt::DescriptorError;
367 }
368 if int_raw.in_dscr_empty().bit_is_set() {
369 result |= DmaRxInterrupt::DescriptorEmpty;
370 }
371 if int_raw.in_suc_eof().bit_is_set() {
372 result |= DmaRxInterrupt::SuccessfulEof;
373 }
374 if int_raw.in_err_eof().bit_is_set() {
375 result |= DmaRxInterrupt::ErrorEof;
376 }
377 if int_raw.in_done().bit_is_set() {
378 result |= DmaRxInterrupt::Done;
379 }
380
381 result
382 }
383
384 fn clear(&self, interrupts: impl Into<EnumSet<DmaRxInterrupt>>) {
385 self.regs().int_clr().write(|w| {
386 for interrupt in interrupts.into() {
387 match interrupt {
388 DmaRxInterrupt::SuccessfulEof => w.in_suc_eof().clear_bit_by_one(),
389 DmaRxInterrupt::ErrorEof => w.in_err_eof().clear_bit_by_one(),
390 DmaRxInterrupt::DescriptorError => w.in_dscr_err().clear_bit_by_one(),
391 DmaRxInterrupt::DescriptorEmpty => w.in_dscr_empty().clear_bit_by_one(),
392 DmaRxInterrupt::Done => w.in_done().clear_bit_by_one(),
393 };
394 }
395 w
396 });
397 }
398
399 fn waker(&self) -> &'static AtomicWaker {
400 self.0.rx_waker()
401 }
402
403 fn is_async(&self) -> bool {
404 self.0.rx_async_flag().load(Ordering::Relaxed)
405 }
406
407 fn set_async(&self, _is_async: bool) {
408 self.0.rx_async_flag().store(_is_async, Ordering::Relaxed);
409 }
410}
411
412crate::any_peripheral! {
413 pub peripheral AnyI2sDmaChannel<'d> {
415 #[cfg(soc_has_i2s0)]
416 I2s0(crate::peripherals::DMA_I2S0<'d>),
417 #[cfg(soc_has_i2s1)]
418 I2s1(crate::peripherals::DMA_I2S1<'d>),
419 }
420}
421
422impl<'d> DmaChannel for AnyI2sDmaChannel<'d> {
423 type Rx = AnyI2sDmaRxChannel<'d>;
424 type Tx = AnyI2sDmaTxChannel<'d>;
425
426 unsafe fn split_internal(self, _: crate::private::Internal) -> (Self::Rx, Self::Tx) {
427 (
428 AnyI2sDmaRxChannel(unsafe { self.clone_unchecked() }),
429 AnyI2sDmaTxChannel(unsafe { self.clone_unchecked() }),
430 )
431 }
432}
433
434impl PdmaChannel for AnyI2sDmaChannel<'_> {
435 type RegisterBlock = I2sRegisterBlock;
436
437 delegate::delegate! {
438 to match &self.0 {
439 #[cfg(soc_has_i2s0)]
440 any::Inner::I2s0(channel) => channel,
441 #[cfg(soc_has_i2s1)]
442 any::Inner::I2s1(channel) => channel,
443 } {
444 fn register_block(&self) -> &I2sRegisterBlock;
445 fn tx_waker(&self) -> &'static AtomicWaker;
446 fn rx_waker(&self) -> &'static AtomicWaker;
447 fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool;
448 fn peripheral_interrupt(&self) -> Interrupt;
449 fn async_handler(&self) -> InterruptHandler;
450 fn rx_async_flag(&self) -> &'static AtomicBool;
451 fn tx_async_flag(&self) -> &'static AtomicBool;
452 }
453 }
454}