Skip to main content

kernel/hil/
spi.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//! Interfaces for SPI controller (master) and peripheral (slave) communication.
6//!
7//! We use the terms master/slave in some situations because the term peripheral
8//! can also refer to a hardware peripheral (e.g., memory-mapped I/O devices in
9//! ARM are called peripherals).
10
11// Author: Alexandru Radovici <msg4alex@gmail.com>
12// Author: Philip Levis <pal@cs.stanford.edu>
13// Author: Hubert Teo <hubert.teo.hk@gmail.com>
14// Author: Brad Campbell <bradjc5@gmail.com>
15// Author: Amit Aryeh Levy <amit@amitlevy.com>
16
17use crate::{ErrorCode, utilities::leasable_buffer::SubSliceMut};
18
19/// Data order defines the order of bits sent over the wire: most significant
20/// first, or least significant first.
21#[derive(Copy, Clone, Debug)]
22pub enum DataOrder {
23    /// Send the most significant byte first.
24    MSBFirst,
25    /// Send the least significant byte first.
26    LSBFirst,
27}
28
29/// Clock polarity (CPOL) defines whether the SPI clock is high or low when
30/// idle.
31#[derive(Copy, Clone, Debug, PartialEq)]
32pub enum ClockPolarity {
33    /// The clock is low when the SPI bus is not active. This is CPOL = 0.
34    IdleLow,
35    /// The clock is high when the SPI bus is not active. This is CPOL = 1.
36    IdleHigh,
37}
38
39/// Clock phase (CPHA) defines whether to sample and send data on a leading or
40/// trailing clock edge.
41///
42/// Consult a SPI reference on how CPHA interacts with CPOL.
43#[derive(Copy, Clone, Debug, PartialEq)]
44pub enum ClockPhase {
45    /// Sample on the leading clock edge. This is CPHA = 0. If CPOL is 0, then
46    /// this samples on the rising edge of the clock. If CPOL is 1, then this
47    /// samples on the falling edge of the clock.
48    SampleLeading,
49    /// Sample on the trailing clock edge. This is CPHA = 1. If CPOL is 0, then
50    /// this samples on the falling edge of the clock. If CPOL is 1, then this
51    /// samples on the rising edge of the clock.
52    SampleTrailing,
53}
54
55/// Utility types for modeling chip select pins in a [`SpiMaster`]
56/// implementation.
57pub mod cs {
58
59    /// Represents the Polarity of a chip-select pin (i.e. whether high or low
60    /// indicates the peripheral is active).
61    #[derive(Copy, Clone)]
62    pub enum Polarity {
63        /// Chip select is active high.
64        High,
65        /// Chip select is active low.
66        Low,
67    }
68
69    mod private {
70        pub trait Sealed {}
71    }
72
73    /// Marker trait indicating whether a peripheral requires active high or low
74    /// polarity as well as whether a [`SpiMaster`](super::SpiMaster)
75    /// implementation can support either or both polarities.
76    ///
77    /// This trait is sealed and only implemented for [`ActiveLow`] and
78    /// [`ActiveHigh`].
79    pub trait ChipSelectActivePolarity: private::Sealed {
80        const POLARITY: Polarity;
81    }
82
83    /// Marks a peripheral as requiring or controller as supporting active low
84    /// chip select pins.
85    pub enum ActiveLow {}
86    /// Marks a peripheral as requiring or controller as supporting active high
87    /// chip select pins.
88    pub enum ActiveHigh {}
89
90    impl private::Sealed for ActiveLow {}
91    impl private::Sealed for ActiveHigh {}
92
93    impl ChipSelectActivePolarity for ActiveLow {
94        const POLARITY: Polarity = Polarity::Low;
95    }
96
97    impl ChipSelectActivePolarity for ActiveHigh {
98        const POLARITY: Polarity = Polarity::High;
99    }
100
101    /// A type that can be converted to the appropriate type for
102    /// [`SpiMaster::ChipSelect`](super::SpiMaster::ChipSelect) for a particular
103    /// `POLARITY`.
104    ///
105    /// Instantiating a driver for any SPI peripheral should require a type that
106    /// implements [`IntoChipSelect`]. That enforces that whatever object is
107    /// used as the chip select can support the correct polarity for the
108    /// particular SPI peripheral. This is mostly commonly handled by the
109    /// component for the peripheral, which requires an object with type
110    /// [`IntoChipSelect`] and then converts the object to the
111    /// [`SpiMaster::ChipSelect`](super::SpiMaster::ChipSelect) type.
112    ///
113    /// # Examples:
114    ///
115    /// Some SPI host controllers only support active low or active high chip
116    /// select pins. Such a controller might provide a unit implementation of
117    /// this trait _only_ for the [`ActiveLow`] marker.
118    ///
119    /// ```rust
120    /// use kernel::hil::spi::cs::*;
121    ///
122    /// #[derive(Copy, Clone)]
123    /// enum PeripheralSelect {
124    ///     Peripheral0,
125    ///     Peripheral1,
126    /// }
127    ///
128    /// impl IntoChipSelect<PeripheralSelect, ActiveLow> for PeripheralSelect {
129    ///     fn into_cs(self) -> Self { self }
130    /// }
131    /// ```
132    ///
133    /// Many other controllers can handle both active low and active high chip
134    /// select pins, in which case, they should implement both the [`ActiveLow`]
135    /// and [`ActiveHigh`] variants, for example, using the [`ChipSelectPolar`]
136    /// wrapper struct (which implements both).
137    pub trait IntoChipSelect<T, POLARITY> {
138        fn into_cs(self) -> T;
139    }
140
141    /// A convenience wrapper type around [`Output`](crate::hil::gpio::Output)
142    /// GPIO pins that implements [`IntoChipSelect`] for both [`ActiveLow`] and
143    /// [`ActiveHigh`].
144    pub struct ChipSelectPolar<'a, P: crate::hil::gpio::Output> {
145        /// The underlying chip select "pin".
146        pub pin: &'a P,
147        /// The polarity from which this wrapper was derived using
148        /// [`IntoChipSelect`].
149        pub polarity: Polarity,
150    }
151
152    impl<P: crate::hil::gpio::Output> Clone for ChipSelectPolar<'_, P> {
153        fn clone(&self) -> Self {
154            *self
155        }
156    }
157
158    impl<P: crate::hil::gpio::Output> Copy for ChipSelectPolar<'_, P> {}
159
160    impl<'a, P: crate::hil::gpio::Output, A: ChipSelectActivePolarity>
161        IntoChipSelect<ChipSelectPolar<'a, P>, A> for &'a P
162    {
163        fn into_cs(self) -> ChipSelectPolar<'a, P> {
164            ChipSelectPolar {
165                pin: self,
166                polarity: A::POLARITY,
167            }
168        }
169    }
170
171    /// When wrapping a GPIO pin that implements
172    /// [`gpio::Output`](crate::hil::gpio::Output), users can use the
173    /// [`activate`](ChipSelectPolar::activate) and
174    /// [`deactivate`](ChipSelectPolar::deactivate) methods to automatically set
175    /// or clear the chip select pin based on the stored polarity.
176    impl<P: crate::hil::gpio::Output> ChipSelectPolar<'_, P> {
177        /// Deactivate the chip select pin.
178        ///
179        /// High if active low, low if active high.
180        pub fn deactivate(&self) {
181            match self.polarity {
182                Polarity::Low => self.pin.set(),
183                Polarity::High => self.pin.clear(),
184            }
185        }
186
187        /// Active the chip select pin.
188        ///
189        /// Low if active low, high if active high.
190        pub fn activate(&self) {
191            match self.polarity {
192                Polarity::Low => self.pin.clear(),
193                Polarity::High => self.pin.set(),
194            }
195        }
196    }
197}
198
199/// Trait for clients of a SPI bus in master mode.
200pub trait SpiMasterClient {
201    /// Callback issued when a read/write operation finishes.
202    ///
203    /// `write_buffer` and `read_buffer` always contain the buffers
204    /// passed to the [SpiMaster::read_write_bytes]
205    /// down-call, with `read_buffer` as an `Option` because the
206    /// down-call passes an `Option`. The contents of `write_buffer`
207    /// is unmodified, while `read_buffer` contains the bytes read
208    /// over SPI. Each buffer's bounds are unmodified from their state
209    /// when `read_write_bytes` is called.
210    ///
211    /// `status` signals if the operation was successful, and if so,
212    /// the length of the operation, or an appropriate `ErrorCode`.
213    fn read_write_done(
214        &self,
215        write_buffer: SubSliceMut<'static, u8>,
216        read_buffer: Option<SubSliceMut<'static, u8>>,
217        status: Result<usize, ErrorCode>,
218    );
219}
220/// Trait for interacting with SPI peripheral devices at a byte or buffer level.
221///
222/// Using [`SpiMaster`] normally involves three steps:
223///
224/// 1. Configure the SPI bus for a peripheral.
225///
226///    1. Call [`SpiMaster::specify_chip_select`] to select which peripheral and
227///       turn on SPI.
228///
229///    2. Call set operations as needed to configure the bus. **NOTE**: You MUST
230///       select the chip select BEFORE configuring SPI settings.
231///
232/// 2. Invoke [`SpiMaster::read_write_bytes`] on [`SpiMaster`].
233///
234/// 3. Go back to step 2 to complete another transaction, or call
235///    [`SpiMaster::specify_chip_select`] to choose another peripheral and go to
236///    step 1.2 or 2.
237///
238/// The SPI configuration for a particular peripheral persists across changes to
239/// the chip select. For example, this set of calls:
240///
241/// ```rust,ignore
242/// SpiMaster::specify_chip_select(1);
243/// SpiMaster::set_phase(ClockPhase::SampleLeading);
244/// SpiMaster::specify_chip_select(2);
245/// SpiMaster::set_phase(ClockPhase::SampleTrailing);
246/// SpiMaster::specify_chip_select(1);
247/// SpiMaster::read_write_bytes(...); // Uses SampleLeading
248/// ```
249///
250/// will have a [`ClockPhase::SampleLeading`] phase in the final
251/// [`SpiMaster::read_write_bytes`] call, because the configuration of chip select 1
252/// is saved, and restored when chip select is set back to 1.
253///
254/// If additional chip selects are needed, they can be performed with GPIO and
255/// manual re-initialization of settings. Note that a SPI chip select (CS) line
256/// is usually active low.
257///
258/// ```rust,ignore
259/// specify_chip_select(0);
260/// set_phase(ClockPhase::SampleLeading);
261/// pin_a.clear(); // Select A
262/// read_write_bytes(...); // Uses SampleLeading
263/// pin_a.set(); // Unselect A
264/// set_phase(ClockPhase::SampleTrailing);
265/// pin_b.clear(); // Select B
266/// read_write_bytes(...); // Uses SampleTrailing
267/// ```
268pub trait SpiMaster<'a> {
269    /// Chip select is an associated type because different SPI buses may have
270    /// different numbers of chip selects. This allows peripheral
271    /// implementations to define their own type.
272    type ChipSelect: Copy;
273
274    /// Initialize this SPI interface. Call this once before invoking any other
275    /// operations.
276    ///
277    /// ### Return values
278    ///
279    /// - `Ok(())`: initialized correctly
280    /// - `Err(OFF)`: not currently powered so can't be initialized
281    /// - `Err(RESERVE)`: no clock is configured yet
282    /// - `Err(FAIL)`: other failure condition
283    fn init(&self) -> Result<(), ErrorCode>;
284
285    /// Change the callback handler for [`SpiMaster::read_write_bytes`] calls.
286    fn set_client(&self, client: &'a dyn SpiMasterClient);
287
288    /// Return whether the SPI peripheral is busy with a
289    /// [`SpiMaster::read_write_bytes`] operation.
290    fn is_busy(&self) -> bool;
291
292    /// Perform an asynchronous read/write operation, whose completion is
293    /// signaled by invoking [`SpiMasterClient`] on the client. Write-only
294    /// operations may pass `None` for `read_buffer`, while read-write
295    /// operations pass `Some` for `read_buffer`.
296    ///
297    /// If `read_buffer` is `None`, the number of bytes written will
298    /// be the the length of `write_buffer`. If `read_buffer` is
299    /// `Some`, the number of bytes read/written will be the minimum
300    /// of the length of `write_buffer` and the length of
301    /// `read_buffer`.
302    ///
303    /// ### Return values
304    ///
305    /// If `read_write_bytes` returns `Ok(())`, the operation will be
306    /// attempted and a callback will be called. If it returns `Err`,
307    /// no callback will be called and the buffers are returned.
308    /// - `Ok(())`: the operation will be attempted and the callback will be
309    ///   called.
310    /// - `Err(OFF)`: the SPI bus is powered down.
311    /// - `Err(INVAL)`: length is 0
312    /// - `Err(BUSY)`: the SPI bus is busy with a prior
313    ///   [`SpiMaster::read_write_bytes`] operation whose callback hasn't been
314    ///   called yet.
315    fn read_write_bytes(
316        &self,
317        write_buffer: SubSliceMut<'static, u8>,
318        read_buffer: Option<SubSliceMut<'static, u8>>,
319    ) -> Result<
320        (),
321        (
322            ErrorCode,
323            SubSliceMut<'static, u8>,
324            Option<SubSliceMut<'static, u8>>,
325        ),
326    >;
327
328    /// Specify which chip select to use. Configuration settings (rate,
329    /// polarity, phase) are chip-select specific and are stored for that chip
330    /// select.
331    fn specify_chip_select(&self, cs: Self::ChipSelect) -> Result<(), ErrorCode>;
332
333    /// Set the clock/data rate for the current chip select.
334    ///
335    /// ### Return values
336    ///
337    /// - `Ok(u32)`: the actual data rate set (limited by clock precision)
338    /// - `Err(INVAL)`: a rate outside the bounds of the bus was passed
339    /// - `Err(BUSY)`: the SPI bus is busy with a
340    ///   [`SpiMaster::read_write_bytes`] operation whose callback hasn't been
341    ///   called yet.
342    /// - `Err(FAIL)`: other failure
343    fn set_rate(&self, rate: u32) -> Result<u32, ErrorCode>;
344
345    /// Return the current chip select's clock rate.
346    fn get_rate(&self) -> u32;
347
348    /// Set the bus polarity (whether idle is high or low) for the
349    /// current chip select.
350    ///
351    /// ### Return values
352    ///
353    /// - `Ok(())`: the polarity was set.
354    /// - `Err(BUSY)`: the SPI bus is busy with a
355    ///   [`SpiMaster::read_write_bytes`] operation whose callback hasn't been
356    ///   called yet.
357    /// - `Err(FAIL)`: other failure
358    fn set_polarity(&self, polarity: ClockPolarity) -> Result<(), ErrorCode>;
359
360    /// Return the current bus polarity.
361    fn get_polarity(&self) -> ClockPolarity;
362
363    /// Set the bus phase for the current chip select (whether data is
364    /// sent/received on leading or trailing edges).
365    ///
366    /// ### Return values
367    ///
368    /// - `Ok(())`: the phase was set.
369    /// - `Err(BUSY)`: the SPI bus is busy with a
370    ///   [`SpiMaster::read_write_bytes`] operation whose callback hasn't been
371    ///   called yet.
372    /// - `Err(FAIL)`: other failure
373    fn set_phase(&self, phase: ClockPhase) -> Result<(), ErrorCode>;
374
375    /// Get the current bus phase for the current chip select.
376    fn get_phase(&self) -> ClockPhase;
377
378    // These two functions determine what happens to the chip select line
379    // between transfers. If hold_low() is called, then the chip select line is
380    // held low after transfers complete. If release_low() is called, then the
381    // chip select line is brought high after a transfer completes. A "transfer"
382    // is any of the read/read_write calls. These functions allow an application
383    // to manually control when the CS line is high or low, such that it can
384    // issue longer read/writes with multiple read_write_bytes calls.
385
386    /// Hold the chip select line low after a [`SpiMaster::read_write_bytes`]
387    /// completes. This allows a client to make one long SPI read/write with
388    /// multiple calls to `read_write_bytes`.
389    fn hold_low(&self);
390
391    /// Raise the chip select line after a [`SpiMaster::read_write_bytes`]
392    /// completes. This will complete the SPI operation.
393    fn release_low(&self);
394}
395
396/// A chip-select-specific interface to the SPI Controller hardware, such that a
397/// client cannot change the chip select line.
398///
399/// This restricts the SPI peripherals the client can access to a specific
400/// peripheral.
401pub trait SpiMasterDevice<'a> {
402    /// Set the callback for read_write operations.
403    fn set_client(&self, client: &'a dyn SpiMasterClient);
404
405    /// Configure the bus for this chip select.
406    fn configure(&self, cpol: ClockPolarity, cpal: ClockPhase, rate: u32) -> Result<(), ErrorCode>;
407
408    /// Same as [`SpiMaster::read_write_bytes`].
409    fn read_write_bytes(
410        &self,
411        write_buffer: SubSliceMut<'static, u8>,
412        read_buffer: Option<SubSliceMut<'static, u8>>,
413    ) -> Result<
414        (),
415        (
416            ErrorCode,
417            SubSliceMut<'static, u8>,
418            Option<SubSliceMut<'static, u8>>,
419        ),
420    >;
421
422    /// Same as [`SpiMaster::set_rate`].
423    fn set_rate(&self, rate: u32) -> Result<(), ErrorCode>;
424
425    /// Return the current chip select's clock rate.
426    fn get_rate(&self) -> u32;
427
428    /// Same as [`SpiMaster::set_polarity`].
429    fn set_polarity(&self, polarity: ClockPolarity) -> Result<(), ErrorCode>;
430
431    /// Return the current bus polarity.
432    fn get_polarity(&self) -> ClockPolarity;
433
434    /// Same as [`SpiMaster::set_phase`].
435    fn set_phase(&self, phase: ClockPhase) -> Result<(), ErrorCode>;
436
437    /// Get the current bus phase for the current chip select.
438    fn get_phase(&self) -> ClockPhase;
439}
440
441/// Trait for SPI peripherals (slaves) to receive callbacks when the
442/// corresponding controller (master) issues operations.
443///
444/// A SPI operation begins with a callback of [`SpiSlaveClient::chip_selected`].
445/// If the client has provided buffers with [`SpiSlave::read_write_bytes`],
446/// these buffers are written from and read into until the operation completes
447/// or one of them fills, at which point a [`SpiSlaveClient::read_write_done`]
448/// callback is called. If the client needs to read/write more it can call
449/// [`SpiSlave::read_write_bytes`] again.
450///
451/// Note that there is no notification when the chip select line goes high.
452pub trait SpiSlaveClient {
453    /// Notification that the chip select has been brought low.
454    fn chip_selected(&self);
455
456    /// Callback issued when the controller completes an SPI operation to this
457    /// peripheral.
458    ///
459    /// `write_buffer` and `read_buffer` are the values passed in the previous
460    /// call to [`SpiSlave::read_write_bytes`]. The `len` parameter specifies
461    /// how many bytes were written from/read into `Some` values of these
462    /// buffers. `len` may be shorter than the size of these buffers if the
463    /// operation did not fill them.
464    fn read_write_done(
465        &self,
466        write_buffer: Option<&'static mut [u8]>,
467        read_buffer: Option<&'static mut [u8]>,
468        len: usize,
469        status: Result<(), ErrorCode>,
470    );
471}
472
473/// Trait for SPI peripherals (slaves) to exchange data with a contoller
474/// (master).
475///
476/// This is a low-level trait typically implemented by hardware: higher level
477/// software typically uses the [`SpiSlaveDevice`] trait, which is provided by a
478/// virtualizing/multiplexing layer.
479pub trait SpiSlave<'a> {
480    /// Initialize the SPI device to be in peripheral mode.
481    ///
482    /// ### Return values
483    ///
484    /// - `Ok(())`: the device is in peripheral mode
485    /// - `Err(BUSY)`: the device is busy with an operation and cannot be
486    ///   initialized
487    /// - `Err(FAIL)`: other failure condition
488    fn init(&self) -> Result<(), ErrorCode>;
489
490    /// Returns true if there is a client. Useful for verifying that two
491    /// software drivers do not both try to take control of the device.
492    fn has_client(&self) -> bool;
493
494    /// Set the callback for slave operations, passing `None` to disable
495    /// peripheral mode.
496    fn set_client(&self, client: Option<&'a dyn SpiSlaveClient>);
497
498    /// Set a single byte to write in response to a read/write operation from a
499    /// controller. Useful for devices that always send a status code in their
500    /// first byte.
501    fn set_write_byte(&self, write_byte: u8);
502
503    /// Provide buffers for the peripheral to write from and read into when a
504    /// controller performs a `read_write_bytes` operation.
505    ///
506    /// The device will issue a callback when one of four things occurs:
507    ///
508    /// - The controller completes the operation by bringing the chip select
509    ///   high.
510    /// - A `Some` write buffer is written.
511    /// - A `Some` read buffer is filled.
512    /// - `len` bytes are read/written
513    ///
514    /// ### Return values
515    ///
516    /// - `Ok(())`: the SPI bus will read/write the provided buffers on the next
517    ///   SPI operation requested by the controller.
518    /// - `Err(BUSY)`: the device is busy with an existing `read_write_bytes`
519    ///   operation.
520    /// - `Err(INVAL)`: the `len` parameter is 0
521    ///
522    /// `Err` return values return the passed buffer `Option`s.
523    fn read_write_bytes(
524        &self,
525        write_buffer: Option<&'static mut [u8]>,
526        read_buffer: Option<&'static mut [u8]>,
527        len: usize,
528    ) -> Result<
529        (),
530        (
531            ErrorCode,
532            Option<&'static mut [u8]>,
533            Option<&'static mut [u8]>,
534        ),
535    >;
536
537    /// Set the bus polarity (whether idle is high or low).
538    ///
539    /// ### Return values
540    ///
541    /// - `Ok(())`: the polarity was set.
542    /// - `Err(BUSY)`: the SPI bus is busy with a [`SpiSlave::read_write_bytes`]
543    ///   operation whose callback hasn't been called yet.
544    /// - `Err(FAIL)`: other failure
545    fn set_polarity(&self, polarity: ClockPolarity) -> Result<(), ErrorCode>;
546
547    /// Return the current bus polarity.
548    fn get_polarity(&self) -> ClockPolarity;
549
550    /// Set the bus phase (whether data is sent/received on leading or
551    /// trailing edges).
552    ///
553    /// ### Return values
554    ///
555    /// - `Ok(())`: the phase was set.
556    /// - `Err(BUSY)`: the SPI bus is busy with a [`SpiSlave::read_write_bytes`]
557    ///   operation whose callback hasn't been called yet.
558    /// - `Err(FAIL)`: other failure
559    fn set_phase(&self, phase: ClockPhase) -> Result<(), ErrorCode>;
560
561    /// Return the current bus phase.
562    fn get_phase(&self) -> ClockPhase;
563}
564
565/// An interface to a SPI bus in peripheral mode.
566///
567/// It is the standard trait used by services within the kernel: [`SpiSlave`] is
568/// for lower-level access responsible for initializing hardware.
569pub trait SpiSlaveDevice<'a> {
570    /// Specify the callback of [`SpiSlaveDevice::read_write_bytes`] operations.
571    fn set_client(&self, client: &'a dyn SpiSlaveClient);
572
573    /// Setup the SPI settings and speed of the bus.
574    fn configure(&self, cpol: ClockPolarity, cpal: ClockPhase) -> Result<(), ErrorCode>;
575
576    /// Same as [`SpiSlave::read_write_bytes`].
577    fn read_write_bytes(
578        &self,
579        write_buffer: Option<&'static mut [u8]>,
580        read_buffer: Option<&'static mut [u8]>,
581        len: usize,
582    ) -> Result<
583        (),
584        (
585            ErrorCode,
586            Option<&'static mut [u8]>,
587            Option<&'static mut [u8]>,
588        ),
589    >;
590
591    /// Same as [`SpiSlave::set_polarity`].
592    fn set_polarity(&self, polarity: ClockPolarity) -> Result<(), ErrorCode>;
593
594    /// Return the current bus polarity.
595    fn get_polarity(&self) -> ClockPolarity;
596
597    /// Same as [`SpiSlave::set_phase`].
598    fn set_phase(&self, phase: ClockPhase) -> Result<(), ErrorCode>;
599
600    /// Return the current bus phase.
601    fn get_phase(&self) -> ClockPhase;
602}