1
#[cfg(spi_master_version = "1")]
2
use core::cell::Cell;
3
use core::{
4
    cell::UnsafeCell,
5
    future::Future,
6
    mem::MaybeUninit,
7
    pin::Pin,
8
    sync::atomic::{AtomicUsize, Ordering},
9
    task::{Context, Poll},
10
};
11

            
12
use enumset::{EnumSet, enum_set};
13

            
14
use super::{
15
    Address,
16
    AnySpi,
17
    Command,
18
    Config,
19
    ConfigError,
20
    DataMode,
21
    EMPTY_WRITE_PAD,
22
    FIFO_SIZE,
23
    SpiInterrupt,
24
    SpiPinGuard,
25
    any,
26
};
27
use crate::{
28
    asynch::AtomicWaker,
29
    clock::ll::SpiInstance,
30
    gpio::{InputSignal, OutputSignal},
31
    handler,
32
    interrupt::InterruptHandler,
33
    pac::spi2::RegisterBlock,
34
    private::{self, DropGuard},
35
    ram,
36
    spi::{BitOrder, Error, Mode},
37
    system::PeripheralGuard,
38
};
39

            
40
#[cfg_attr(spi_master_version = "1", path = "v1.rs")]
41
#[cfg_attr(spi_master_version = "2", path = "v2.rs")]
42
#[cfg_attr(spi_master_version = "3", path = "v3.rs")]
43
mod version;
44

            
45
#[derive(Debug)]
46
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
47
pub(super) struct SpiWrapper<'d> {
48
    pub(super) spi: AnySpi<'d>,
49
    _guard: PeripheralGuard,
50
}
51

            
52
impl<'d> SpiWrapper<'d> {
53
    pub(super) fn new(spi: impl Instance + 'd) -> Self {
54
70
        let p = spi.info().peripheral;
55
        let this = Self {
56
            spi: spi.degrade(),
57
70
            _guard: PeripheralGuard::new(p),
58
        };
59

            
60
        // Initialize state
61
        unsafe {
62
            this.state()
63
                .pins
64
                .get()
65
                .write(MaybeUninit::new(SpiPinGuard::new_unconnected()))
66
        }
67

            
68
        this
69
    }
70

            
71
    pub(super) fn info(&self) -> &'static Info {
72
        self.spi.info()
73
    }
74

            
75
    pub(super) fn state(&self) -> &'static State {
76
        self.spi.state()
77
    }
78

            
79
    pub(super) fn disable_peri_interrupt_on_all_cores(&self) {
80
        self.spi.disable_peri_interrupt_on_all_cores();
81
    }
82

            
83
    pub(super) fn set_interrupt_handler(&self, handler: InterruptHandler) {
84
        self.spi.set_interrupt_handler(handler);
85
    }
86

            
87
    pub(super) fn pins(&mut self) -> &mut SpiPinGuard {
88
        unsafe {
89
            // SAFETY: we "own" the state, we are allowed to borrow it mutably
90
            self.state().pins()
91
        }
92
    }
93
}
94

            
95
impl Drop for SpiWrapper<'_> {
96
50
    fn drop(&mut self) {
97
        unsafe {
98
            // SAFETY: we "own" the state, we are allowed to deinit it
99
            self.spi.state().deinit();
100
        }
101
50
    }
102
}
103

            
104
pub(super) struct SpiClockGuard {
105
    clock: SpiInstance,
106
}
107

            
108
impl SpiClockGuard {
109
146
    pub(super) fn new(spi: &Info) -> Self {
110
        let clock = spi.clock_instance;
111
        crate::clock::ll::ClockTree::with(|clocks| clock.request_function_clock(clocks));
112
        Self { clock }
113
146
    }
114
}
115

            
116
impl Drop for SpiClockGuard {
117
144
    fn drop(&mut self) {
118
        crate::clock::ll::ClockTree::with(|clocks| self.clock.release_function_clock(clocks));
119
144
    }
120
}
121

            
122
/// SPI peripheral instance.
123
pub trait Instance: private::Sealed + any::Degrade {
124
    #[doc(hidden)]
125
    /// Returns the peripheral data and state describing this instance.
126
    fn parts(&self) -> (&'static Info, &'static State);
127

            
128
    /// Returns the peripheral data describing this instance.
129
    #[doc(hidden)]
130
    #[inline(always)]
131
    fn info(&self) -> &'static Info {
132
        self.parts().0
133
    }
134

            
135
    /// Returns the peripheral state for this instance.
136
    #[doc(hidden)]
137
    #[inline(always)]
138
    fn state(&self) -> &'static State {
139
        self.parts().1
140
    }
141
}
142

            
143
/// Marker trait for QSPI-capable SPI peripherals.
144
#[doc(hidden)]
145
pub trait QspiInstance: Instance {}
146

            
147
/// Peripheral data describing a particular SPI instance.
148
#[doc(hidden)]
149
#[non_exhaustive]
150
#[allow(private_interfaces, reason = "Unstable details")]
151
pub struct Info {
152
    /// Pointer to the register block for this SPI instance.
153
    ///
154
    /// Used with [`Self::register_block`] to access the register block.
155
    pub register_block: *const RegisterBlock,
156

            
157
    /// The system peripheral marker.
158
    pub peripheral: crate::system::Peripheral,
159

            
160
    /// Interrupt handler for the asynchronous operations.
161
    pub async_handler: InterruptHandler,
162

            
163
    /// SCLK signal.
164
    pub sclk: OutputSignal,
165

            
166
    /// Chip select signals.
167
    pub cs: &'static [OutputSignal],
168

            
169
    pub sio_inputs: &'static [InputSignal],
170
    pub sio_outputs: &'static [OutputSignal],
171

            
172
    /// Clocks tree instance for this SPI peripheral.
173
    pub clock_instance: crate::soc::clocks::SpiInstance,
174
}
175

            
176
impl Info {
177
70
    pub(super) fn cs(&self, n: usize) -> OutputSignal {
178
70
        *unwrap!(self.cs.get(n), "CS{} is not defined", n)
179
70
    }
180

            
181
    pub(super) fn opt_sio_input(&self, n: usize) -> Option<InputSignal> {
182
71
        self.sio_inputs.get(n).copied()
183
    }
184

            
185
    pub(super) fn opt_sio_output(&self, n: usize) -> Option<OutputSignal> {
186
59
        self.sio_outputs.get(n).copied()
187
    }
188

            
189
71
    pub(super) fn sio_input(&self, n: usize) -> InputSignal {
190
        unwrap!(self.opt_sio_input(n), "SIO{} is not defined", n)
191
71
    }
192

            
193
59
    pub(super) fn sio_output(&self, n: usize) -> OutputSignal {
194
        unwrap!(self.opt_sio_output(n), "SIO{} is not defined", n)
195
59
    }
196
}
197

            
198
pub(super) struct Driver {
199
    pub(super) info: &'static Info,
200
    pub(super) state: &'static State,
201
}
202

            
203
// Private implementation bits.
204
impl Driver {
205
    /// Returns the register block for this SPI instance.
206
    pub(super) fn regs(&self) -> &RegisterBlock {
207
6846904
        unsafe { &*self.info.register_block }
208
    }
209

            
210
2
    pub(super) fn abort_transfer(&self) {
211
2
        version::abort_transfer(self);
212
        self.update();
213
2
    }
214

            
215
    /// Initializes for full-duplex 1 bit mode.
216
70
    pub(super) fn init(&self) {
217
70
        version::enable_peripheral_clock(self);
218

            
219
        crate::soc::clocks::ClockTree::with(|clocks| {
220
            #[cfg(soc_clock_node_spi_function_clock_is_configurable)]
221
            self.info.clock_instance.configure_function_clock(
222
                clocks,
223
                crate::soc::clocks::SpiFunctionClockConfig::default(),
224
            );
225
            self.info.clock_instance.request_function_clock(clocks);
226

            
227
            self.regs().user().modify(|_, w| {
228
                w.usr_miso_highpart().clear_bit();
229
                w.usr_mosi_highpart().clear_bit();
230
                w.doutdin().set_bit();
231
                w.usr_miso().set_bit();
232
                w.usr_mosi().set_bit();
233
                w.cs_hold().set_bit();
234
                w.usr_dummy_idle().set_bit();
235
                w.usr_addr().clear_bit();
236
                w.usr_command().clear_bit()
237
            });
238

            
239
            version::init(self);
240
            self.info.clock_instance.release_function_clock(clocks);
241
        });
242

            
243
        self.regs().slave().write(|w| unsafe { w.bits(0) });
244
70
    }
245

            
246
    fn init_spi_data_mode(
247
        &self,
248
        cmd_mode: DataMode,
249
        address_mode: DataMode,
250
        data_mode: DataMode,
251
    ) -> Result<(), Error> {
252
        version::init_spi_data_mode(self, cmd_mode, address_mode, data_mode)
253
    }
254

            
255
    /// Enables or disables listening for the given interrupts.
256
    #[cfg_attr(not(feature = "unstable"), allow(dead_code))]
257
    pub(super) fn enable_listen(&self, interrupts: EnumSet<SpiInterrupt>, enable: bool) {
258
482
        version::enable_listen(self, interrupts, enable);
259
    }
260

            
261
    /// Returns the asserted interrupts.
262
    #[cfg_attr(not(feature = "unstable"), allow(dead_code))]
263
    pub(super) fn interrupts(&self) -> EnumSet<SpiInterrupt> {
264
        version::interrupts(self)
265
    }
266

            
267
    /// Resets asserted interrupts.
268
    pub(super) fn clear_interrupts(&self, interrupts: EnumSet<SpiInterrupt>) {
269
        version::clear_interrupts(self, interrupts);
270
    }
271

            
272
90
    pub(super) fn apply_config(&self, config: &Config) -> Result<(), ConfigError> {
273
90
        config.validate()?;
274

            
275
        let raw = config.raw_clock_reg_value()?;
276
        crate::soc::clocks::ClockTree::with(|clocks| {
277
            #[cfg(soc_clock_node_spi_function_clock_is_configurable)]
278
            self.info
279
                .clock_instance
280
                .configure_function_clock(clocks, config.clock_source);
281
            self.info.clock_instance.request_function_clock(clocks);
282

            
283
            self.regs().clock().write(|w| unsafe { w.bits(raw) });
284

            
285
            self.set_bit_order(config.read_bit_order, config.write_bit_order);
286
90
            self.set_data_mode(config.mode);
287

            
288
            version::apply_config(self);
289
            self.info.clock_instance.release_function_clock(clocks);
290
        });
291

            
292
90
        self.state
293
            .min_async_transfer_size
294
90
            .store(config.min_async_transfer_size, Ordering::Relaxed);
295

            
296
        Ok(())
297
90
    }
298

            
299
    fn set_data_mode(&self, data_mode: Mode) {
300
        version::set_data_mode(self, data_mode);
301
    }
302

            
303
    #[cfg(not(spi_master_bit_order_is_bool))]
304
    fn set_bit_order(&self, read_order: BitOrder, write_order: BitOrder) {
305
        let read_value = match read_order {
306
            BitOrder::MsbFirst => 0,
307
            BitOrder::LsbFirst => 1,
308
        };
309
        let write_value = match write_order {
310
            BitOrder::MsbFirst => 0,
311
            BitOrder::LsbFirst => 1,
312
        };
313
        self.regs().ctrl().modify(|_, w| unsafe {
314
            w.rd_bit_order().bits(read_value);
315
            w.wr_bit_order().bits(write_value);
316
            w
317
        });
318
    }
319

            
320
    #[cfg(spi_master_bit_order_is_bool)]
321
    fn set_bit_order(&self, read_order: BitOrder, write_order: BitOrder) {
322
        let read_value = match read_order {
323
            BitOrder::MsbFirst => false,
324
            BitOrder::LsbFirst => true,
325
        };
326
        let write_value = match write_order {
327
            BitOrder::MsbFirst => false,
328
            BitOrder::LsbFirst => true,
329
        };
330
        self.regs().ctrl().modify(|_, w| {
331
            w.rd_bit_order().bit(read_value);
332
            w.wr_bit_order().bit(write_value);
333
            w
334
        });
335
    }
336

            
337
    #[cfg_attr(place_spi_master_driver_in_ram, ram)]
338
535
    pub(super) fn fill_fifo(&self, chunk: &[u8]) {
339
        let (chunks, rem) = chunk.as_chunks::<4>();
340
        let mut w_iter = self.regs().w_iter();
341
        for c in chunks {
342
            if let Some(w_reg) = w_iter.next() {
343
8335
                let word = u32::from_le_bytes(*c);
344
                w_reg.write(|w| w.buf().set(word));
345
            }
346
        }
347
535
        if !rem.is_empty()
348
            && let Some(w_reg) = w_iter.next()
349
        {
350
            let word = match rem.len() {
351
                3 => (rem[0] as u32) | ((rem[1] as u32) << 8) | ((rem[2] as u32) << 16),
352
                2 => (rem[0] as u32) | ((rem[1] as u32) << 8),
353
                1 => rem[0] as u32,
354
                _ => unreachable!(),
355
            };
356
            w_reg.write(|w| w.buf().set(word));
357
        }
358
535
    }
359

            
360
    /// Writes bytes to SPI.
361
    #[cfg_attr(place_spi_master_driver_in_ram, ram)]
362
535
    pub(super) fn write_one(&self, words: &[u8]) -> Result<(), Error> {
363
535
        if words.len() > FIFO_SIZE {
364
            return Err(Error::FifoSizeExeeded);
365
        }
366
        self.configure_datalen(0, words.len());
367
535
        self.fill_fifo(words);
368
        self.start_operation();
369
        Ok(())
370
535
    }
371

            
372
    /// Writes bytes to SPI.
373
    #[cfg_attr(place_spi_master_driver_in_ram, ram)]
374
    pub(super) fn write(&self, words: &[u8]) -> Result<(), Error> {
375
        for chunk in words.chunks(FIFO_SIZE) {
376
            self.write_one(chunk)?;
377
            self.flush()?;
378
        }
379
        Ok(())
380
    }
381

            
382
    /// Writes bytes to SPI.
383
    #[cfg_attr(place_spi_master_driver_in_ram, ram)]
384
    pub(super) async fn write_async(&self, words: &[u8]) -> Result<(), Error> {
385
        for chunk in words.chunks(FIFO_SIZE) {
386
            self.write_one(chunk)?;
387
            self.flush_async().await;
388
        }
389
        Ok(())
390
    }
391

            
392
    /// Reads bytes from SPI.
393
    ///
394
    /// Sends out a stuffing byte for every byte to read. Does not perform
395
    /// flushing. To read the response to a prior write, use [`Self::transfer`]
396
    /// instead.
397
    #[cfg_attr(place_spi_master_driver_in_ram, ram)]
398
    pub(super) fn read(&self, words: &mut [u8]) -> Result<(), Error> {
399
        let empty_array = [EMPTY_WRITE_PAD; FIFO_SIZE];
400

            
401
        for chunk in words.chunks_mut(FIFO_SIZE) {
402
            self.write_one(&empty_array[0..chunk.len()])?;
403
            self.flush()?;
404
            self.read_from_fifo(chunk)?;
405
        }
406
        Ok(())
407
    }
408

            
409
    /// Reads bytes from SPI.
410
    ///
411
    /// Sends out a stuffing byte for every byte to read. To read the response to a
412
    /// prior write, use [`Self::transfer`] instead
413
    #[cfg_attr(place_spi_master_driver_in_ram, ram)]
414
    pub(super) async fn read_async(&self, words: &mut [u8]) -> Result<(), Error> {
415
        let empty_array = [EMPTY_WRITE_PAD; FIFO_SIZE];
416

            
417
        for chunk in words.chunks_mut(FIFO_SIZE) {
418
            self.write_one(&empty_array[0..chunk.len()])?;
419
            self.flush_async().await;
420
            self.read_from_fifo(chunk)?;
421
        }
422
        Ok(())
423
    }
424

            
425
    /// Reads received bytes from SPI FIFO.
426
    ///
427
    /// Copies the contents of the SPI receive FIFO into `words`. Does not perform
428
    /// any data transfer. To read the response to a prior write, use
429
    /// [`Self::transfer`] instead
430
    #[cfg_attr(place_spi_master_driver_in_ram, ram)]
431
577
    pub(super) fn read_from_fifo(&self, words: &mut [u8]) -> Result<(), Error> {
432
577
        if words.len() > FIFO_SIZE {
433
            return Err(Error::FifoSizeExeeded);
434
        }
435

            
436
        for (chunk, w_reg) in words.chunks_mut(4).zip(self.regs().w_iter()) {
437
            let reg_val = w_reg.read().bits();
438
            let bytes = reg_val.to_le_bytes();
439

            
440
            let len = chunk.len();
441
            chunk.copy_from_slice(&bytes[..len]);
442
        }
443

            
444
        Ok(())
445
577
    }
446

            
447
    pub(super) fn busy(&self) -> bool {
448
        self.regs().cmd().read().usr().bit_is_set()
449
6846904
    }
450

            
451
    // Check if the bus is busy and if it is wait for it to be idle
452
    #[cfg_attr(place_spi_master_driver_in_ram, ram)]
453
    pub(super) fn flush_async(&self) -> impl Future<Output = ()> {
454
        SpiFuture { driver: self }
455
    }
456

            
457
    // Check if the bus is busy and if it is wait for it to be idle
458
    #[cfg_attr(place_spi_master_driver_in_ram, ram)]
459
2
    pub(super) fn flush(&self) -> Result<(), Error> {
460
383643
        while self.busy() {
461
            // wait for bus to be clear
462
        }
463
        Ok(())
464
2
    }
465

            
466
    #[cfg_attr(place_spi_master_driver_in_ram, ram)]
467
3
    pub(super) fn transfer_in_place(&self, words: &mut [u8]) -> Result<(), Error> {
468
        for chunk in words.chunks_mut(FIFO_SIZE) {
469
129
            self.write_one(chunk)?;
470
            self.flush()?;
471
129
            self.read_from_fifo(chunk)?;
472
        }
473

            
474
        Ok(())
475
3
    }
476

            
477
    #[cfg_attr(place_spi_master_driver_in_ram, ram)]
478
10
    pub(super) fn transfer(&self, read: &mut [u8], write: &[u8]) -> Result<(), Error> {
479
        let mut write_from = 0;
480
        let mut read_from = 0;
481

            
482
        loop {
483
            // How many bytes we write in this chunk
484
146
            let write_inc = core::cmp::min(FIFO_SIZE, write.len() - write_from);
485
            // How many bytes we read in this chunk
486
146
            let read_inc = core::cmp::min(FIFO_SIZE, read.len() - read_from);
487

            
488
146
            if (write_inc == 0) && (read_inc == 0) {
489
                break;
490
            }
491

            
492
136
            if write_inc < read_inc {
493
                // Read more than we write, must pad writing part with zeros
494
2
                let mut empty = [EMPTY_WRITE_PAD; FIFO_SIZE];
495
                empty[0..write_inc].copy_from_slice(&write[write_from..][..write_inc]);
496
2
                self.write_one(&empty[..read_inc])?;
497
            } else {
498
134
                self.write_one(&write[write_from..][..write_inc])?;
499
            }
500

            
501
            self.flush()?;
502

            
503
136
            if read_inc > 0 {
504
136
                self.read_from_fifo(&mut read[read_from..][..read_inc])?;
505
            }
506

            
507
136
            write_from += write_inc;
508
136
            read_from += read_inc;
509
        }
510
        Ok(())
511
10
    }
512

            
513
18
    fn prepare_half_duplex_chunk(&self, first: bool, last: bool) {
514
        self.regs().user().modify(|_, w| {
515
26
            if !first {
516
                w.usr_command().clear_bit();
517
                w.usr_addr().clear_bit();
518
                w.usr_dummy().clear_bit();
519
                w.cs_setup().clear_bit();
520
            }
521
            w.cs_hold().bit(!last)
522
        });
523
        version::set_cs_keep_active(self, !last);
524
18
    }
525

            
526
    /// Blocking, FIFO-based half-duplex read.
527
    ///
528
    /// Performs the command, address, dummy, and data phases as a single SPI transaction without
529
    /// involving the DMA engine. Transfers larger than the FIFO are split into chunks while keeping
530
    /// CS asserted.
531
    #[cfg_attr(place_spi_master_driver_in_ram, ram)]
532
10
    pub(super) fn half_duplex_read(
533
        &self,
534
        data_mode: DataMode,
535
        cmd: Command,
536
        address: Address,
537
        dummy: u8,
538
        buffer: &mut [u8],
539
    ) -> Result<(), Error> {
540
10
        if buffer.is_empty() {
541
            error!("Half-duplex mode does not support empty buffer");
542
            return Err(Error::Unsupported);
543
        }
544

            
545
10
        self.setup_half_duplex(
546
            false,
547
            cmd,
548
            address,
549
            false,
550
            dummy,
551
            buffer.is_empty(),
552
            data_mode,
553
        )?;
554

            
555
        let _keep_cs_guard = DropGuard::new((), |_| version::set_cs_keep_active(self, false));
556
        let mut first = true;
557
        let mut chunks = buffer.chunks_mut(FIFO_SIZE).peekable();
558
26
        while let Some(chunk) = chunks.next() {
559
            let last = chunks.peek().is_none();
560
            self.prepare_half_duplex_chunk(first, last);
561
            self.configure_datalen(chunk.len(), 0);
562
            self.start_operation();
563
            self.flush()?;
564
26
            self.read_from_fifo(chunk)?;
565
            first = false;
566
        }
567
        Ok(())
568
10
    }
569

            
570
    /// Blocking, FIFO-based half-duplex write.
571
    ///
572
    /// Performs the command, address, dummy, and data phases as a single SPI transaction without
573
    /// involving the DMA engine. Transfers larger than the FIFO are split into chunks while keeping
574
    /// CS asserted.
575
    #[cfg_attr(place_spi_master_driver_in_ram, ram)]
576
    pub(super) fn half_duplex_write(
577
        &self,
578
        data_mode: DataMode,
579
        cmd: Command,
580
        address: Address,
581
        dummy: u8,
582
        buffer: &[u8],
583
    ) -> Result<(), Error> {
584
        cfg_select! {
585
            all(spi_master_version = "1", spi_address_workaround) => {
586
                let mut buffer = buffer;
587
                let mut data_mode = data_mode;
588
                let mut address = address;
589
                let addr_bytes;
590
                if buffer.is_empty() && !address.is_none() {
591
                    // If the buffer is empty, we need to send a dummy byte
592
                    // to trigger the address phase.
593
                    let bytes_to_write = address.width().div_ceil(8);
594
                    // The address register is read in big-endian order,
595
                    // we have to prepare the emulated write in the same way.
596
                    addr_bytes = address.value().to_be_bytes();
597
                    buffer = &addr_bytes[4 - bytes_to_write..][..bytes_to_write];
598
                    data_mode = address.mode();
599
                    address = Address::None;
600
                }
601

            
602
                if dummy > 0 {
603
                    // FIXME: https://github.com/esp-rs/esp-hal/issues/2240
604
                    error!("Dummy bits are not supported without data");
605
                    return Err(Error::Unsupported);
606
                }
607
            }
608
            _ => {}
609
        }
610

            
611
        self.setup_half_duplex(
612
            true,
613
            cmd,
614
            address,
615
            false,
616
            dummy,
617
            buffer.is_empty(),
618
            data_mode,
619
        )?;
620

            
621
        let _keep_cs_guard = DropGuard::new((), |_| version::set_cs_keep_active(self, false));
622
        if buffer.is_empty() {
623
            self.prepare_half_duplex_chunk(true, true);
624
            self.start_operation();
625
            self.flush()?;
626
        } else {
627
            let mut first = true;
628
            let mut chunks = buffer.chunks(FIFO_SIZE).peekable();
629
            while let Some(chunk) = chunks.next() {
630
                let last = chunks.peek().is_none();
631
                self.prepare_half_duplex_chunk(first, last);
632
                self.configure_datalen(0, chunk.len());
633
                self.fill_fifo(chunk);
634
                self.start_operation();
635
                self.flush()?;
636
                first = false;
637
            }
638
        }
639
        Ok(())
640
    }
641

            
642
    /// Asynchronous, FIFO-based half-duplex read.
643
    ///
644
    /// Performs the command, address, dummy, and data phases as a single SPI transaction without
645
    /// involving the DMA engine. Transfers larger than the FIFO are split into chunks while keeping
646
    /// CS asserted.
647
    #[cfg_attr(place_spi_master_driver_in_ram, ram)]
648
    pub(super) async fn half_duplex_read_async(
649
6
        &self,
650
6
        data_mode: DataMode,
651
6
        cmd: Command,
652
6
        address: Address,
653
6
        dummy: u8,
654
6
        buffer: &mut [u8],
655
18
    ) -> Result<(), Error> {
656
6
        if buffer.is_empty() {
657
            error!("Half-duplex mode does not support empty buffer");
658
            return Err(Error::Unsupported);
659
        }
660

            
661
6
        self.setup_half_duplex(
662
            false,
663
            cmd,
664
            address,
665
            false,
666
            dummy,
667
            buffer.is_empty(),
668
            data_mode,
669
        )?;
670

            
671
6
        let _keep_cs_guard = DropGuard::new((), |_| version::set_cs_keep_active(self, false));
672
        let mut first = true;
673
        let mut chunks = buffer.chunks_mut(FIFO_SIZE).peekable();
674
24
        while let Some(chunk) = chunks.next() {
675
            let last = chunks.peek().is_none();
676
18
            self.prepare_half_duplex_chunk(first, last);
677
18
            self.configure_datalen(chunk.len(), 0);
678
18
            self.start_operation();
679

            
680
18
            let cancel_on_drop = DropGuard::new((), |_| {
681
                self.abort_transfer();
682
                let _ = self.flush();
683
            });
684
18
            self.flush_async().await;
685
            cancel_on_drop.defuse();
686

            
687
18
            self.read_from_fifo(chunk)?;
688
            first = false;
689
        }
690
        Ok(())
691
6
    }
692

            
693
    /// Asynchronous, FIFO-based half-duplex write.
694
    ///
695
    /// Performs the command, address, dummy, and data phases as a single SPI transaction without
696
    /// involving the DMA engine. Transfers larger than the FIFO are split into chunks while keeping
697
    /// CS asserted.
698
    #[cfg_attr(place_spi_master_driver_in_ram, ram)]
699
    pub(super) async fn half_duplex_write_async(
700
        &self,
701
        data_mode: DataMode,
702
        cmd: Command,
703
        address: Address,
704
        dummy: u8,
705
        buffer: &[u8],
706
    ) -> Result<(), Error> {
707
        cfg_select! {
708
            all(spi_master_version = "1", spi_address_workaround) => {
709
                let mut buffer = buffer;
710
                let mut data_mode = data_mode;
711
                let mut address = address;
712
                let addr_bytes;
713
                if buffer.is_empty() && !address.is_none() {
714
                    // If the buffer is empty, we need to send a dummy byte
715
                    // to trigger the address phase.
716
                    let bytes_to_write = address.width().div_ceil(8);
717
                    // The address register is read in big-endian order,
718
                    // we have to prepare the emulated write in the same way.
719
                    addr_bytes = address.value().to_be_bytes();
720
                    buffer = &addr_bytes[4 - bytes_to_write..][..bytes_to_write];
721
                    data_mode = address.mode();
722
                    address = Address::None;
723
                }
724

            
725
                if dummy > 0 {
726
                    // FIXME: https://github.com/esp-rs/esp-hal/issues/2240
727
                    error!("Dummy bits are not supported without data");
728
                    return Err(Error::Unsupported);
729
                }
730
            }
731
            _ => {}
732
        }
733

            
734
        self.setup_half_duplex(
735
            true,
736
            cmd,
737
            address,
738
            false,
739
            dummy,
740
            buffer.is_empty(),
741
            data_mode,
742
        )?;
743

            
744
        let _keep_cs_guard = DropGuard::new((), |_| version::set_cs_keep_active(self, false));
745
        if buffer.is_empty() {
746
            self.prepare_half_duplex_chunk(true, true);
747
            self.start_operation();
748

            
749
            let cancel_on_drop = DropGuard::new((), |_| {
750
                self.abort_transfer();
751
                let _ = self.flush();
752
            });
753
            self.flush_async().await;
754
            cancel_on_drop.defuse();
755
        } else {
756
            let mut first = true;
757
            let mut chunks = buffer.chunks(FIFO_SIZE).peekable();
758
            while let Some(chunk) = chunks.next() {
759
                let last = chunks.peek().is_none();
760
                self.prepare_half_duplex_chunk(first, last);
761
                self.configure_datalen(0, chunk.len());
762
                self.fill_fifo(chunk);
763
                self.start_operation();
764

            
765
                let cancel_on_drop = DropGuard::new((), |_| {
766
                    self.abort_transfer();
767
                    let _ = self.flush();
768
                });
769
                self.flush_async().await;
770
                cancel_on_drop.defuse();
771

            
772
                first = false;
773
            }
774
        }
775
        Ok(())
776
    }
777

            
778
    #[cfg_attr(place_spi_master_driver_in_ram, ram)]
779
328
    pub(super) async fn transfer_in_place_async(&self, words: &mut [u8]) -> Result<(), Error> {
780
136
        for chunk in words.chunks_mut(FIFO_SIZE) {
781
            // Cut the transfer short if the future is dropped. We'll block for a short
782
            // while to ensure the peripheral is idle.
783
136
            let cancel_on_drop = DropGuard::new((), |_| {
784
2
                self.abort_transfer();
785
2
                let _ = self.flush();
786
            });
787
136
            let res = self.write_one(chunk);
788
464
            self.flush_async().await;
789
            cancel_on_drop.defuse();
790
134
            res?;
791

            
792
134
            self.read_from_fifo(chunk)?;
793
2
        }
794

            
795
        Ok(())
796
    }
797

            
798
    #[cfg_attr(place_spi_master_driver_in_ram, ram)]
799
128
    pub(super) async fn transfer_async(&self, read: &mut [u8], write: &[u8]) -> Result<(), Error> {
800
8
        let mut write_from = 0;
801
8
        let mut read_from = 0;
802

            
803
        loop {
804
            // How many bytes we write in this chunk
805
142
            let write_inc = core::cmp::min(FIFO_SIZE, write.len() - write_from);
806
            // How many bytes we read in this chunk
807
142
            let read_inc = core::cmp::min(FIFO_SIZE, read.len() - read_from);
808

            
809
142
            if (write_inc == 0) && (read_inc == 0) {
810
                break;
811
            }
812

            
813
134
            self.flush_async().await;
814

            
815
134
            if write_inc < read_inc {
816
                // Read more than we write, must pad writing part with zeros
817
2
                let mut empty = [EMPTY_WRITE_PAD; FIFO_SIZE];
818
2
                empty[0..write_inc].copy_from_slice(&write[write_from..][..write_inc]);
819
2
                self.write_one(&empty[..read_inc])?;
820
            } else {
821
132
                self.write_one(&write[write_from..][..write_inc])?;
822
            }
823

            
824
262
            self.flush_async().await;
825

            
826
134
            if read_inc > 0 {
827
134
                self.read_from_fifo(&mut read[read_from..][..read_inc])?;
828
            }
829

            
830
134
            write_from += write_inc;
831
134
            read_from += read_inc;
832
        }
833
        Ok(())
834
    }
835

            
836
    #[cfg_attr(place_spi_master_driver_in_ram, ram)]
837
119
    pub(super) fn start_operation(&self) {
838
119
        self.update();
839
        self.clear_interrupts(SpiInterrupt::TransferDone.into());
840
        self.regs().cmd().modify(|_, w| w.usr().set_bit());
841
119
    }
842

            
843
66
    pub(super) fn setup_full_duplex(&self) -> Result<(), Error> {
844
        self.regs().user().modify(|_, w| {
845
            w.usr_miso().set_bit();
846
            w.usr_mosi().set_bit();
847
            w.doutdin().set_bit();
848
            w.usr_dummy().clear_bit();
849
            w.sio().clear_bit()
850
        });
851

            
852
        self.init_spi_data_mode(
853
            DataMode::SingleTwoDataLines,
854
            DataMode::SingleTwoDataLines,
855
            DataMode::SingleTwoDataLines,
856
        )?;
857

            
858
        version::setup_full_duplex(self);
859

            
860
        Ok(())
861
66
    }
862

            
863
    #[expect(clippy::too_many_arguments)]
864
76
    pub(super) fn setup_half_duplex(
865
        &self,
866
        is_write: bool,
867
        cmd: Command,
868
        address: Address,
869
        dummy_idle: bool,
870
        dummy: u8,
871
        no_mosi_miso: bool,
872
        data_mode: DataMode,
873
    ) -> Result<(), Error> {
874
76
        self.init_spi_data_mode(cmd.mode(), address.mode(), data_mode)?;
875

            
876
        let dummy = version::prepare_half_duplex(self, is_write, dummy);
877

            
878
        let reg_block = self.regs();
879
        reg_block.user().modify(|_, w| {
880
            w.usr_miso_highpart().clear_bit();
881
            w.usr_mosi_highpart().clear_bit();
882
            // This bit tells the hardware whether we use Single or SingleTwoDataLines
883
            w.sio().bit(data_mode == DataMode::Single);
884
            w.doutdin().clear_bit();
885
76
            w.usr_miso().bit(!is_write && !no_mosi_miso);
886
            w.usr_mosi().bit(is_write && !no_mosi_miso);
887
            w.cs_hold().set_bit();
888
            w.usr_dummy_idle().bit(dummy_idle);
889
76
            w.usr_dummy().bit(dummy != 0);
890
            w.usr_addr().bit(!address.is_none());
891
            w.usr_command().bit(!cmd.is_none())
892
        });
893

            
894
        version::setup_half_duplex(self);
895

            
896
        reg_block.slave().write(|w| unsafe { w.bits(0) });
897

            
898
        self.update();
899

            
900
        // set cmd, address, dummy cycles
901
76
        self.set_up_common_phases(cmd, address, dummy);
902

            
903
        Ok(())
904
76
    }
905

            
906
    pub(super) fn set_up_common_phases(&self, cmd: Command, address: Address, dummy: u8) {
907
        let reg_block = self.regs();
908
76
        if !cmd.is_none() {
909
            reg_block.user2().modify(|_, w| unsafe {
910
                w.usr_command_bitlen().bits((cmd.width() - 1) as u8);
911
                w.usr_command_value().bits(cmd.value())
912
            });
913
        }
914

            
915
76
        if !address.is_none() {
916
            reg_block
917
                .user1()
918
18
                .modify(|_, w| unsafe { w.usr_addr_bitlen().bits((address.width() - 1) as u8) });
919

            
920
18
            version::write_address(self, address.value() << (32 - address.width()));
921
        }
922

            
923
76
        if dummy > 0 {
924
            reg_block
925
                .user1()
926
                .modify(|_, w| unsafe { w.usr_dummy_cyclelen().bits(dummy - 1) });
927
        }
928
    }
929

            
930
    pub(super) fn update(&self) {
931
        cfg_select! {
932
            spi_master_version = "3" => {
933
                let reg_block = self.regs();
934

            
935
                reg_block.cmd().modify(|_, w| w.update().set_bit());
936

            
937
535
                while reg_block.cmd().read().update().bit_is_set() {
938
                    // wait
939
                }
940
            }
941
            _ => {
942
                // Doesn't seem to be needed for ESP32 and ESP32-S2
943
            }
944
        }
945
    }
946

            
947
119
    pub(super) fn configure_datalen(&self, rx_len_bytes: usize, tx_len_bytes: usize) {
948
119
        let rx_len = rx_len_bytes as u32 * 8;
949
535
        let tx_len = tx_len_bytes as u32 * 8;
950

            
951
535
        version::configure_datalen(self, rx_len.saturating_sub(1), tx_len.saturating_sub(1));
952
119
    }
953
}
954

            
955
impl PartialEq for Info {
956
    fn eq(&self, other: &Self) -> bool {
957
        core::ptr::eq(self.register_block, other.register_block)
958
    }
959
}
960

            
961
unsafe impl Sync for Info {}
962

            
963
for_each_spi_master! {
964
    ($peri:ident, $sys:ident, $sclk:ident [$($cs:ident),+] [$($sio:ident),*] $(, $is_qspi:tt)?) => {
965
        impl Instance for crate::peripherals::$peri<'_> {
966
            #[inline(always)]
967
            fn parts(&self) -> (&'static Info, &'static State) {
968
                #[handler]
969
286
                #[ram]
970
                fn irq_handler() {
971
286
                    handle_async(&INFO, &STATE)
972
                }
973

            
974
                static INFO: Info = Info {
975
                    register_block: crate::peripherals::$peri::ptr(),
976
                    peripheral: crate::system::Peripheral::$sys,
977
                    async_handler: irq_handler,
978
                    sclk: OutputSignal::$sclk,
979
                    cs: &[$(OutputSignal::$cs),+],
980
                    sio_inputs: &[$(InputSignal::$sio),*],
981
                    sio_outputs: &[$(OutputSignal::$sio),*],
982
                    clock_instance: crate::soc::clocks::SpiInstance::$sys,
983
                };
984

            
985
                static STATE: State = State {
986
                    waker: AtomicWaker::new(),
987
                    pins: UnsafeCell::new(MaybeUninit::uninit()),
988
                    min_async_transfer_size: AtomicUsize::new(0),
989

            
990
                    #[cfg(spi_master_version = "1")]
991
                    esp32_hack: Esp32Hack {
992
                        timing_miso_delay: Cell::new(None),
993
                        extra_dummy: Cell::new(0),
994
                    },
995
                };
996

            
997
                (&INFO, &STATE)
998
            }
999
        }
        $(
            // If the extra pins are set, implement QspiInstance
            $crate::ignore!($is_qspi);
            impl QspiInstance for crate::peripherals::$peri<'_> {}
        )?
    };
}
#[doc(hidden)]
pub struct State {
    pub(super) waker: AtomicWaker,
    pins: UnsafeCell<MaybeUninit<SpiPinGuard>>,
    pub(super) min_async_transfer_size: AtomicUsize,
    #[cfg(spi_master_version = "1")]
    esp32_hack: Esp32Hack,
}
impl State {
    // Syntactic helper to get a mutable reference to the pin guard.
    //
    // Intended to be called in `SpiWrapper::pins` only
    //
    // # Safety
    //
    // The caller must ensure that Rust's aliasing rules are upheld.
    #[allow(
        clippy::mut_from_ref,
        reason = "Safety requirements ensure this is okay"
    )]
    pub(super) unsafe fn pins(&self) -> &mut SpiPinGuard {
        unsafe { (&mut *self.pins.get()).assume_init_mut() }
    }
    unsafe fn deinit(&self) {
        unsafe {
            let mut old = self.pins.get().replace(MaybeUninit::uninit());
            old.assume_init_drop();
        }
    }
}
#[cfg(spi_master_version = "1")]
pub(super) struct Esp32Hack {
    timing_miso_delay: Cell<Option<u8>>,
    extra_dummy: Cell<u8>,
}
unsafe impl Sync for State {}
#[ram]
286
pub(super) fn handle_async(info: &'static Info, state: &'static State) {
    let driver = Driver { info, state };
286
    if driver.interrupts().contains(SpiInterrupt::TransferDone) {
        driver.enable_listen(SpiInterrupt::TransferDone.into(), false);
286
        state.waker.wake();
    }
}
#[must_use = "futures do nothing unless you `.await` or poll them"]
struct SpiFuture<'a> {
    driver: &'a Driver,
}
impl SpiFuture<'_> {
    const EVENTS: EnumSet<SpiInterrupt> = enum_set!(SpiInterrupt::TransferDone);
}
impl Future for SpiFuture<'_> {
    type Output = ();
    #[cfg_attr(place_spi_master_driver_in_ram, ram)]
896
    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
896
        if !self.driver.busy() {
            self.driver.clear_interrupts(Self::EVENTS);
            return Poll::Ready(());
        }
482
        self.driver.state.waker.register(cx.waker());
        self.driver.enable_listen(Self::EVENTS, true);
        // On some chips the interrupt enable bit and the interrupt status bit are in the same
        // register. If the transfer ends while we enable the interrupt, the read-modify-write
        // clears the status bit, and the peripheral does not request an interrupt. Check the
        // peripheral again to detect this case.
482
        if self.driver.busy() {
            Poll::Pending
        } else {
            self.driver.clear_interrupts(Self::EVENTS);
            Poll::Ready(())
        }
896
    }
}
impl Drop for SpiFuture<'_> {
    fn drop(&mut self) {
422
        self.driver.enable_listen(Self::EVENTS, false);
422
    }
}