capsules_core/virtualizers/
virtual_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//! Virtualize a SPI master bus to enable multiple users of the SPI bus.
6
7use core::cell::Cell;
8use kernel::collections::list::{List, ListLink, ListNode};
9use kernel::deferred_call::{DeferredCall, DeferredCallClient};
10use kernel::hil;
11use kernel::hil::spi::SpiMasterClient;
12use kernel::utilities::cells::{MapCell, OptionalCell};
13use kernel::utilities::leasable_buffer::SubSliceMut;
14use kernel::ErrorCode;
15
16/// The Mux struct manages multiple Spi clients. Each client may have
17/// at most one outstanding Spi request.
18pub struct MuxSpiMaster<'a, Spi: hil::spi::SpiMaster<'a>> {
19    spi: &'a Spi,
20    devices: List<'a, VirtualSpiMasterDevice<'a, Spi>>,
21    inflight: OptionalCell<&'a VirtualSpiMasterDevice<'a, Spi>>,
22    deferred_call: DeferredCall,
23}
24
25impl<'a, Spi: hil::spi::SpiMaster<'a>> hil::spi::SpiMasterClient for MuxSpiMaster<'a, Spi> {
26    fn read_write_done(
27        &self,
28        write_buffer: SubSliceMut<'static, u8>,
29        read_buffer: Option<SubSliceMut<'static, u8>>,
30        status: Result<usize, ErrorCode>,
31    ) {
32        let dev = self.inflight.take();
33        // Need to do next op before signaling so we get some kind of
34        // sharing. Otherwise a call to read_write in the callback
35        // can allow this client to never relinquish the device.
36        // -pal 7/30/21
37        self.do_next_op();
38        dev.map(move |device| {
39            device.read_write_done(write_buffer, read_buffer, status);
40        });
41    }
42}
43
44impl<'a, Spi: hil::spi::SpiMaster<'a>> MuxSpiMaster<'a, Spi> {
45    pub fn new(spi: &'a Spi) -> Self {
46        Self {
47            spi,
48            devices: List::new(),
49            inflight: OptionalCell::empty(),
50            deferred_call: DeferredCall::new(),
51        }
52    }
53
54    fn do_next_op(&self) {
55        if self.inflight.is_none() {
56            let mnode = self
57                .devices
58                .iter()
59                .find(|node| node.operation.get() != Op::Idle);
60            mnode.map(|node| {
61                let configuration = node.configuration.get();
62                let cs = configuration.chip_select;
63                let _ = self.spi.specify_chip_select(cs);
64
65                let op = node.operation.get();
66                // Need to set idle here in case callback changes state
67                node.operation.set(Op::Idle);
68                match op {
69                    Op::ReadWriteBytes => {
70                        // Only async operations want to block by setting
71                        // the devices as inflight.
72                        self.inflight.set(node);
73                        node.txbuffer.take().map(|txbuffer| {
74                            let rresult = self.spi.set_rate(configuration.rate);
75                            let polresult = self.spi.set_polarity(configuration.polarity);
76                            let phaseresult = self.spi.set_phase(configuration.phase);
77                            if rresult.is_err() || polresult.is_err() || phaseresult.is_err() {
78                                node.txbuffer.replace(txbuffer);
79                                node.operation.set(Op::ReadWriteDone(Err(ErrorCode::INVAL)));
80                                self.do_next_op_async();
81                            } else {
82                                let rxbuffer = node.rxbuffer.take();
83                                if let Err((e, write_buffer, read_buffer)) =
84                                    self.spi.read_write_bytes(txbuffer, rxbuffer)
85                                {
86                                    node.txbuffer.replace(write_buffer);
87                                    read_buffer.map(|buffer| {
88                                        node.rxbuffer.replace(buffer);
89                                    });
90                                    node.operation.set(Op::ReadWriteDone(Err(e)));
91                                    self.do_next_op_async();
92                                }
93                            }
94                        });
95                    }
96                    Op::ReadWriteDone(status) => {
97                        node.txbuffer.take().map(|write_buffer| {
98                            let read_buffer = node.rxbuffer.take();
99                            self.read_write_done(write_buffer, read_buffer, status);
100                        });
101                    }
102                    Op::Idle => {} // Can't get here...
103                }
104            });
105        } else {
106            self.inflight.map(|node| {
107                if let Op::ReadWriteDone(status) = node.operation.get() {
108                    node.txbuffer.take().map(|write_buffer| {
109                        let read_buffer = node.rxbuffer.take();
110                        self.read_write_done(write_buffer, read_buffer, status);
111                    });
112                }
113            });
114        }
115    }
116
117    /// Asynchronously executes the next operation, if any. Used by calls
118    /// to trigger do_next_op such that it will execute after the call
119    /// returns. This is important in case the operation triggers an error,
120    /// requiring a callback with an error condition; if the operation
121    /// is executed synchronously, the callback may be reentrant (executed
122    /// during the downcall). Please see
123    /// <https://github.com/tock/tock/issues/1496>
124    fn do_next_op_async(&self) {
125        self.deferred_call.set();
126    }
127}
128
129impl<'a, Spi: hil::spi::SpiMaster<'a>> DeferredCallClient for MuxSpiMaster<'a, Spi> {
130    fn handle_deferred_call(&self) {
131        self.do_next_op();
132    }
133
134    fn register(&'static self) {
135        self.deferred_call.register(self);
136    }
137}
138
139#[derive(Copy, Clone, PartialEq)]
140enum Op {
141    Idle,
142    ReadWriteBytes,
143    ReadWriteDone(Result<usize, ErrorCode>),
144}
145
146// Structure used to store the SPI configuration of a client/virtual device,
147// so it can restored on each operation.
148struct SpiConfiguration<'a, Spi: hil::spi::SpiMaster<'a>> {
149    chip_select: Spi::ChipSelect,
150    polarity: hil::spi::ClockPolarity,
151    phase: hil::spi::ClockPhase,
152    rate: u32,
153}
154
155// Have to do this manually because otherwise the Copy and Clone are parameterized
156// by Spi::ChipSelect and don't work for Cells.
157// https://stackoverflow.com/questions/63132174/how-do-i-fix-the-method-clone-exists-but-the-following-trait-bounds-were-not
158impl<'a, Spi: hil::spi::SpiMaster<'a>> Copy for SpiConfiguration<'a, Spi> {}
159impl<'a, Spi: hil::spi::SpiMaster<'a>> Clone for SpiConfiguration<'a, Spi> {
160    fn clone(&self) -> SpiConfiguration<'a, Spi> {
161        *self
162    }
163}
164
165pub struct VirtualSpiMasterDevice<'a, Spi: hil::spi::SpiMaster<'a>> {
166    mux: &'a MuxSpiMaster<'a, Spi>,
167    configuration: Cell<SpiConfiguration<'a, Spi>>,
168    txbuffer: MapCell<SubSliceMut<'static, u8>>,
169    rxbuffer: MapCell<SubSliceMut<'static, u8>>,
170    operation: Cell<Op>,
171    next: ListLink<'a, VirtualSpiMasterDevice<'a, Spi>>,
172    client: OptionalCell<&'a dyn hil::spi::SpiMasterClient>,
173}
174
175impl<'a, Spi: hil::spi::SpiMaster<'a>> VirtualSpiMasterDevice<'a, Spi> {
176    pub fn new(
177        mux: &'a MuxSpiMaster<'a, Spi>,
178        chip_select: Spi::ChipSelect,
179    ) -> VirtualSpiMasterDevice<'a, Spi> {
180        VirtualSpiMasterDevice {
181            mux,
182            configuration: Cell::new(SpiConfiguration {
183                chip_select,
184                polarity: hil::spi::ClockPolarity::IdleLow,
185                phase: hil::spi::ClockPhase::SampleLeading,
186                rate: 100_000,
187            }),
188            txbuffer: MapCell::empty(),
189            rxbuffer: MapCell::empty(),
190            operation: Cell::new(Op::Idle),
191            next: ListLink::empty(),
192            client: OptionalCell::empty(),
193        }
194    }
195
196    /// Must be called right after `static_init!()`.
197    pub fn setup(&'a self) {
198        self.mux.devices.push_head(self);
199    }
200}
201
202impl<'a, Spi: hil::spi::SpiMaster<'a>> hil::spi::SpiMasterClient
203    for VirtualSpiMasterDevice<'a, Spi>
204{
205    fn read_write_done(
206        &self,
207        write_buffer: SubSliceMut<'static, u8>,
208        read_buffer: Option<SubSliceMut<'static, u8>>,
209        status: Result<usize, ErrorCode>,
210    ) {
211        self.client.map(move |client| {
212            client.read_write_done(write_buffer, read_buffer, status);
213        });
214    }
215}
216
217impl<'a, Spi: hil::spi::SpiMaster<'a>> ListNode<'a, VirtualSpiMasterDevice<'a, Spi>>
218    for VirtualSpiMasterDevice<'a, Spi>
219{
220    fn next(&'a self) -> &'a ListLink<'a, VirtualSpiMasterDevice<'a, Spi>> {
221        &self.next
222    }
223}
224
225impl<'a, Spi: hil::spi::SpiMaster<'a>> hil::spi::SpiMasterDevice<'a>
226    for VirtualSpiMasterDevice<'a, Spi>
227{
228    fn set_client(&self, client: &'a dyn SpiMasterClient) {
229        self.client.set(client);
230    }
231
232    fn configure(
233        &self,
234        cpol: hil::spi::ClockPolarity,
235        cpal: hil::spi::ClockPhase,
236        rate: u32,
237    ) -> Result<(), ErrorCode> {
238        if self.operation.get() == Op::Idle {
239            let mut configuration = self.configuration.get();
240            configuration.polarity = cpol;
241            configuration.phase = cpal;
242            configuration.rate = rate;
243            self.configuration.set(configuration);
244            Ok(())
245        } else {
246            Err(ErrorCode::BUSY)
247        }
248    }
249
250    fn read_write_bytes(
251        &self,
252        write_buffer: SubSliceMut<'static, u8>,
253        mut read_buffer: Option<SubSliceMut<'static, u8>>,
254    ) -> Result<
255        (),
256        (
257            ErrorCode,
258            SubSliceMut<'static, u8>,
259            Option<SubSliceMut<'static, u8>>,
260        ),
261    > {
262        if self.operation.get() == Op::Idle {
263            self.txbuffer.replace(write_buffer);
264            if let Some(rb) = read_buffer.take() {
265                self.rxbuffer.put(rb);
266            }
267            self.operation.set(Op::ReadWriteBytes);
268            self.mux.do_next_op();
269            Ok(())
270        } else {
271            Err((ErrorCode::BUSY, write_buffer, read_buffer))
272        }
273    }
274
275    fn set_polarity(&self, cpol: hil::spi::ClockPolarity) -> Result<(), ErrorCode> {
276        if self.operation.get() == Op::Idle {
277            let mut configuration = self.configuration.get();
278            configuration.polarity = cpol;
279            self.configuration.set(configuration);
280            Ok(())
281        } else {
282            Err(ErrorCode::BUSY)
283        }
284    }
285
286    fn set_phase(&self, cpal: hil::spi::ClockPhase) -> Result<(), ErrorCode> {
287        if self.operation.get() == Op::Idle {
288            let mut configuration = self.configuration.get();
289            configuration.phase = cpal;
290            self.configuration.set(configuration);
291            Ok(())
292        } else {
293            Err(ErrorCode::BUSY)
294        }
295    }
296
297    fn set_rate(&self, rate: u32) -> Result<(), ErrorCode> {
298        if self.operation.get() == Op::Idle {
299            let mut configuration = self.configuration.get();
300            configuration.rate = rate;
301            self.configuration.set(configuration);
302            Ok(())
303        } else {
304            Err(ErrorCode::BUSY)
305        }
306    }
307
308    fn get_polarity(&self) -> hil::spi::ClockPolarity {
309        self.configuration.get().polarity
310    }
311
312    fn get_phase(&self) -> hil::spi::ClockPhase {
313        self.configuration.get().phase
314    }
315
316    fn get_rate(&self) -> u32 {
317        self.configuration.get().rate
318    }
319}
320
321pub struct SpiSlaveDevice<'a, Spi: hil::spi::SpiSlave<'a>> {
322    spi: &'a Spi,
323    client: OptionalCell<&'a dyn hil::spi::SpiSlaveClient>,
324}
325
326impl<'a, Spi: hil::spi::SpiSlave<'a>> SpiSlaveDevice<'a, Spi> {
327    pub const fn new(spi: &'a Spi) -> SpiSlaveDevice<'a, Spi> {
328        SpiSlaveDevice {
329            spi,
330            client: OptionalCell::empty(),
331        }
332    }
333}
334
335impl<'a, Spi: hil::spi::SpiSlave<'a>> hil::spi::SpiSlaveClient for SpiSlaveDevice<'a, Spi> {
336    fn read_write_done(
337        &self,
338        write_buffer: Option<&'static mut [u8]>,
339        read_buffer: Option<&'static mut [u8]>,
340        len: usize,
341        status: Result<(), ErrorCode>,
342    ) {
343        self.client.map(move |client| {
344            client.read_write_done(write_buffer, read_buffer, len, status);
345        });
346    }
347
348    fn chip_selected(&self) {
349        self.client.map(move |client| {
350            client.chip_selected();
351        });
352    }
353}
354
355impl<'a, Spi: hil::spi::SpiSlave<'a>> hil::spi::SpiSlaveDevice<'a> for SpiSlaveDevice<'a, Spi> {
356    fn set_client(&self, client: &'a dyn hil::spi::SpiSlaveClient) {
357        self.client.set(client);
358    }
359
360    fn configure(
361        &self,
362        cpol: hil::spi::ClockPolarity,
363        cpal: hil::spi::ClockPhase,
364    ) -> Result<(), ErrorCode> {
365        self.spi.set_polarity(cpol)?;
366        self.spi.set_phase(cpal)
367    }
368
369    fn read_write_bytes(
370        &self,
371        write_buffer: Option<&'static mut [u8]>,
372        read_buffer: Option<&'static mut [u8]>,
373        len: usize,
374    ) -> Result<
375        (),
376        (
377            ErrorCode,
378            Option<&'static mut [u8]>,
379            Option<&'static mut [u8]>,
380        ),
381    > {
382        self.spi.read_write_bytes(write_buffer, read_buffer, len)
383    }
384
385    fn set_polarity(&self, cpol: hil::spi::ClockPolarity) -> Result<(), ErrorCode> {
386        self.spi.set_polarity(cpol)
387    }
388
389    fn set_phase(&self, cpal: hil::spi::ClockPhase) -> Result<(), ErrorCode> {
390        self.spi.set_phase(cpal)
391    }
392
393    fn get_polarity(&self) -> hil::spi::ClockPolarity {
394        self.spi.get_polarity()
395    }
396
397    fn get_phase(&self) -> hil::spi::ClockPhase {
398        self.spi.get_phase()
399    }
400}