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}