components/
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//! Components for SPI.
6//!
7//! This provides four components.
8//!
9//! 1. `SpiMuxComponent` provides a virtualization layer for a SPI controller.
10//! 2. `SpiSyscallComponent` provides a controller system call interface to SPI.
11//! 3. `SpiPSyscallComponent` provides a peripheral system call interface to SPI.
12//! 4. `SpiComponent` provides a virtualized client to the SPI bus.
13//!
14//! `SpiSyscallComponent` is used for processes, while `SpiComponent` is used
15//! for kernel capsules that need access to the SPI bus.
16//!
17//! Usage
18//! -----
19//! ```rust
20//! let mux_spi = components::spi::SpiMuxComponent::new(&sam4l::spi::SPI).finalize(
21//!     components::spi_mux_component_static!(sam4l::spi::SpiHw));
22//! let spi_syscalls = SpiSyscallComponent::new(mux_spi, 3).finalize(
23//!     components::spi_syscalls_component_static!(sam4l::spi::SpiHw));
24//! let rf233_spi = SpiComponent::new(mux_spi, 3).finalize(
25//!     components::spi_component_static!(sam4l::spi::SpiHw));
26//! ```
27
28// Author: Philip Levis <pal@cs.stanford.edu>
29// Last modified: 6/20/2018
30
31use core::marker::PhantomData;
32use core::mem::MaybeUninit;
33
34use capsules_core::spi_controller::{Spi, DEFAULT_READ_BUF_LENGTH, DEFAULT_WRITE_BUF_LENGTH};
35use capsules_core::spi_peripheral::SpiPeripheral;
36use capsules_core::virtualizers::virtual_spi;
37use capsules_core::virtualizers::virtual_spi::{MuxSpiMaster, VirtualSpiMasterDevice};
38use kernel::capabilities;
39use kernel::component::Component;
40use kernel::create_capability;
41use kernel::hil::spi;
42use kernel::hil::spi::{SpiMasterDevice, SpiSlaveDevice};
43
44// Setup static space for the objects.
45#[macro_export]
46macro_rules! spi_mux_component_static {
47    ($S:ty $(,)?) => {{
48        kernel::static_buf!(capsules_core::virtualizers::virtual_spi::MuxSpiMaster<'static, $S>)
49    };};
50}
51
52#[macro_export]
53macro_rules! spi_syscall_component_static {
54    ($S:ty $(,)?) => {{
55        let virtual_spi = kernel::static_buf!(
56            capsules_core::virtualizers::virtual_spi::VirtualSpiMasterDevice<'static, $S>
57        );
58        let spi = kernel::static_buf!(
59            capsules_core::spi_controller::Spi<
60                'static,
61                capsules_core::virtualizers::virtual_spi::VirtualSpiMasterDevice<'static, $S>,
62            >
63        );
64
65        let spi_read_buf =
66            kernel::static_buf!([u8; capsules_core::spi_controller::DEFAULT_READ_BUF_LENGTH]);
67        let spi_write_buf =
68            kernel::static_buf!([u8; capsules_core::spi_controller::DEFAULT_WRITE_BUF_LENGTH]);
69
70        (virtual_spi, spi, spi_read_buf, spi_write_buf)
71    };};
72}
73
74#[macro_export]
75macro_rules! spi_syscallp_component_static {
76    ($S:ty $(,)?) => {{
77        let spi_slave = kernel::static_buf!(
78            capsules_core::virtualizers::virtual_spi::SpiSlaveDevice<'static, $S>
79        );
80        let spi_peripheral = kernel::static_buf!(
81            capsules_core::spi_peripheral::SpiPeripheral<
82                'static,
83                capsules_core::virtualizers::virtual_spi::SpiSlaveDevice<'static, $S>,
84            >
85        );
86
87        let spi_read_buf =
88            kernel::static_buf!([u8; capsules_core::spi_controller::DEFAULT_READ_BUF_LENGTH]);
89        let spi_write_buf =
90            kernel::static_buf!([u8; capsules_core::spi_controller::DEFAULT_WRITE_BUF_LENGTH]);
91
92        (spi_slave, spi_peripheral, spi_read_buf, spi_write_buf)
93    };};
94}
95
96#[macro_export]
97macro_rules! spi_component_static {
98    ($S:ty $(,)?) => {{
99        kernel::static_buf!(
100            capsules_core::virtualizers::virtual_spi::VirtualSpiMasterDevice<'static, $S>
101        )
102    };};
103}
104
105#[macro_export]
106macro_rules! spi_peripheral_component_static {
107    ($S:ty $(,)?) => {{
108        kernel::static_buf!(capsules_core::spi_peripheral::SpiPeripheral<'static, $S>)
109    };};
110}
111
112pub struct SpiMuxComponent<S: 'static + spi::SpiMaster<'static>> {
113    spi: &'static S,
114}
115
116pub struct SpiSyscallComponent<S: 'static + spi::SpiMaster<'static>> {
117    board_kernel: &'static kernel::Kernel,
118    spi_mux: &'static MuxSpiMaster<'static, S>,
119    chip_select: S::ChipSelect,
120    driver_num: usize,
121}
122
123pub struct SpiSyscallPComponent<S: 'static + spi::SpiSlave<'static>> {
124    board_kernel: &'static kernel::Kernel,
125    spi_slave: &'static S,
126    driver_num: usize,
127}
128
129pub struct SpiComponent<
130    S: 'static + spi::SpiMaster<'static>,
131    CS: spi::cs::IntoChipSelect<S::ChipSelect, AP>,
132    AP: spi::cs::ChipSelectActivePolarity,
133> {
134    spi_mux: &'static MuxSpiMaster<'static, S>,
135    chip_select: CS,
136    _phantom: PhantomData<AP>,
137}
138
139impl<S: 'static + spi::SpiMaster<'static>> SpiMuxComponent<S> {
140    pub fn new(spi: &'static S) -> Self {
141        Self { spi }
142    }
143}
144
145impl<S: 'static + spi::SpiMaster<'static>> Component for SpiMuxComponent<S> {
146    type StaticInput = &'static mut MaybeUninit<MuxSpiMaster<'static, S>>;
147    type Output = &'static MuxSpiMaster<'static, S>;
148
149    fn finalize(self, static_buffer: Self::StaticInput) -> Self::Output {
150        let mux_spi = static_buffer.write(MuxSpiMaster::new(self.spi));
151        kernel::deferred_call::DeferredCallClient::register(mux_spi);
152
153        self.spi.set_client(mux_spi);
154
155        if let Err(error) = self.spi.init() {
156            panic!("SPI init failed ({:?})", error);
157        }
158
159        mux_spi
160    }
161}
162
163impl<S: 'static + spi::SpiMaster<'static>> SpiSyscallComponent<S> {
164    pub fn new(
165        board_kernel: &'static kernel::Kernel,
166        mux: &'static MuxSpiMaster<'static, S>,
167        chip_select: S::ChipSelect,
168        driver_num: usize,
169    ) -> Self {
170        SpiSyscallComponent {
171            board_kernel,
172            spi_mux: mux,
173            chip_select,
174            driver_num,
175        }
176    }
177}
178
179impl<S: 'static + spi::SpiMaster<'static>> Component for SpiSyscallComponent<S> {
180    type StaticInput = (
181        &'static mut MaybeUninit<VirtualSpiMasterDevice<'static, S>>,
182        &'static mut MaybeUninit<Spi<'static, VirtualSpiMasterDevice<'static, S>>>,
183        &'static mut MaybeUninit<[u8; DEFAULT_READ_BUF_LENGTH]>,
184        &'static mut MaybeUninit<[u8; DEFAULT_WRITE_BUF_LENGTH]>,
185    );
186    type Output = &'static Spi<'static, VirtualSpiMasterDevice<'static, S>>;
187
188    fn finalize(self, static_buffer: Self::StaticInput) -> Self::Output {
189        let grant_cap = create_capability!(capabilities::MemoryAllocationCapability);
190
191        let syscall_spi_device = static_buffer
192            .0
193            .write(VirtualSpiMasterDevice::new(self.spi_mux, self.chip_select));
194
195        let spi_syscalls = static_buffer.1.write(Spi::new(
196            syscall_spi_device,
197            self.board_kernel.create_grant(self.driver_num, &grant_cap),
198        ));
199
200        let spi_read_buf = static_buffer.2.write([0; DEFAULT_READ_BUF_LENGTH]);
201        let spi_write_buf = static_buffer.3.write([0; DEFAULT_WRITE_BUF_LENGTH]);
202
203        spi_syscalls.config_buffers(spi_read_buf, spi_write_buf);
204        syscall_spi_device.setup();
205        syscall_spi_device.set_client(spi_syscalls);
206        spi_syscalls
207    }
208}
209
210impl<S: 'static + spi::SpiSlave<'static>> SpiSyscallPComponent<S> {
211    pub fn new(
212        board_kernel: &'static kernel::Kernel,
213        slave: &'static S,
214        driver_num: usize,
215    ) -> Self {
216        SpiSyscallPComponent {
217            board_kernel,
218            spi_slave: slave,
219            driver_num,
220        }
221    }
222}
223
224impl<S: 'static + spi::SpiSlave<'static>> Component for SpiSyscallPComponent<S> {
225    type StaticInput = (
226        &'static mut MaybeUninit<virtual_spi::SpiSlaveDevice<'static, S>>,
227        &'static mut MaybeUninit<SpiPeripheral<'static, virtual_spi::SpiSlaveDevice<'static, S>>>,
228        &'static mut MaybeUninit<[u8; DEFAULT_READ_BUF_LENGTH]>,
229        &'static mut MaybeUninit<[u8; DEFAULT_WRITE_BUF_LENGTH]>,
230    );
231    type Output = &'static SpiPeripheral<'static, virtual_spi::SpiSlaveDevice<'static, S>>;
232
233    fn finalize(self, static_buffer: Self::StaticInput) -> Self::Output {
234        let grant_cap = create_capability!(capabilities::MemoryAllocationCapability);
235
236        let syscallp_spi_device = static_buffer
237            .0
238            .write(virtual_spi::SpiSlaveDevice::new(self.spi_slave));
239
240        let spi_syscallsp = static_buffer.1.write(SpiPeripheral::new(
241            syscallp_spi_device,
242            self.board_kernel.create_grant(self.driver_num, &grant_cap),
243        ));
244
245        let spi_read_buf = static_buffer.2.write([0; DEFAULT_READ_BUF_LENGTH]);
246        let spi_write_buf = static_buffer.3.write([0; DEFAULT_WRITE_BUF_LENGTH]);
247
248        spi_syscallsp.config_buffers(spi_read_buf, spi_write_buf);
249        syscallp_spi_device.set_client(spi_syscallsp);
250
251        spi_syscallsp
252    }
253}
254
255impl<
256        S: 'static + spi::SpiMaster<'static>,
257        CS: spi::cs::IntoChipSelect<S::ChipSelect, AP>,
258        AP: spi::cs::ChipSelectActivePolarity,
259    > SpiComponent<S, CS, AP>
260{
261    pub fn new(mux: &'static MuxSpiMaster<'static, S>, chip_select: CS) -> Self {
262        SpiComponent {
263            spi_mux: mux,
264            _phantom: PhantomData,
265            chip_select,
266        }
267    }
268}
269
270impl<
271        S: 'static + spi::SpiMaster<'static>,
272        CS: spi::cs::IntoChipSelect<S::ChipSelect, AP>,
273        AP: spi::cs::ChipSelectActivePolarity,
274    > Component for SpiComponent<S, CS, AP>
275{
276    type StaticInput = &'static mut MaybeUninit<VirtualSpiMasterDevice<'static, S>>;
277    type Output = &'static VirtualSpiMasterDevice<'static, S>;
278
279    fn finalize(self, static_buffer: Self::StaticInput) -> Self::Output {
280        let spi_device = static_buffer.write(VirtualSpiMasterDevice::new(
281            self.spi_mux,
282            self.chip_select.into_cs(),
283        ));
284        spi_device.setup();
285        spi_device
286    }
287}
288
289pub struct SpiPeripheralComponent<S: 'static + spi::SpiSlave<'static>> {
290    board_kernel: &'static kernel::Kernel,
291    device: &'static S,
292    driver_num: usize,
293}
294
295impl<S: 'static + spi::SpiSlave<'static>> SpiPeripheralComponent<S> {
296    pub fn new(
297        board_kernel: &'static kernel::Kernel,
298        device: &'static S,
299        driver_num: usize,
300    ) -> Self {
301        SpiPeripheralComponent {
302            board_kernel,
303            device,
304            driver_num,
305        }
306    }
307}
308
309impl<S: 'static + spi::SpiSlave<'static> + kernel::hil::spi::SpiSlaveDevice<'static>> Component
310    for SpiPeripheralComponent<S>
311{
312    type StaticInput = &'static mut MaybeUninit<SpiPeripheral<'static, S>>;
313    type Output = &'static SpiPeripheral<'static, S>;
314
315    fn finalize(self, static_buffer: Self::StaticInput) -> Self::Output {
316        let grant_cap = create_capability!(capabilities::MemoryAllocationCapability);
317
318        let spi_device = static_buffer.write(SpiPeripheral::new(
319            self.device,
320            self.board_kernel.create_grant(self.driver_num, &grant_cap),
321        ));
322
323        spi_device
324    }
325}