apollo3/
iom.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! IO Master Driver (I2C and SPI)
6
7use core::cell::Cell;
8use kernel::hil;
9use kernel::hil::gpio::Configure;
10use kernel::hil::i2c;
11use kernel::hil::spi::cs::ChipSelectPolar;
12use kernel::hil::spi::{ClockPhase, ClockPolarity, SpiMaster, SpiMasterClient};
13use kernel::utilities::cells::{MapCell, OptionalCell};
14use kernel::utilities::leasable_buffer::SubSliceMut;
15use kernel::utilities::registers::interfaces::{ReadWriteable, Readable, Writeable};
16use kernel::utilities::registers::{register_bitfields, register_structs, ReadOnly, ReadWrite};
17use kernel::utilities::StaticRef;
18use kernel::ErrorCode;
19
20const IOM0_BASE: StaticRef<IomRegisters> =
21    unsafe { StaticRef::new(0x5000_4000 as *const IomRegisters) };
22const IOM1_BASE: StaticRef<IomRegisters> =
23    unsafe { StaticRef::new(0x5000_5000 as *const IomRegisters) };
24const IOM2_BASE: StaticRef<IomRegisters> =
25    unsafe { StaticRef::new(0x5000_6000 as *const IomRegisters) };
26const IOM3_BASE: StaticRef<IomRegisters> =
27    unsafe { StaticRef::new(0x5000_7000 as *const IomRegisters) };
28const IOM4_BASE: StaticRef<IomRegisters> =
29    unsafe { StaticRef::new(0x5000_8000 as *const IomRegisters) };
30const IOM5_BASE: StaticRef<IomRegisters> =
31    unsafe { StaticRef::new(0x5000_9000 as *const IomRegisters) };
32
33register_structs! {
34    pub IomRegisters {
35        (0x000 => fifo: ReadWrite<u32, FIFO::Register>),
36        (0x004 => _reserved0),
37        (0x100 => fifoptr: ReadWrite<u32, FIFOPTR::Register>),
38        (0x104 => fifothr: ReadWrite<u32, FIFOTHR::Register>),
39        (0x108 => fifopop: ReadWrite<u32, FIFOPOP::Register>),
40        (0x10C => fifopush: ReadWrite<u32, FIFOPUSH::Register>),
41        (0x110 => fifoctrl: ReadWrite<u32, FIFOCTRL::Register>),
42        (0x114 => fifoloc: ReadWrite<u32, FIFOLOC::Register>),
43        (0x118 => _reserved1),
44        (0x200 => inten: ReadWrite<u32, INT::Register>),
45        (0x204 => intstat: ReadWrite<u32, INT::Register>),
46        (0x208 => intclr: ReadWrite<u32, INT::Register>),
47        (0x20C => intset: ReadWrite<u32, INT::Register>),
48        (0x210 => clkcfg: ReadWrite<u32, CLKCFG::Register>),
49        (0x214 => submodctrl: ReadWrite<u32, SUBMODCTRL::Register>),
50        (0x218 => cmd: ReadWrite<u32, CMD::Register>),
51        (0x21C => dcx: ReadWrite<u32, DCX::Register>),
52        (0x220 => offsethi: ReadWrite<u32, OFFSETHI::Register>),
53        (0x224 => cmdstat: ReadOnly<u32, CMDSTAT::Register>),
54        (0x228 => _reserved2),
55        (0x240 => dmatrigen: ReadWrite<u32, DMATRIGEN::Register>),
56        (0x244 => dmatrigstat: ReadWrite<u32, DMATRIGSTAT::Register>),
57        (0x248 => _reserved3),
58        (0x280 => dmacfg: ReadWrite<u32, DMACFG::Register>),
59        (0x284 => _reserved4),
60        (0x288 => dmatotcount: ReadWrite<u32, DMATOTCOUNT::Register>),
61        (0x28C => dmatargaddr: ReadWrite<u32, DMATARGADDR::Register>),
62        (0x290 => dmastat: ReadWrite<u32, DMASTAT::Register>),
63        (0x294 => cqcfg: ReadWrite<u32, CQCFG::Register>),
64        (0x298 => cqaddr: ReadWrite<u32, CQADDR::Register>),
65        (0x29C => cqstat: ReadWrite<u32, CQSTAT::Register>),
66        (0x2A0 => cqflags: ReadWrite<u32, CQFLAGS::Register>),
67        (0x2A4 => cqsetclear: ReadWrite<u32, CQSETCLEAR::Register>),
68        (0x2A8 => cqpauseen: ReadWrite<u32, CQPAUSEEN::Register>),
69        (0x2AC => cqcuridx: ReadWrite<u32, CQCURIDX::Register>),
70        (0x2B0 => cqendidx: ReadWrite<u32, CQENDIDX::Register>),
71        (0x2B4 => status: ReadOnly<u32, STATUS::Register>),
72        (0x2B8 => _reserved5),
73        (0x300 => mspicfg: ReadWrite<u32, MSPICFG::Register>),
74        (0x304 => _reserved6),
75        (0x400 => mi2ccfg: ReadWrite<u32, MI2CCFG::Register>),
76        (0x404 => devcfg: ReadWrite<u32, DEVCFG::Register>),
77        (0x408 => _reserved7),
78        (0x410 => iomdbg: ReadWrite<u32, IOMDBG::Register>),
79        (0x414 => @END),
80    }
81}
82
83register_bitfields![u32,
84    FIFO [
85        FIFO OFFSET(0) NUMBITS(32) []
86    ],
87    FIFOPTR [
88        FIFO0SIZ OFFSET(0) NUMBITS(8) [],
89        FIFO0REM OFFSET(8) NUMBITS(8) [],
90        FIFO1SIZ OFFSET(16) NUMBITS(8) [],
91        FIFO1REM OFFSET(24) NUMBITS(8) []
92    ],
93    FIFOTHR [
94        FIFORTHR OFFSET(0) NUMBITS(6) [],
95        FIFOWTHR OFFSET(8) NUMBITS(6) []
96    ],
97    FIFOPOP [
98        FIFODOUT OFFSET(0) NUMBITS(32) []
99    ],
100    FIFOPUSH [
101        FIFODIN OFFSET(0) NUMBITS(32) []
102    ],
103    FIFOCTRL [
104        POPWR OFFSET(0) NUMBITS(1) [],
105        FIFORSTN OFFSET(1) NUMBITS(1) []
106    ],
107    FIFOLOC [
108        FIFOWPTR OFFSET(0) NUMBITS(4) [],
109        FIFORPTR OFFSET(8) NUMBITS(4) []
110    ],
111    INT [
112        CMDCMP OFFSET(0) NUMBITS(1) [],
113        THR OFFSET(1) NUMBITS(1) [],
114        FUNDFL OFFSET(2) NUMBITS(1) [],
115        FOVFL OFFSET(3) NUMBITS(1) [],
116        NAK OFFSET(4) NUMBITS(1) [],
117        IACC OFFSET(5) NUMBITS(1) [],
118        ICMD OFFSET(6) NUMBITS(1) [],
119        START OFFSET(7) NUMBITS(1) [],
120        STOP OFFSET(8) NUMBITS(1) [],
121        ARB OFFSET(9) NUMBITS(1) [],
122        DCMP OFFSET(10) NUMBITS(1) [],
123        DERR OFFSET(11) NUMBITS(1) [],
124        CQPAUSED OFFSET(12) NUMBITS(1) [],
125        CQUPD OFFSET(13) NUMBITS(1) [],
126        CQERR OFFSET(14) NUMBITS(1) []
127    ],
128    CLKCFG [
129        IOCLKEN OFFSET(0) NUMBITS(1) [],
130        FSEL OFFSET(8) NUMBITS(3) [],
131        DIV3 OFFSET(11) NUMBITS(1) [],
132        DIVEN OFFSET(12) NUMBITS(1) [],
133        LOWPER OFFSET(16) NUMBITS(8) [],
134        TOTPER OFFSET(24) NUMBITS(8) []
135    ],
136    SUBMODCTRL [
137        SMOD0EN OFFSET(0) NUMBITS(1) [],
138        SMOD0TYPE OFFSET(1) NUMBITS(3) [],
139        SMOD1EN OFFSET(4) NUMBITS(1) [],
140        SMOD1TYPE OFFSET(5) NUMBITS(3) []
141    ],
142    CMD [
143        CMD OFFSET(0) NUMBITS(4) [
144            WRITE = 0x1,
145            READ = 0x2,
146            TMW = 0x3,
147            TMR = 0x4
148        ],
149        OFFSETCNT OFFSET(5) NUMBITS(2) [],
150        CONT OFFSET(7) NUMBITS(1) [],
151        TSIZE OFFSET(8) NUMBITS(12) [],
152        CMDSEL OFFSET(20) NUMBITS(2) [],
153        OFFSETLO OFFSET(24) NUMBITS(8) []
154    ],
155    DCX [
156        CE0OUT OFFSET(0) NUMBITS(1) [],
157        CE1OUT OFFSET(1) NUMBITS(1) [],
158        CE2OUT OFFSET(2) NUMBITS(1) [],
159        DCXEN OFFSET(4) NUMBITS(1) []
160    ],
161    OFFSETHI [
162        OFFSETHI OFFSET(0) NUMBITS(16) []
163    ],
164    CMDSTAT [
165        CCMD OFFSET(0) NUMBITS(4) [],
166        CMDSTAT OFFSET(5) NUMBITS(4) [],
167        CTSIZE OFFSET(8) NUMBITS(12) []
168    ],
169    DMATRIGEN [
170        DCMDCMPEN OFFSET(0) NUMBITS(1) [],
171        DTHREN OFFSET(1) NUMBITS(1) []
172    ],
173    DMATRIGSTAT [
174        DCMDCMP OFFSET(0) NUMBITS(1) [],
175        DTHR OFFSET(1) NUMBITS(1) [],
176        DTOTCMP OFFSET(2) NUMBITS(1) []
177    ],
178    DMACFG [
179        DMAEN OFFSET(0) NUMBITS(1) [],
180        DMADIR OFFSET(1) NUMBITS(1) [],
181        DMAPRI OFFSET(8) NUMBITS(1) [],
182        DPWROFF OFFSET(9) NUMBITS(1) []
183    ],
184    DMATOTCOUNT [
185        TOTCOUNT OFFSET(0) NUMBITS(12) []
186    ],
187    DMATARGADDR [
188        TARGADDR OFFSET(0) NUMBITS(21) [],
189        TARGADDR28 OFFSET(28) NUMBITS(1) []
190    ],
191    DMASTAT [
192        DMATIP OFFSET(0) NUMBITS(1) [],
193        DMACPL OFFSET(1) NUMBITS(1) [],
194        DMAERR OFFSET(2) NUMBITS(1) []
195    ],
196    CQCFG [
197        CQEN OFFSET(0) NUMBITS(1) [],
198        CQPRI OFFSET(1) NUMBITS(1) [],
199        MSPIFLGSEL OFFSET(2) NUMBITS(2) []
200    ],
201    CQADDR [
202        CQADDR OFFSET(2) NUMBITS(19) [],
203        CQADDR28 OFFSET(28) NUMBITS(1) []
204    ],
205    CQSTAT [
206        CQTIP OFFSET(0) NUMBITS(1) [],
207        CQPAUSED OFFSET(1) NUMBITS(1) [],
208        CQERR OFFSET(2) NUMBITS(1) []
209    ],
210    CQFLAGS [
211        CQFLAGS OFFSET(0) NUMBITS(16) [],
212        CQIRQMASK OFFSET(16) NUMBITS(16) []
213    ],
214    CQSETCLEAR [
215        CQFSET OFFSET(0) NUMBITS(8) [],
216        CQFTGL OFFSET(8) NUMBITS(8) [],
217        CQFCLR OFFSET(16) NUMBITS(8) []
218    ],
219    CQPAUSEEN [
220        CQPEN OFFSET(0) NUMBITS(16) []
221    ],
222    CQCURIDX [
223        CQCURIDX OFFSET(0) NUMBITS(8) []
224    ],
225    CQENDIDX [
226        CQENDIDX OFFSET(0) NUMBITS(8) []
227    ],
228    STATUS [
229        ERR OFFSET(0) NUMBITS(1) [],
230        CMDACT OFFSET(1) NUMBITS(2) [],
231        IDLESET OFFSET(2) NUMBITS(1) []
232    ],
233    MSPICFG [
234        SPOL OFFSET(0) NUMBITS(1) [],
235        SPHA OFFSET(1) NUMBITS(1) [],
236        FULLDUP OFFSET(2) NUMBITS(1) [],
237        WTFC OFFSET(16) NUMBITS(1) [],
238        RDFC OFFSET(17) NUMBITS(1) [],
239        MOSIINV OFFSET(18) NUMBITS(1) [],
240        WTFCIRQ OFFSET(20) NUMBITS(1) [],
241        WTFCPOL OFFSET(21) NUMBITS(1) [],
242        RDFCPOL OFFSET(22) NUMBITS(1) [],
243        SPILSB OFFSET(23) NUMBITS(1) [],
244        DINDLY OFFSET(24) NUMBITS(3) [],
245        DOUTDLY OFFSET(27) NUMBITS(3) [],
246        MSPIRST OFFSET(30) NUMBITS(1) []
247    ],
248    MI2CCFG [
249        ADDRSZ OFFSET(0) NUMBITS(1) [],
250        IOMLSB OFFSET(1) NUMBITS(1) [],
251        ARBEN OFFSET(2) NUMBITS(1) [],
252        SDADLY OFFSET(4) NUMBITS(2) [],
253        MI2CRST OFFSET(6) NUMBITS(1) [],
254        SCLENDLY OFFSET(8) NUMBITS(3) [],
255        SDAENDLY OFFSET(12) NUMBITS(3) [],
256        SMPCNT OFFSET(16) NUMBITS(8) [],
257        STRDIS OFFSET(24) NUMBITS(1) []
258    ],
259    DEVCFG [
260        DEVADDR OFFSET(0) NUMBITS(10) []
261    ],
262    IOMDBG [
263        DBGEN OFFSET(0) NUMBITS(1) [],
264        IOCLKON OFFSET(1) NUMBITS(1) [],
265        APBCLKON OFFSET(2) NUMBITS(1) [],
266        DBGDATA OFFSET(3) NUMBITS(29) []
267    ]
268];
269
270#[derive(Clone, Copy, PartialEq, Debug)]
271enum Operation {
272    None,
273    I2C,
274    SPI,
275}
276
277pub struct Iom<'a> {
278    registers: StaticRef<IomRegisters>,
279
280    i2c_master_client: OptionalCell<&'a dyn hil::i2c::I2CHwMasterClient>,
281    spi_master_client: OptionalCell<&'a dyn SpiMasterClient>,
282
283    buffer: MapCell<SubSliceMut<'static, u8>>,
284    spi_read_buffer: MapCell<SubSliceMut<'static, u8>>,
285    write_len: Cell<usize>,
286    write_index: Cell<usize>,
287
288    read_len: Cell<usize>,
289    read_index: Cell<usize>,
290
291    op: Cell<Operation>,
292    spi_phase: Cell<ClockPhase>,
293    spi_cs: OptionalCell<ChipSelectPolar<'a, crate::gpio::GpioPin<'a>>>,
294    smbus: Cell<bool>,
295}
296
297impl<'a> Iom<'_> {
298    pub fn new0() -> Iom<'a> {
299        Iom {
300            registers: IOM0_BASE,
301            i2c_master_client: OptionalCell::empty(),
302            spi_master_client: OptionalCell::empty(),
303            buffer: MapCell::empty(),
304            spi_read_buffer: MapCell::empty(),
305            write_len: Cell::new(0),
306            write_index: Cell::new(0),
307            read_len: Cell::new(0),
308            read_index: Cell::new(0),
309            op: Cell::new(Operation::None),
310            spi_phase: Cell::new(ClockPhase::SampleLeading),
311            spi_cs: OptionalCell::empty(),
312            smbus: Cell::new(false),
313        }
314    }
315    pub fn new1() -> Iom<'a> {
316        Iom {
317            registers: IOM1_BASE,
318            i2c_master_client: OptionalCell::empty(),
319            spi_master_client: OptionalCell::empty(),
320            buffer: MapCell::empty(),
321            spi_read_buffer: MapCell::empty(),
322            write_len: Cell::new(0),
323            write_index: Cell::new(0),
324            read_len: Cell::new(0),
325            read_index: Cell::new(0),
326            op: Cell::new(Operation::None),
327            spi_phase: Cell::new(ClockPhase::SampleLeading),
328            spi_cs: OptionalCell::empty(),
329            smbus: Cell::new(false),
330        }
331    }
332    pub fn new2() -> Iom<'a> {
333        Iom {
334            registers: IOM2_BASE,
335            i2c_master_client: OptionalCell::empty(),
336            spi_master_client: OptionalCell::empty(),
337            buffer: MapCell::empty(),
338            spi_read_buffer: MapCell::empty(),
339            write_len: Cell::new(0),
340            write_index: Cell::new(0),
341            read_len: Cell::new(0),
342            read_index: Cell::new(0),
343            op: Cell::new(Operation::None),
344            spi_phase: Cell::new(ClockPhase::SampleLeading),
345            spi_cs: OptionalCell::empty(),
346            smbus: Cell::new(false),
347        }
348    }
349    pub fn new3() -> Iom<'a> {
350        Iom {
351            registers: IOM3_BASE,
352            i2c_master_client: OptionalCell::empty(),
353            spi_master_client: OptionalCell::empty(),
354            buffer: MapCell::empty(),
355            spi_read_buffer: MapCell::empty(),
356            write_len: Cell::new(0),
357            write_index: Cell::new(0),
358            read_len: Cell::new(0),
359            read_index: Cell::new(0),
360            op: Cell::new(Operation::None),
361            spi_phase: Cell::new(ClockPhase::SampleLeading),
362            spi_cs: OptionalCell::empty(),
363            smbus: Cell::new(false),
364        }
365    }
366    pub fn new4() -> Iom<'a> {
367        Iom {
368            registers: IOM4_BASE,
369            i2c_master_client: OptionalCell::empty(),
370            spi_master_client: OptionalCell::empty(),
371            buffer: MapCell::empty(),
372            spi_read_buffer: MapCell::empty(),
373            write_len: Cell::new(0),
374            write_index: Cell::new(0),
375            read_len: Cell::new(0),
376            read_index: Cell::new(0),
377            op: Cell::new(Operation::None),
378            spi_phase: Cell::new(ClockPhase::SampleLeading),
379            spi_cs: OptionalCell::empty(),
380            smbus: Cell::new(false),
381        }
382    }
383    pub fn new5() -> Iom<'a> {
384        Iom {
385            registers: IOM5_BASE,
386            i2c_master_client: OptionalCell::empty(),
387            spi_master_client: OptionalCell::empty(),
388            buffer: MapCell::empty(),
389            spi_read_buffer: MapCell::empty(),
390            write_len: Cell::new(0),
391            write_index: Cell::new(0),
392            read_len: Cell::new(0),
393            read_index: Cell::new(0),
394            op: Cell::new(Operation::None),
395            spi_phase: Cell::new(ClockPhase::SampleLeading),
396            spi_cs: OptionalCell::empty(),
397            smbus: Cell::new(false),
398        }
399    }
400
401    fn i2c_reset_fifo(&self) {
402        let regs = self.registers;
403
404        // Set the value low to reset
405        regs.fifoctrl.modify(FIFOCTRL::FIFORSTN::CLEAR);
406
407        // Wait a few cycles to ensure the reset completes
408        for _i in 0..30 {
409            cortexm4f::support::nop();
410        }
411
412        // Exit the reset state
413        regs.fifoctrl.modify(FIFOCTRL::FIFORSTN::SET);
414    }
415
416    /// The IOM has a few erratas when used in FIFO mode (as we do here).
417    /// See: <https://ambiq.com/wp-content/uploads/2022/01/Apollo3-Blue-Errata-List.pdf>
418    ///
419    /// ERR009 means that we might get a THR interrupt incorrectly, it also
420    /// appears that the FIFOxSIZ fields are a little slow to update, so even
421    /// if we check the fields, they contain the wrong information.
422    ///
423    /// Adding a small delay here is enough to ensure the fifoptr values update
424    /// before the next iteration. This value is mostly arbitrary, but the
425    /// current value seems to work reliably.
426    fn iom_fifo_errata_delay(&self) {
427        for _i in 0..3000 {
428            cortexm4f::support::nop();
429        }
430    }
431
432    fn i2c_write_data(&self) {
433        let regs = self.registers;
434        let mut data_pushed = self.write_index.get();
435        let len = self.write_len.get();
436
437        if data_pushed == len {
438            return;
439        }
440
441        self.buffer.map(|buf| {
442            // Push some data to FIFO
443            for i in (data_pushed / 4)..(len / 4) {
444                let data_idx = i * 4;
445
446                if regs.fifoptr.read(FIFOPTR::FIFO0REM) <= 4 {
447                    self.write_index.set(data_pushed);
448                    break;
449                }
450
451                let mut d = (buf[data_idx + 0] as u32) << 0;
452                d |= (buf[data_idx + 1] as u32) << 8;
453                d |= (buf[data_idx + 2] as u32) << 16;
454                d |= (buf[data_idx + 3] as u32) << 24;
455
456                regs.fifopush.set(d);
457
458                data_pushed = data_idx + 4;
459            }
460
461            // We never filled up the FIFO
462            if len < 4 || data_pushed > (len - 4) {
463                // Check if we have any left over data
464                if len % 4 == 1 {
465                    let d = buf[len - 1] as u32;
466
467                    regs.fifopush.set(d);
468                } else if len % 4 == 2 {
469                    let mut d = (buf[len - 1] as u32) << 8;
470                    d |= (buf[len - 2] as u32) << 0;
471
472                    regs.fifopush.set(d);
473                } else if len % 4 == 3 {
474                    let mut d = (buf[len - 1] as u32) << 16;
475                    d |= (buf[len - 2] as u32) << 8;
476                    d |= (buf[len - 3] as u32) << 0;
477
478                    regs.fifopush.set(d);
479                }
480                self.write_index.set(len);
481            }
482        });
483    }
484
485    fn i2c_read_data(&self) {
486        let regs = self.registers;
487        let mut data_popped = self.read_index.get();
488        let len = self.read_len.get();
489
490        if data_popped == len {
491            return;
492        }
493
494        self.buffer.map(|buf| {
495            // Pop some data from the FIFO
496            for i in (data_popped / 4)..(len / 4) {
497                let data_idx = i * 4;
498
499                self.iom_fifo_errata_delay();
500
501                if regs.fifoptr.read(FIFOPTR::FIFO1SIZ) < 4 {
502                    self.read_index.set(data_popped);
503                    break;
504                }
505
506                let d = regs.fifopop.get().to_ne_bytes();
507
508                buf[data_idx + 0] = d[0];
509                buf[data_idx + 1] = d[1];
510                buf[data_idx + 2] = d[2];
511                buf[data_idx + 3] = d[3];
512
513                data_popped = data_idx + 4;
514            }
515
516            // Get remaining data that isn't 4 bytes long
517            if len < 4 || data_popped > (len - 4) {
518                self.iom_fifo_errata_delay();
519
520                // Check if we have any left over data
521                if len % 4 == 1 {
522                    let d = regs.fifopop.get().to_ne_bytes();
523
524                    buf[len - 1] = d[0];
525                } else if len % 4 == 2 {
526                    let d = regs.fifopop.get().to_ne_bytes();
527
528                    buf[len - 2] = d[0];
529                    buf[len - 1] = d[1];
530                } else if len % 4 == 3 {
531                    let d = regs.fifopop.get().to_ne_bytes();
532
533                    buf[len - 3] = d[0];
534                    buf[len - 2] = d[1];
535                    buf[len - 1] = d[2];
536                }
537                self.read_index.set(len);
538            }
539        });
540    }
541
542    pub fn handle_interrupt(&self) {
543        let regs = self.registers;
544        let irqs = regs.intstat.extract();
545
546        // Clear interrrupts
547        regs.intclr.set(0xFFFF_FFFF);
548        // Ensure interrupts remain enabled
549        regs.inten.set(0xFFFF_FFFF);
550
551        if irqs.is_set(INT::NAK) {
552            if self.op.get() == Operation::I2C {
553                // Disable interrupts
554                regs.inten.set(0x00);
555                self.i2c_reset_fifo();
556
557                self.i2c_master_client.map(|client| {
558                    self.buffer.take().map(|buffer| {
559                        client.command_complete(buffer.take(), Err(i2c::Error::DataNak));
560                    });
561                });
562
563                // Finished with SMBus
564                if self.smbus.get() {
565                    // Setup 400kHz
566                    regs.clkcfg.write(
567                        CLKCFG::TOTPER.val(0x1D)
568                            + CLKCFG::LOWPER.val(0xE)
569                            + CLKCFG::DIVEN.val(1)
570                            + CLKCFG::DIV3.val(0)
571                            + CLKCFG::FSEL.val(2)
572                            + CLKCFG::IOCLKEN::SET,
573                    );
574
575                    self.smbus.set(false);
576                }
577            } else {
578                // Disable interrupts
579                regs.inten.set(0x00);
580
581                // Clear CS
582                self.spi_cs.map(|cs| cs.deactivate());
583
584                self.op.set(Operation::None);
585
586                self.spi_master_client.map(|client| {
587                    self.buffer.take().map(|buffer| {
588                        let read_buffer = self.spi_read_buffer.take();
589                        client.read_write_done(buffer, read_buffer, Err(ErrorCode::NOACK));
590                    });
591                });
592            }
593            return;
594        }
595
596        if self.op.get() == Operation::SPI {
597            // Read the incoming data
598            if let Some(mut buf) = self.spi_read_buffer.take() {
599                while self.registers.fifoptr.read(FIFOPTR::FIFO1SIZ) > 0 {
600                    self.iom_fifo_errata_delay();
601
602                    let d = self.registers.fifopop.get().to_ne_bytes();
603                    let data_idx = self.read_index.get();
604
605                    if let Some(b) = buf.as_slice().get_mut(data_idx + 0) {
606                        *b = d[0];
607                        self.read_index.set(data_idx + 1);
608                    }
609                    if let Some(b) = buf.as_slice().get_mut(data_idx + 1) {
610                        *b = d[1];
611                        self.read_index.set(data_idx + 2);
612                    }
613                    if let Some(b) = buf.as_slice().get_mut(data_idx + 2) {
614                        *b = d[2];
615                        self.read_index.set(data_idx + 3);
616                    }
617                    if let Some(b) = buf.as_slice().get_mut(data_idx + 3) {
618                        *b = d[3];
619                        self.read_index.set(data_idx + 4);
620                    }
621                }
622
623                self.spi_read_buffer.replace(buf);
624
625                if self.read_len.get() > self.read_index.get() {
626                    let remaining_bytes = (self.read_len.get() - self.read_index.get()).min(32);
627                    self.registers
628                        .fifothr
629                        .modify(FIFOTHR::FIFORTHR.val(remaining_bytes as u32));
630                } else {
631                    self.registers.fifothr.modify(FIFOTHR::FIFORTHR.val(0));
632                }
633            } else {
634                while self.registers.fifoptr.read(FIFOPTR::FIFO1SIZ) > 0 {
635                    self.iom_fifo_errata_delay();
636
637                    let _d = self.registers.fifopop.get().to_ne_bytes();
638                }
639
640                self.registers.fifothr.modify(FIFOTHR::FIFORTHR.val(0));
641            }
642
643            // Write more data out
644            if self.write_index.get() < self.write_len.get() {
645                if let Some(write_buffer) = self.buffer.take() {
646                    let mut transfered_bytes = 0;
647
648                    // While there is some free space in FIFO0 (writing to the SPI bus) and
649                    // at least 4 bytes free in FIFO1 (reading from the SPI bus to the
650                    // hardware FIFO) we write up to 24 bytes of data.
651                    //
652                    // The `> 4` really could be `>= 4` but > gives us a little wiggle room
653                    // as the hardware does seem a little slow at updating the FIFO size
654                    // registers.
655                    //
656                    // The 24 byte limit is along the same lines, of just making sure we
657                    // don't write too much data. I don't have a good answer of why it should
658                    // be 24, but that seems to work reliably from testing.
659                    //
660                    // There isn't a specific errata for this issue, but the official HAL
661                    // uses DMA so there aren't a lot of FIFO users for large transfers like
662                    // this.
663                    while self.registers.fifoptr.read(FIFOPTR::FIFO0REM) > 0
664                        && self.registers.fifoptr.read(FIFOPTR::FIFO1REM) > 4
665                        && self.write_index.get() < self.write_len.get()
666                        && transfered_bytes < 24
667                    {
668                        let idx = self.write_index.get();
669
670                        let chunk = write_buffer[idx..].chunks(4).next().unwrap_or(&[]);
671
672                        let data = u32::from_le_bytes([
673                            chunk.get(0).copied().unwrap_or(0),
674                            chunk.get(1).copied().unwrap_or(0),
675                            chunk.get(2).copied().unwrap_or(0),
676                            chunk.get(3).copied().unwrap_or(0),
677                        ]);
678
679                        self.registers.fifopush.set(data);
680                        self.write_index.set(idx + 4);
681                        transfered_bytes += 4;
682                    }
683
684                    self.buffer.replace(write_buffer);
685                }
686
687                let remaining_bytes = (self.write_len.get() - self.write_index.get()).min(32);
688                self.registers
689                    .fifothr
690                    .modify(FIFOTHR::FIFOWTHR.val(remaining_bytes as u32));
691            } else {
692                self.registers.fifothr.modify(FIFOTHR::FIFOWTHR.val(0));
693            }
694
695            if (self.write_len.get() > 0
696                && self.write_index.get() >= self.write_len.get()
697                && self.read_len.get() > 0
698                && self.read_index.get() >= self.read_len.get())
699                || irqs.is_set(INT::CMDCMP)
700            {
701                // Disable interrupts
702                regs.inten.set(0x00);
703
704                // Clear CS
705                self.spi_cs.map(|cs| cs.deactivate());
706
707                self.op.set(Operation::None);
708
709                self.spi_master_client.map(|client| {
710                    self.buffer.take().map(|buffer| {
711                        let read_buffer = self.spi_read_buffer.take();
712                        client.read_write_done(buffer, read_buffer, Ok(self.write_len.get()));
713                    });
714                });
715            }
716
717            return;
718        }
719
720        if irqs.is_set(INT::CMDCMP) || irqs.is_set(INT::THR) {
721            if self.op.get() == Operation::I2C {
722                if irqs.is_set(INT::THR) {
723                    if regs.fifothr.read(FIFOTHR::FIFOWTHR) > 0 {
724                        let remaining = self.write_len.get() - self.write_index.get();
725
726                        if remaining > 4 {
727                            regs.fifothr.write(
728                                FIFOTHR::FIFORTHR.val(0)
729                                    + FIFOTHR::FIFOWTHR.val(remaining as u32 / 2),
730                            );
731                        } else {
732                            regs.fifothr
733                                .write(FIFOTHR::FIFORTHR.val(0) + FIFOTHR::FIFOWTHR.val(1));
734                        }
735
736                        self.i2c_write_data();
737                    } else if regs.fifothr.read(FIFOTHR::FIFORTHR) > 0 {
738                        let remaining = self.read_len.get() - self.read_index.get();
739
740                        if remaining > 4 {
741                            regs.fifothr.write(
742                                FIFOTHR::FIFORTHR.val(remaining as u32 / 2)
743                                    + FIFOTHR::FIFOWTHR.val(0),
744                            );
745                        } else {
746                            regs.fifothr
747                                .write(FIFOTHR::FIFORTHR.val(1) + FIFOTHR::FIFOWTHR.val(0));
748                        }
749
750                        self.i2c_read_data();
751                    }
752                }
753
754                if irqs.is_set(INT::CMDCMP) {
755                    if (self.read_len.get() > 0 && self.read_index.get() == self.read_len.get())
756                        || (self.write_len.get() > 0
757                            && self.write_index.get() == self.write_len.get())
758                    {
759                        // Disable interrupts
760                        regs.inten.set(0x00);
761                        self.i2c_reset_fifo();
762
763                        self.i2c_master_client.map(|client| {
764                            self.buffer.take().map(|buffer| {
765                                client.command_complete(buffer.take(), Ok(()));
766                            });
767                        });
768
769                        // Finished with SMBus
770                        if self.smbus.get() {
771                            // Setup 400kHz
772                            regs.clkcfg.write(
773                                CLKCFG::TOTPER.val(0x1D)
774                                    + CLKCFG::LOWPER.val(0xE)
775                                    + CLKCFG::DIVEN.val(1)
776                                    + CLKCFG::DIV3.val(0)
777                                    + CLKCFG::FSEL.val(2)
778                                    + CLKCFG::IOCLKEN::SET,
779                            );
780
781                            self.smbus.set(false);
782                        }
783                    }
784                }
785            } else {
786                self.buffer.take().map(|write_buffer| {
787                    let offset = self.write_index.get();
788                    if self.write_len.get() > offset {
789                        let burst_len = (self.write_len.get() - offset)
790                            .min(self.registers.fifoptr.read(FIFOPTR::FIFO0REM) as usize);
791
792                        // Start the transfer
793                        self.registers.cmd.write(
794                            CMD::TSIZE.val(burst_len as u32)
795                                + CMD::CMDSEL.val(1)
796                                + CMD::CONT::CLEAR
797                                + CMD::CMD::WRITE
798                                + CMD::OFFSETCNT.val(0_u32)
799                                + CMD::OFFSETLO.val(0),
800                        );
801
802                        while self.registers.fifoptr.read(FIFOPTR::FIFO0REM) > 4
803                            && self.registers.fifoptr.read(FIFOPTR::FIFO1SIZ) < 32
804                            && self.write_index.get() < (((offset + burst_len) / 4) * 4)
805                            && self.write_len.get() - self.write_index.get() > 4
806                        {
807                            let idx = self.write_index.get();
808                            let data = u32::from_le_bytes(
809                                write_buffer[idx..(idx + 4)].try_into().unwrap_or([0; 4]),
810                            );
811
812                            self.registers.fifopush.set(data);
813                            self.write_index.set(idx + 4);
814                        }
815
816                        // Get remaining data that isn't 4 bytes long
817                        if self.write_len.get() - self.write_index.get() < 4
818                            && self.write_index.get() < (offset + burst_len)
819                        {
820                            let len = self.write_len.get() - self.write_index.get();
821                            let mut buf = [0; 4];
822                            // Check if we have any left over data
823                            if len % 4 == 1 {
824                                buf[len - 1] = write_buffer[self.write_index.get() + 0];
825                            } else if len % 4 == 2 {
826                                buf[len - 2] = write_buffer[self.write_index.get() + 0];
827                                buf[len - 1] = write_buffer[self.write_index.get() + 1];
828                            } else if len % 4 == 3 {
829                                buf[len - 3] = write_buffer[self.write_index.get() + 0];
830                                buf[len - 2] = write_buffer[self.write_index.get() + 1];
831                                buf[len - 1] = write_buffer[self.write_index.get() + 2];
832                            }
833                            self.registers.fifopush.set(u32::from_le_bytes(buf));
834                            self.write_index.set(self.write_index.get() + len);
835                        }
836                    }
837
838                    self.buffer.replace(write_buffer);
839                });
840            }
841        }
842    }
843
844    fn i2c_tx_rx(
845        &self,
846        addr: u8,
847        data: &'static mut [u8],
848        write_len: usize,
849        read_len: usize,
850    ) -> Result<(), (i2c::Error, &'static mut [u8])> {
851        let regs = self.registers;
852        let mut offsetlo = 0;
853
854        // Disable DMA as we don't support it
855        regs.dmacfg.write(DMACFG::DMAEN::CLEAR);
856
857        // Set the address
858        regs.devcfg.write(DEVCFG::DEVADDR.val(addr as u32));
859
860        // Set the DCX
861        regs.dcx.set(0);
862
863        // Set the read FIFO threashold and disable the write
864        if read_len > 4 {
865            regs.fifothr
866                .write(FIFOTHR::FIFORTHR.val(read_len as u32 / 2) + FIFOTHR::FIFOWTHR.val(0));
867        } else {
868            regs.fifothr
869                .write(FIFOTHR::FIFORTHR.val(1) + FIFOTHR::FIFOWTHR.val(0));
870        }
871
872        self.i2c_reset_fifo();
873
874        if write_len > 0 {
875            offsetlo = data[0] as u32;
876        }
877
878        if write_len == 2 {
879            regs.offsethi.set(data[1] as u32);
880        } else if write_len == 3 {
881            regs.offsethi.set(data[1] as u32 | ((data[2] as u32) << 8));
882        }
883
884        if write_len > 3 {
885            Err((i2c::Error::NotSupported, data))
886        } else {
887            // Save all the data and offsets we still need to send
888            self.buffer.replace(data.into());
889            self.write_len.set(write_len);
890            self.read_len.set(read_len);
891            self.write_index.set(0);
892            self.read_index.set(0);
893            // Clear and enable interrupts
894            regs.intclr.set(0xFFFF_FFFF);
895            regs.inten.set(0xFFFF_FFFF);
896
897            // Start the transfer
898            regs.cmd.write(
899                CMD::TSIZE.val(read_len as u32)
900                    + CMD::CMD::READ
901                    + CMD::OFFSETCNT.val(write_len as u32)
902                    + CMD::OFFSETLO.val(offsetlo),
903            );
904
905            Ok(())
906        }
907    }
908
909    fn i2c_tx(
910        &self,
911        addr: u8,
912        data: &'static mut [u8],
913        len: usize,
914    ) -> Result<(), (i2c::Error, &'static mut [u8])> {
915        let regs = self.registers;
916
917        // Disable DMA as we don't support it
918        regs.dmacfg.write(DMACFG::DMAEN::CLEAR);
919
920        // Set the address
921        regs.devcfg.write(DEVCFG::DEVADDR.val(addr as u32));
922
923        // Set the DCX
924        regs.dcx.set(0);
925
926        // Set the write FIFO threashold and disable the read
927        if len > 4 {
928            regs.fifothr
929                .write(FIFOTHR::FIFORTHR.val(0) + FIFOTHR::FIFOWTHR.val(len as u32 / 2));
930        } else {
931            regs.fifothr
932                .write(FIFOTHR::FIFORTHR.val(0) + FIFOTHR::FIFOWTHR.val(1));
933        }
934
935        self.i2c_reset_fifo();
936
937        // Save all the data and offsets we still need to send
938        self.buffer.replace(data.into());
939        self.write_len.set(len);
940        self.read_len.set(0);
941        self.write_index.set(0);
942
943        self.i2c_write_data();
944
945        // Clear and enable interrupts
946        regs.intclr.set(0xFFFF_FFFF);
947        regs.inten.set(0xFFFF_FFFF);
948
949        // Start the transfer
950        regs.cmd
951            .write(CMD::TSIZE.val(len as u32) + CMD::CMD::WRITE + CMD::CONT::CLEAR);
952        Ok(())
953    }
954
955    fn i2c_rx(
956        &self,
957        addr: u8,
958        buffer: &'static mut [u8],
959        len: usize,
960    ) -> Result<(), (i2c::Error, &'static mut [u8])> {
961        let regs = self.registers;
962
963        // Disable DMA as we don't support it
964        regs.dmacfg.modify(DMACFG::DMAEN::CLEAR);
965
966        // Set the address
967        regs.devcfg.write(DEVCFG::DEVADDR.val(addr as u32));
968
969        // Set the DCX
970        regs.dcx.set(0);
971
972        // Set the read FIFO threashold and disable the write
973        if len > 4 {
974            regs.fifothr
975                .write(FIFOTHR::FIFORTHR.val(len as u32 / 2) + FIFOTHR::FIFOWTHR.val(0));
976        } else {
977            regs.fifothr
978                .write(FIFOTHR::FIFORTHR.val(1) + FIFOTHR::FIFOWTHR.val(0));
979        }
980
981        self.i2c_reset_fifo();
982
983        // Clear and enable interrupts
984        regs.intclr.set(0xFFFF_FFFF);
985        regs.inten.set(0xFFFF_FFFF);
986
987        // Start the transfer
988        regs.cmd
989            .write(CMD::TSIZE.val(len as u32) + CMD::CMD::READ + CMD::CONT::CLEAR);
990
991        // Save all the data and offsets we still need to send
992        self.buffer.replace(buffer.into());
993        self.read_len.set(len);
994        self.write_len.set(0);
995        self.read_index.set(0);
996
997        self.i2c_read_data();
998
999        Ok(())
1000    }
1001}
1002
1003impl<'a> hil::i2c::I2CMaster<'a> for Iom<'a> {
1004    fn set_master_client(&self, i2c_master_client: &'a dyn i2c::I2CHwMasterClient) {
1005        self.i2c_master_client.set(i2c_master_client);
1006    }
1007
1008    fn enable(&self) {
1009        let regs = self.registers;
1010
1011        self.op.set(Operation::I2C);
1012
1013        // Setup the I2C
1014        regs.mi2ccfg.write(
1015            MI2CCFG::STRDIS.val(0)
1016                + MI2CCFG::SMPCNT.val(3)
1017                + MI2CCFG::SDAENDLY.val(15)
1018                + MI2CCFG::SCLENDLY.val(2)
1019                + MI2CCFG::SDADLY.val(3)
1020                + MI2CCFG::ARBEN::SET
1021                + MI2CCFG::IOMLSB::CLEAR
1022                + MI2CCFG::ADDRSZ::CLEAR,
1023        );
1024
1025        // Setup 400kHz
1026        regs.clkcfg.write(
1027            CLKCFG::TOTPER.val(0x1D)
1028                + CLKCFG::LOWPER.val(0xE)
1029                + CLKCFG::DIVEN.val(1)
1030                + CLKCFG::DIV3.val(0)
1031                + CLKCFG::FSEL.val(2)
1032                + CLKCFG::IOCLKEN::SET,
1033        );
1034
1035        // Enable I2C
1036        regs.submodctrl.write(SUBMODCTRL::SMOD1EN::SET);
1037
1038        // Disable command queue
1039        regs.cqcfg.modify(CQCFG::CQEN::CLEAR);
1040    }
1041
1042    fn disable(&self) {
1043        let regs = self.registers;
1044
1045        if self.op.get() == Operation::I2C {
1046            regs.submodctrl.write(SUBMODCTRL::SMOD1EN::CLEAR);
1047
1048            self.op.set(Operation::None);
1049        }
1050    }
1051
1052    fn write_read(
1053        &self,
1054        addr: u8,
1055        data: &'static mut [u8],
1056        write_len: usize,
1057        read_len: usize,
1058    ) -> Result<(), (hil::i2c::Error, &'static mut [u8])> {
1059        if self.op.get() != Operation::I2C {
1060            return Err((hil::i2c::Error::Busy, data));
1061        }
1062        if data.len() < write_len {
1063            return Err((hil::i2c::Error::Overrun, data));
1064        }
1065        self.i2c_tx_rx(addr, data, write_len, read_len)
1066    }
1067
1068    fn write(
1069        &self,
1070        addr: u8,
1071        data: &'static mut [u8],
1072        len: usize,
1073    ) -> Result<(), (hil::i2c::Error, &'static mut [u8])> {
1074        if self.op.get() != Operation::I2C {
1075            return Err((hil::i2c::Error::Busy, data));
1076        }
1077        if data.len() < len {
1078            return Err((hil::i2c::Error::Overrun, data));
1079        }
1080        self.i2c_tx(addr, data, len)
1081    }
1082
1083    fn read(
1084        &self,
1085        addr: u8,
1086        buffer: &'static mut [u8],
1087        len: usize,
1088    ) -> Result<(), (hil::i2c::Error, &'static mut [u8])> {
1089        if self.op.get() != Operation::I2C {
1090            return Err((hil::i2c::Error::Busy, buffer));
1091        }
1092        if buffer.len() < len {
1093            return Err((hil::i2c::Error::Overrun, buffer));
1094        }
1095        self.i2c_rx(addr, buffer, len)
1096    }
1097}
1098
1099impl<'a> hil::i2c::SMBusMaster<'a> for Iom<'a> {
1100    fn smbus_write_read(
1101        &self,
1102        addr: u8,
1103        data: &'static mut [u8],
1104        write_len: usize,
1105        read_len: usize,
1106    ) -> Result<(), (hil::i2c::Error, &'static mut [u8])> {
1107        let regs = self.registers;
1108
1109        if self.op.get() != Operation::I2C {
1110            return Err((hil::i2c::Error::Busy, data));
1111        }
1112
1113        // Setup 100kHz
1114        regs.clkcfg.write(
1115            CLKCFG::TOTPER.val(0x77)
1116                + CLKCFG::LOWPER.val(0x3B)
1117                + CLKCFG::DIVEN.val(1)
1118                + CLKCFG::DIV3.val(0)
1119                + CLKCFG::FSEL.val(2)
1120                + CLKCFG::IOCLKEN::SET,
1121        );
1122
1123        self.smbus.set(true);
1124
1125        self.i2c_tx_rx(addr, data, write_len, read_len)
1126    }
1127
1128    fn smbus_write(
1129        &self,
1130        addr: u8,
1131        data: &'static mut [u8],
1132        len: usize,
1133    ) -> Result<(), (hil::i2c::Error, &'static mut [u8])> {
1134        let regs = self.registers;
1135
1136        if self.op.get() != Operation::I2C {
1137            return Err((hil::i2c::Error::Busy, data));
1138        }
1139
1140        // Setup 100kHz
1141        regs.clkcfg.write(
1142            CLKCFG::TOTPER.val(0x77)
1143                + CLKCFG::LOWPER.val(0x3B)
1144                + CLKCFG::DIVEN.val(1)
1145                + CLKCFG::DIV3.val(0)
1146                + CLKCFG::FSEL.val(2)
1147                + CLKCFG::IOCLKEN::SET,
1148        );
1149
1150        self.smbus.set(true);
1151
1152        self.i2c_tx(addr, data, len)
1153    }
1154
1155    fn smbus_read(
1156        &self,
1157        addr: u8,
1158        buffer: &'static mut [u8],
1159        len: usize,
1160    ) -> Result<(), (hil::i2c::Error, &'static mut [u8])> {
1161        let regs = self.registers;
1162
1163        if self.op.get() != Operation::I2C {
1164            return Err((hil::i2c::Error::Busy, buffer));
1165        }
1166
1167        // Setup 100kHz
1168        regs.clkcfg.write(
1169            CLKCFG::TOTPER.val(0x77)
1170                + CLKCFG::LOWPER.val(0x3B)
1171                + CLKCFG::DIVEN.val(1)
1172                + CLKCFG::DIV3.val(0)
1173                + CLKCFG::FSEL.val(2)
1174                + CLKCFG::IOCLKEN::SET,
1175        );
1176
1177        self.smbus.set(true);
1178
1179        self.i2c_rx(addr, buffer, len)
1180    }
1181}
1182
1183impl<'a> SpiMaster<'a> for Iom<'a> {
1184    type ChipSelect = ChipSelectPolar<'a, crate::gpio::GpioPin<'a>>;
1185
1186    fn init(&self) -> Result<(), ErrorCode> {
1187        self.op.set(Operation::SPI);
1188
1189        self.registers.mspicfg.write(
1190            MSPICFG::FULLDUP::SET
1191                + MSPICFG::WTFC::CLEAR
1192                + MSPICFG::RDFC::CLEAR
1193                + MSPICFG::MOSIINV::CLEAR
1194                + MSPICFG::WTFCIRQ::CLEAR
1195                + MSPICFG::WTFCPOL::CLEAR
1196                + MSPICFG::RDFCPOL::CLEAR
1197                + MSPICFG::SPILSB::CLEAR
1198                + MSPICFG::DINDLY::CLEAR
1199                + MSPICFG::DOUTDLY::CLEAR
1200                + MSPICFG::MSPIRST::CLEAR,
1201        );
1202
1203        // Enable SPI
1204        self.registers
1205            .submodctrl
1206            .write(SUBMODCTRL::SMOD1EN::CLEAR + SUBMODCTRL::SMOD0EN::SET);
1207
1208        self.registers.dmatrigen.write(DMATRIGEN::DTHREN::SET);
1209
1210        Ok(())
1211    }
1212
1213    fn set_client(&self, client: &'a dyn SpiMasterClient) {
1214        self.spi_master_client.set(client);
1215    }
1216
1217    fn is_busy(&self) -> bool {
1218        self.op.get() != Operation::None
1219    }
1220
1221    fn read_write_bytes(
1222        &self,
1223        write_buffer: SubSliceMut<'static, u8>,
1224        read_buffer: Option<SubSliceMut<'static, u8>>,
1225    ) -> Result<
1226        (),
1227        (
1228            ErrorCode,
1229            SubSliceMut<'static, u8>,
1230            Option<SubSliceMut<'static, u8>>,
1231        ),
1232    > {
1233        let (write_len, read_len) = if let Some(rb) = read_buffer.as_ref() {
1234            let min = write_buffer.len().min(rb.len());
1235            (min, min)
1236        } else {
1237            (write_buffer.len(), 0)
1238        };
1239
1240        // Disable DMA as we don't support it
1241        self.registers.dmacfg.write(DMACFG::DMAEN::CLEAR);
1242
1243        // Set the DCX
1244        self.registers.dcx.set(0);
1245
1246        self.write_index.set(0);
1247        self.read_index.set(0);
1248
1249        // Clear interrupts
1250        self.registers.intclr.set(0xFFFF_FFFF);
1251
1252        // Trigger CS
1253        self.spi_cs.map(|cs| cs.activate());
1254
1255        // Start the transfer
1256        self.registers.cmd.write(
1257            CMD::TSIZE.val(write_len as u32)
1258                + CMD::CMDSEL.val(1)
1259                + CMD::CONT::CLEAR
1260                + CMD::CMD::WRITE
1261                + CMD::OFFSETCNT.val(0_u32)
1262                + CMD::OFFSETLO.val(0),
1263        );
1264
1265        if let Some(buf) = read_buffer {
1266            self.spi_read_buffer.replace(buf);
1267        }
1268
1269        while self.registers.cmdstat.read(CMDSTAT::CMDSTAT) == 0x02 {}
1270
1271        let mut transfered_bytes = 0;
1272
1273        // While there is some free space in FIFO0 (writing to the SPI bus) and
1274        // at least 4 bytes free in FIFO1 (reading from the SPI bus to the
1275        // hardware FIFO) we write up to 24 bytes of data.
1276        //
1277        // The `> 4` really could be `>= 4` but > gives us a little wiggle room
1278        // as the hardware does seem a little slow at updating the FIFO size
1279        // registers.
1280        //
1281        // The 24 byte limit is along the same lines, of just making sure we
1282        // don't write too much data. I don't have a good answer of why it should
1283        // be 24, but that seems to work reliably from testing.
1284        //
1285        // There isn't a specific errata for this issue, but the official HAL
1286        // uses DMA so there aren't a lot of FIFO users for large transfers like
1287        // this.
1288        while self.registers.fifoptr.read(FIFOPTR::FIFO0REM) > 0
1289            && self.registers.fifoptr.read(FIFOPTR::FIFO1REM) > 4
1290            && self.write_index.get() < write_len
1291            && transfered_bytes < 24
1292        {
1293            let idx = self.write_index.get();
1294
1295            // Caution: This must handle "bytes remaining % 4 != 0" correctly.
1296            let chunk = write_buffer[idx..].chunks(4).next().unwrap_or(&[]);
1297
1298            let data = u32::from_le_bytes([
1299                chunk.get(0).copied().unwrap_or(0),
1300                chunk.get(1).copied().unwrap_or(0),
1301                chunk.get(2).copied().unwrap_or(0),
1302                chunk.get(3).copied().unwrap_or(0),
1303            ]);
1304
1305            self.iom_fifo_errata_delay();
1306
1307            self.registers.fifopush.set(data);
1308            self.write_index.set(idx + 4);
1309            transfered_bytes += 4;
1310
1311            if let Some(mut buf) = self.spi_read_buffer.take() {
1312                if self.registers.fifoptr.read(FIFOPTR::FIFO1SIZ) > 0
1313                    && self.read_index.get() < read_len
1314                {
1315                    let d = self.registers.fifopop.get().to_ne_bytes();
1316
1317                    let data_idx = self.read_index.get();
1318
1319                    buf[data_idx + 0] = d[0];
1320                    buf[data_idx + 1] = d[1];
1321                    buf[data_idx + 2] = d[2];
1322                    buf[data_idx + 3] = d[3];
1323
1324                    self.read_index.set(data_idx + 4);
1325                }
1326
1327                self.spi_read_buffer.replace(buf);
1328            } else {
1329                if self.registers.fifoptr.read(FIFOPTR::FIFO1SIZ) > 0 {
1330                    let _d = self.registers.fifopop.get();
1331                }
1332            }
1333        }
1334
1335        // Save all the data and offsets we still need to send
1336        self.buffer.replace(write_buffer);
1337        self.write_len.set(write_len);
1338        self.read_len.set(read_len);
1339        self.op.set(Operation::SPI);
1340
1341        if read_len > self.read_index.get() {
1342            let remaining_bytes = (read_len - self.read_index.get()).min(32);
1343            self.registers
1344                .fifothr
1345                .modify(FIFOTHR::FIFORTHR.val(remaining_bytes as u32));
1346        } else {
1347            self.registers.fifothr.modify(FIFOTHR::FIFORTHR.val(0));
1348        }
1349
1350        if write_len > self.write_index.get() {
1351            let remaining_bytes = (self.write_len.get() - self.write_index.get()).min(32);
1352
1353            self.registers
1354                .fifothr
1355                .modify(FIFOTHR::FIFOWTHR.val(remaining_bytes as u32));
1356        } else {
1357            self.registers.fifothr.modify(FIFOTHR::FIFOWTHR.val(0));
1358        }
1359
1360        // Enable interrupts
1361        self.registers.inten.set(0xFFFF_FFFF);
1362
1363        Ok(())
1364    }
1365
1366    fn write_byte(&self, val: u8) -> Result<(), ErrorCode> {
1367        let burst_len = 1;
1368
1369        // Disable DMA as we don't support it
1370        self.registers.dmacfg.write(DMACFG::DMAEN::CLEAR);
1371
1372        // Set the DCX
1373        self.registers.dcx.set(0);
1374
1375        // Clear interrupts
1376        self.registers.intclr.set(0xFFFF_FFFF);
1377
1378        // Trigger CS
1379        self.spi_cs.map(|cs| cs.activate());
1380
1381        // Start the transfer
1382        self.registers.cmd.write(
1383            CMD::TSIZE.val(burst_len as u32)
1384                + CMD::CMDSEL.val(1)
1385                + CMD::CONT::CLEAR
1386                + CMD::CMD::WRITE
1387                + CMD::OFFSETCNT.val(0_u32)
1388                + CMD::OFFSETLO.val(0),
1389        );
1390
1391        self.registers.fifopush.set(val as u32);
1392
1393        self.spi_cs.map(|cs| cs.deactivate());
1394
1395        Ok(())
1396    }
1397
1398    fn read_byte(&self) -> Result<u8, ErrorCode> {
1399        let burst_len = 1;
1400
1401        // Disable DMA as we don't support it
1402        self.registers.dmacfg.write(DMACFG::DMAEN::CLEAR);
1403
1404        // Set the DCX
1405        self.registers.dcx.set(0);
1406
1407        // Clear interrupts
1408        self.registers.intclr.set(0xFFFF_FFFF);
1409
1410        // Trigger CS
1411        self.spi_cs.map(|cs| cs.activate());
1412
1413        // Start the transfer
1414        self.registers.cmd.write(
1415            CMD::TSIZE.val(burst_len as u32)
1416                + CMD::CMDSEL.val(1)
1417                + CMD::CONT::CLEAR
1418                + CMD::CMD::READ
1419                + CMD::OFFSETCNT.val(0_u32)
1420                + CMD::OFFSETLO.val(0),
1421        );
1422
1423        if self.registers.fifoptr.read(FIFOPTR::FIFO1SIZ) > 0 {
1424            let d = self.registers.fifopop.get().to_ne_bytes();
1425
1426            self.spi_cs.map(|cs| cs.deactivate());
1427            return Ok(d[0]);
1428        }
1429
1430        self.spi_cs.map(|cs| cs.deactivate());
1431
1432        Err(ErrorCode::FAIL)
1433    }
1434
1435    fn read_write_byte(&self, val: u8) -> Result<u8, ErrorCode> {
1436        let burst_len = 1;
1437
1438        // Disable DMA as we don't support it
1439        self.registers.dmacfg.write(DMACFG::DMAEN::CLEAR);
1440
1441        // Set the DCX
1442        self.registers.dcx.set(0);
1443
1444        // Clear interrupts
1445        self.registers.intclr.set(0xFFFF_FFFF);
1446
1447        // Trigger CS
1448        self.spi_cs.map(|cs| cs.activate());
1449
1450        // Start the transfer
1451        self.registers.cmd.write(
1452            CMD::TSIZE.val(burst_len as u32)
1453                + CMD::CMDSEL.val(1)
1454                + CMD::CONT::CLEAR
1455                + CMD::CMD::WRITE
1456                + CMD::OFFSETCNT.val(0_u32)
1457                + CMD::OFFSETLO.val(0),
1458        );
1459
1460        self.registers.fifopush.set(val as u32);
1461
1462        if self.registers.fifoptr.read(FIFOPTR::FIFO1SIZ) > 0 {
1463            let d = self.registers.fifopop.get().to_ne_bytes();
1464
1465            self.spi_cs.map(|cs| cs.deactivate());
1466            return Ok(d[0]);
1467        }
1468
1469        self.spi_cs.map(|cs| cs.deactivate());
1470
1471        Err(ErrorCode::FAIL)
1472    }
1473
1474    fn specify_chip_select(&self, cs: Self::ChipSelect) -> Result<(), ErrorCode> {
1475        cs.pin.make_output();
1476        cs.deactivate();
1477        self.spi_cs.set(cs);
1478
1479        Ok(())
1480    }
1481
1482    fn set_rate(&self, rate: u32) -> Result<u32, ErrorCode> {
1483        if self.op.get() != Operation::SPI && self.op.get() != Operation::None {
1484            return Err(ErrorCode::BUSY);
1485        }
1486
1487        let div: u32 = 48000000 / rate; // TODO: Change to `48000000_u32.div_ceil(rate)` when api out of nightly
1488        let n = div.trailing_zeros().max(6);
1489
1490        let div3 = u32::from(
1491            (rate < (48000000 / 16384))
1492                || ((rate >= (48000000 / 3)) && (rate <= ((48000000 / 2) - 1))),
1493        );
1494        let denom = (1 << n) * (1 + (div3 * 2));
1495        let tot_per = if div % denom > 0 {
1496            (div / denom) + 1
1497        } else {
1498            div / denom
1499        };
1500        let v1 = 31 - tot_per.leading_zeros();
1501        let fsel = if v1 > 7 { v1 + n - 6 } else { n + 1 };
1502
1503        if fsel > 7 {
1504            return Err(ErrorCode::NOSUPPORT);
1505        }
1506
1507        let diven = u32::from((rate >= (48000000 / 4)) || ((1 << (fsel - 1)) == div));
1508        let low_per = if self.spi_phase.get() == ClockPhase::SampleLeading {
1509            (tot_per - 1) / 2
1510        } else {
1511            (tot_per - 2) / 2
1512        };
1513
1514        self.registers.clkcfg.write(
1515            CLKCFG::TOTPER.val(tot_per - 1)
1516                + CLKCFG::LOWPER.val(low_per)
1517                + CLKCFG::DIVEN.val(diven)
1518                + CLKCFG::DIV3.val(div3)
1519                + CLKCFG::FSEL.val(fsel)
1520                + CLKCFG::IOCLKEN::SET,
1521        );
1522
1523        Ok(self.get_rate())
1524    }
1525
1526    fn get_rate(&self) -> u32 {
1527        let fsel = self.registers.clkcfg.read(CLKCFG::FSEL);
1528        let div3 = self.registers.clkcfg.read(CLKCFG::DIV3);
1529        let diven = self.registers.clkcfg.read(CLKCFG::DIVEN);
1530        let tot_per = self.registers.clkcfg.read(CLKCFG::TOTPER) + 1;
1531
1532        let denom_final = (1 << (fsel - 1)) * (1 + div3 * 2) * (1 + diven * (tot_per));
1533
1534        if ((48000000) % denom_final) > (denom_final / 2) {
1535            (48000000 / denom_final) + 1
1536        } else {
1537            48000000 / denom_final
1538        }
1539    }
1540
1541    fn set_polarity(&self, polarity: ClockPolarity) -> Result<(), ErrorCode> {
1542        if self.op.get() != Operation::SPI && self.op.get() != Operation::None {
1543            return Err(ErrorCode::BUSY);
1544        }
1545
1546        if polarity == ClockPolarity::IdleLow {
1547            self.registers.mspicfg.modify(MSPICFG::SPOL::CLEAR);
1548        } else {
1549            self.registers.mspicfg.modify(MSPICFG::SPOL::SET);
1550        }
1551
1552        Ok(())
1553    }
1554
1555    fn get_polarity(&self) -> ClockPolarity {
1556        if self.registers.mspicfg.is_set(MSPICFG::SPOL) {
1557            ClockPolarity::IdleHigh
1558        } else {
1559            ClockPolarity::IdleLow
1560        }
1561    }
1562
1563    fn set_phase(&self, phase: ClockPhase) -> Result<(), ErrorCode> {
1564        if self.op.get() != Operation::SPI && self.op.get() != Operation::None {
1565            return Err(ErrorCode::BUSY);
1566        }
1567
1568        let low_per = if self.spi_phase.get() == ClockPhase::SampleLeading {
1569            (self.registers.clkcfg.read(CLKCFG::LOWPER) * 2) + 1
1570        } else {
1571            (self.registers.clkcfg.read(CLKCFG::LOWPER) * 2) + 2
1572        };
1573
1574        if phase == ClockPhase::SampleLeading {
1575            self.registers
1576                .clkcfg
1577                .modify(CLKCFG::LOWPER.val((low_per - 1) / 2));
1578        } else {
1579            self.registers
1580                .clkcfg
1581                .modify(CLKCFG::LOWPER.val((low_per - 2) / 2));
1582        }
1583
1584        self.spi_phase.set(phase);
1585
1586        Ok(())
1587    }
1588
1589    fn get_phase(&self) -> ClockPhase {
1590        self.spi_phase.get()
1591    }
1592
1593    fn hold_low(&self) {
1594        self.spi_cs.map(|cs| cs.activate());
1595    }
1596
1597    fn release_low(&self) {
1598        self.spi_cs.map(|cs| cs.deactivate());
1599    }
1600}