capsules_core/virtualizers/
virtual_i2c.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 an I2C master bus.
6//!
7//! `MuxI2C` provides shared access to a single I2C Master Bus for multiple
8//! users. `I2CDevice` provides access to a specific I2C address.
9
10use core::cell::Cell;
11
12use kernel::collections::list::{List, ListLink, ListNode};
13use kernel::deferred_call::{DeferredCall, DeferredCallClient};
14use kernel::hil::i2c::{self, Error, I2CClient, I2CHwMasterClient, NoSMBus};
15use kernel::utilities::cells::{OptionalCell, TakeCell};
16// `NoSMBus` provides a placeholder for `SMBusMaster` in case the board doesn't have a SMBus
17pub struct MuxI2C<'a, I: i2c::I2CMaster<'a>, S: i2c::SMBusMaster<'a> = NoSMBus> {
18    i2c: &'a I,
19    smbus: Option<&'a S>,
20    i2c_devices: List<'a, I2CDevice<'a, I, S>>,
21    smbus_devices: List<'a, SMBusDevice<'a, I, S>>,
22    enabled: Cell<usize>,
23    i2c_inflight: OptionalCell<&'a I2CDevice<'a, I, S>>,
24    smbus_inflight: OptionalCell<&'a SMBusDevice<'a, I, S>>,
25    deferred_call: DeferredCall,
26}
27
28impl<'a, I: i2c::I2CMaster<'a>, S: i2c::SMBusMaster<'a>> I2CHwMasterClient for MuxI2C<'a, I, S> {
29    fn command_complete(&self, buffer: &'static mut [u8], status: Result<(), Error>) {
30        if self.i2c_inflight.is_some() {
31            self.i2c_inflight.take().map(move |device| {
32                device.command_complete(buffer, status);
33            });
34        } else if self.smbus_inflight.is_some() {
35            self.smbus_inflight.take().map(move |device| {
36                device.command_complete(buffer, status);
37            });
38        }
39        self.do_next_op();
40    }
41}
42
43impl<'a, I: i2c::I2CMaster<'a>, S: i2c::SMBusMaster<'a>> MuxI2C<'a, I, S> {
44    pub fn new(i2c: &'a I, smbus: Option<&'a S>) -> Self {
45        Self {
46            i2c,
47            smbus,
48            i2c_devices: List::new(),
49            smbus_devices: List::new(),
50            enabled: Cell::new(0),
51            i2c_inflight: OptionalCell::empty(),
52            smbus_inflight: OptionalCell::empty(),
53            deferred_call: DeferredCall::new(),
54        }
55    }
56
57    fn enable(&self) {
58        let enabled = self.enabled.get();
59        self.enabled.set(enabled + 1);
60        if enabled == 0 {
61            self.i2c.enable();
62        }
63    }
64
65    fn disable(&self) {
66        let enabled = self.enabled.get();
67        self.enabled.set(enabled - 1);
68        if enabled == 1 {
69            self.i2c.disable();
70        }
71    }
72
73    fn do_next_op(&self) {
74        if self.i2c_inflight.is_none() && self.smbus_inflight.is_none() {
75            // Nothing is currently in flight
76
77            // Try to do the next I2C operation
78            let mnode = self
79                .i2c_devices
80                .iter()
81                .find(|node| node.operation.get() != Op::Idle);
82            mnode.map(|node| {
83                node.buffer.take().map(|buf| {
84                    match node.operation.get() {
85                        Op::Write(len) => match self.i2c.write(node.addr, buf, len) {
86                            Ok(()) => {}
87                            Err((error, buffer)) => {
88                                node.buffer.replace(buffer);
89                                node.operation.set(Op::CommandComplete(Err(error)));
90                                node.mux.do_next_op_async();
91                            }
92                        },
93                        Op::Read(len) => match self.i2c.read(node.addr, buf, len) {
94                            Ok(()) => {}
95                            Err((error, buffer)) => {
96                                node.buffer.replace(buffer);
97                                node.operation.set(Op::CommandComplete(Err(error)));
98                                node.mux.do_next_op_async();
99                            }
100                        },
101                        Op::WriteRead(wlen, rlen) => {
102                            match self.i2c.write_read(node.addr, buf, wlen, rlen) {
103                                Ok(()) => {}
104                                Err((error, buffer)) => {
105                                    node.buffer.replace(buffer);
106                                    node.operation.set(Op::CommandComplete(Err(error)));
107                                    node.mux.do_next_op_async();
108                                }
109                            }
110                        }
111                        Op::CommandComplete(err) => {
112                            self.command_complete(buf, err);
113                        }
114                        Op::Idle => {} // Can't get here...
115                    }
116                });
117                node.operation.set(Op::Idle);
118                self.i2c_inflight.set(node);
119            });
120
121            if self.i2c_inflight.is_none() && self.smbus.is_some() {
122                // No I2C operation in flight, try SMBus next
123                let mnode = self
124                    .smbus_devices
125                    .iter()
126                    .find(|node| node.operation.get() != Op::Idle);
127                mnode.map(|node| {
128                    node.buffer.take().map(|buf| match node.operation.get() {
129                        Op::Write(len) => {
130                            match self.smbus.unwrap().smbus_write(node.addr, buf, len) {
131                                Ok(()) => {}
132                                Err(e) => {
133                                    node.buffer.replace(e.1);
134                                    node.operation.set(Op::CommandComplete(Err(e.0)));
135                                    node.mux.do_next_op_async();
136                                }
137                            }
138                        }
139                        Op::Read(len) => {
140                            match self.smbus.unwrap().smbus_read(node.addr, buf, len) {
141                                Ok(()) => {}
142                                Err(e) => {
143                                    node.buffer.replace(e.1);
144                                    node.operation.set(Op::CommandComplete(Err(e.0)));
145                                    node.mux.do_next_op_async();
146                                }
147                            }
148                        }
149                        Op::WriteRead(wlen, rlen) => {
150                            match self
151                                .smbus
152                                .unwrap()
153                                .smbus_write_read(node.addr, buf, wlen, rlen)
154                            {
155                                Ok(()) => {}
156                                Err(e) => {
157                                    node.buffer.replace(e.1);
158                                    node.operation.set(Op::CommandComplete(Err(e.0)));
159                                    node.mux.do_next_op_async();
160                                }
161                            }
162                        }
163                        Op::CommandComplete(err) => {
164                            self.command_complete(buf, err);
165                        }
166                        Op::Idle => unreachable!(),
167                    });
168                    node.operation.set(Op::Idle);
169                    self.smbus_inflight.set(node);
170                });
171            }
172        }
173    }
174
175    /// Asynchronously executes the next operation, if any. Used by calls
176    /// to trigger do_next_op such that it will execute after the call
177    /// returns. This is important in case the operation triggers an error,
178    /// requiring a callback with an error condition; if the operation
179    /// is executed synchronously, the callback may be reentrant (executed
180    /// during the downcall). Please see
181    /// <https://github.com/tock/tock/issues/1496>
182    fn do_next_op_async(&self) {
183        self.deferred_call.set();
184    }
185}
186
187impl<'a, I: i2c::I2CMaster<'a>, S: i2c::SMBusMaster<'a>> DeferredCallClient for MuxI2C<'a, I, S> {
188    fn handle_deferred_call(&self) {
189        self.do_next_op();
190    }
191
192    fn register(&'static self) {
193        self.deferred_call.register(self);
194    }
195}
196
197#[derive(Copy, Clone, PartialEq)]
198enum Op {
199    Idle,
200    Write(usize),
201    Read(usize),
202    WriteRead(usize, usize),
203    CommandComplete(Result<(), Error>),
204}
205
206pub struct I2CDevice<'a, I: i2c::I2CMaster<'a>, S: i2c::SMBusMaster<'a> = NoSMBus> {
207    mux: &'a MuxI2C<'a, I, S>,
208    addr: u8,
209    enabled: Cell<bool>,
210    buffer: TakeCell<'static, [u8]>,
211    operation: Cell<Op>,
212    next: ListLink<'a, I2CDevice<'a, I, S>>,
213    client: OptionalCell<&'a dyn I2CClient>,
214}
215
216impl<'a, I: i2c::I2CMaster<'a>, S: i2c::SMBusMaster<'a>> I2CDevice<'a, I, S> {
217    pub fn new(mux: &'a MuxI2C<'a, I, S>, addr: u8) -> I2CDevice<'a, I, S> {
218        I2CDevice {
219            mux,
220            addr,
221            enabled: Cell::new(false),
222            buffer: TakeCell::empty(),
223            operation: Cell::new(Op::Idle),
224            next: ListLink::empty(),
225            client: OptionalCell::empty(),
226        }
227    }
228
229    pub fn set_client(&'a self, client: &'a dyn I2CClient) {
230        self.mux.i2c_devices.push_head(self);
231        self.client.set(client);
232    }
233}
234
235impl<'a, I: i2c::I2CMaster<'a>, S: i2c::SMBusMaster<'a>> I2CClient for I2CDevice<'a, I, S> {
236    fn command_complete(&self, buffer: &'static mut [u8], status: Result<(), Error>) {
237        self.client.map(move |client| {
238            client.command_complete(buffer, status);
239        });
240    }
241}
242
243impl<'a, I: i2c::I2CMaster<'a>, S: i2c::SMBusMaster<'a>> ListNode<'a, I2CDevice<'a, I, S>>
244    for I2CDevice<'a, I, S>
245{
246    fn next(&'a self) -> &'a ListLink<'a, I2CDevice<'a, I, S>> {
247        &self.next
248    }
249}
250
251impl<'a, I: i2c::I2CMaster<'a>> i2c::I2CDevice for I2CDevice<'a, I> {
252    fn enable(&self) {
253        if !self.enabled.get() {
254            self.enabled.set(true);
255            self.mux.enable();
256        }
257    }
258
259    fn disable(&self) {
260        if self.enabled.get() {
261            self.enabled.set(false);
262            self.mux.disable();
263        }
264    }
265
266    fn write_read(
267        &self,
268        data: &'static mut [u8],
269        write_len: usize,
270        read_len: usize,
271    ) -> Result<(), (Error, &'static mut [u8])> {
272        if self.operation.get() == Op::Idle {
273            self.buffer.replace(data);
274            self.operation.set(Op::WriteRead(write_len, read_len));
275            self.mux.do_next_op();
276            Ok(())
277        } else {
278            Err((Error::ArbitrationLost, data))
279        }
280    }
281
282    fn write(&self, data: &'static mut [u8], len: usize) -> Result<(), (Error, &'static mut [u8])> {
283        if self.operation.get() == Op::Idle {
284            self.buffer.replace(data);
285            self.operation.set(Op::Write(len));
286            self.mux.do_next_op();
287            Ok(())
288        } else {
289            Err((Error::ArbitrationLost, data))
290        }
291    }
292
293    fn read(
294        &self,
295        buffer: &'static mut [u8],
296        len: usize,
297    ) -> Result<(), (Error, &'static mut [u8])> {
298        if self.operation.get() == Op::Idle {
299            self.buffer.replace(buffer);
300            self.operation.set(Op::Read(len));
301            self.mux.do_next_op();
302            Ok(())
303        } else {
304            Err((Error::ArbitrationLost, buffer))
305        }
306    }
307}
308
309pub struct SMBusDevice<'a, I: i2c::I2CMaster<'a>, S: i2c::SMBusMaster<'a>> {
310    mux: &'a MuxI2C<'a, I, S>,
311    addr: u8,
312    enabled: Cell<bool>,
313    buffer: TakeCell<'static, [u8]>,
314    operation: Cell<Op>,
315    next: ListLink<'a, SMBusDevice<'a, I, S>>,
316    client: OptionalCell<&'a dyn I2CClient>,
317}
318
319impl<'a, I: i2c::I2CMaster<'a>, S: i2c::SMBusMaster<'a>> SMBusDevice<'a, I, S> {
320    pub fn new(mux: &'a MuxI2C<'a, I, S>, addr: u8) -> SMBusDevice<'a, I, S> {
321        if mux.smbus.is_none() {
322            panic!("There is no SMBus to attach to");
323        }
324
325        SMBusDevice {
326            mux,
327            addr,
328            enabled: Cell::new(false),
329            buffer: TakeCell::empty(),
330            operation: Cell::new(Op::Idle),
331            next: ListLink::empty(),
332            client: OptionalCell::empty(),
333        }
334    }
335
336    pub fn set_client(&'a self, client: &'a dyn I2CClient) {
337        self.mux.smbus_devices.push_head(self);
338        self.client.set(client);
339    }
340}
341
342impl<'a, I: i2c::I2CMaster<'a>, S: i2c::SMBusMaster<'a>> I2CClient for SMBusDevice<'a, I, S> {
343    fn command_complete(&self, buffer: &'static mut [u8], status: Result<(), Error>) {
344        self.client.map(move |client| {
345            client.command_complete(buffer, status);
346        });
347    }
348}
349
350impl<'a, I: i2c::I2CMaster<'a>, S: i2c::SMBusMaster<'a>> ListNode<'a, SMBusDevice<'a, I, S>>
351    for SMBusDevice<'a, I, S>
352{
353    fn next(&'a self) -> &'a ListLink<'a, SMBusDevice<'a, I, S>> {
354        &self.next
355    }
356}
357
358impl<'a, I: i2c::I2CMaster<'a>, S: i2c::SMBusMaster<'a>> i2c::I2CDevice for SMBusDevice<'a, I, S> {
359    fn enable(&self) {
360        if !self.enabled.get() {
361            self.enabled.set(true);
362            self.mux.enable();
363        }
364    }
365
366    fn disable(&self) {
367        if self.enabled.get() {
368            self.enabled.set(false);
369            self.mux.disable();
370        }
371    }
372
373    fn write_read(
374        &self,
375        data: &'static mut [u8],
376        write_len: usize,
377        read_len: usize,
378    ) -> Result<(), (Error, &'static mut [u8])> {
379        if self.operation.get() == Op::Idle {
380            self.buffer.replace(data);
381            self.operation.set(Op::WriteRead(write_len, read_len));
382            self.mux.do_next_op();
383            Ok(())
384        } else {
385            Err((Error::ArbitrationLost, data))
386        }
387    }
388
389    fn write(&self, data: &'static mut [u8], len: usize) -> Result<(), (Error, &'static mut [u8])> {
390        if self.operation.get() == Op::Idle {
391            self.buffer.replace(data);
392            self.operation.set(Op::Write(len));
393            self.mux.do_next_op();
394            Ok(())
395        } else {
396            Err((Error::ArbitrationLost, data))
397        }
398    }
399
400    fn read(
401        &self,
402        buffer: &'static mut [u8],
403        len: usize,
404    ) -> Result<(), (Error, &'static mut [u8])> {
405        if self.operation.get() == Op::Idle {
406            self.buffer.replace(buffer);
407            self.operation.set(Op::Read(len));
408            self.mux.do_next_op();
409            Ok(())
410        } else {
411            Err((Error::ArbitrationLost, buffer))
412        }
413    }
414}
415
416impl<'a, I: i2c::I2CMaster<'a>, S: i2c::SMBusMaster<'a>> i2c::SMBusDevice
417    for SMBusDevice<'a, I, S>
418{
419    fn smbus_write_read(
420        &self,
421        data: &'static mut [u8],
422        write_len: usize,
423        read_len: usize,
424    ) -> Result<(), (Error, &'static mut [u8])> {
425        if self.operation.get() == Op::Idle {
426            self.buffer.replace(data);
427            self.operation.set(Op::WriteRead(write_len, read_len));
428            self.mux.do_next_op();
429            Ok(())
430        } else {
431            Err((Error::ArbitrationLost, data))
432        }
433    }
434
435    fn smbus_write(
436        &self,
437        data: &'static mut [u8],
438        len: usize,
439    ) -> Result<(), (Error, &'static mut [u8])> {
440        if self.operation.get() == Op::Idle {
441            self.buffer.replace(data);
442            self.operation.set(Op::Write(len));
443            self.mux.do_next_op();
444            Ok(())
445        } else {
446            Err((Error::ArbitrationLost, data))
447        }
448    }
449
450    fn smbus_read(
451        &self,
452        buffer: &'static mut [u8],
453        len: usize,
454    ) -> Result<(), (Error, &'static mut [u8])> {
455        if self.operation.get() == Op::Idle {
456            self.buffer.replace(buffer);
457            self.operation.set(Op::Read(len));
458            self.mux.do_next_op();
459            Ok(())
460        } else {
461            Err((Error::ArbitrationLost, buffer))
462        }
463    }
464}