opentitanlib/transport/ftdi/
spi.rs1use crate::io::spi::Transfer;
6use anyhow::Result;
7use std::cell::RefCell;
8use std::collections::HashMap;
9use std::rc::Rc;
10
11use embedded_hal::spi::SpiBus;
12
13use ftdi_embedded_hal as ftdi_hal;
14
15use crate::io::gpio;
16use crate::io::spi::AssertChipSelect;
17use crate::io::spi::MaxSizes;
18use crate::io::spi::SpiError;
19use crate::io::spi::TransferMode;
20use crate::transport::Target;
21use crate::transport::TransportError;
22
23pub struct Spi<T> {
24 spi: Rc<RefCell<ftdi_hal::Spi<ftdi::Device>>>,
25 cs: T,
26}
27
28impl<T: gpio::GpioPin> Spi<T> {
29 pub fn open(
30 ftdi_interfaces: &Rc<HashMap<ftdi::Interface, ftdi_hal::FtHal<ftdi::Device>>>,
31 cs: T,
32 ) -> Result<Self> {
33 let hal = ftdi_interfaces
34 .get(&ftdi::Interface::B)
35 .ok_or_else(|| SpiError::InvalidOption("spi interface".to_owned()))?;
36 let spi = hal.spi()?;
37 Ok(Spi {
38 spi: Rc::new(RefCell::new(spi)),
39 cs,
40 })
41 }
42
43 fn spi_transaction(&self, transaction: &mut [Transfer]) -> Result<()> {
45 for transfer in transaction.iter_mut() {
46 match transfer {
47 Transfer::Read(buf) => self.spi.borrow_mut().read(buf)?,
48 Transfer::Write(buf) => self.spi.borrow_mut().write(buf)?,
49 Transfer::Both(wbuf, rbuf) => self.spi.borrow_mut().transfer(rbuf, wbuf)?,
50 Transfer::TpmPoll => (),
51 Transfer::GscReady => (),
52 }
53 }
54 Ok(())
55 }
56}
57
58impl<T: gpio::GpioPin> Target for Spi<T> {
59 fn get_transfer_mode(&self) -> Result<TransferMode> {
60 Ok(TransferMode::Mode0)
61 }
62 fn set_transfer_mode(&self, mode: TransferMode) -> Result<()> {
63 log::warn!(
64 "set_transfer_mode to {:?}, but only Mode0 is supported on this device",
65 mode
66 );
67 Ok(())
68 }
69
70 fn get_bits_per_word(&self) -> Result<u32> {
71 Ok(8)
72 }
73 fn set_bits_per_word(&self, bits_per_word: u32) -> Result<()> {
74 match bits_per_word {
75 8 => Ok(()),
76 _ => Err(SpiError::InvalidWordSize(bits_per_word).into()),
77 }
78 }
79
80 fn get_max_speed(&self) -> Result<u32> {
81 Ok(6_000_000)
82 }
83 fn set_max_speed(&self, frequency: u32) -> Result<()> {
84 log::warn!(
85 "set_max_speed to {:?}, but this device doesn't support changing speeds.",
86 frequency
87 );
88 Ok(())
89 }
90
91 fn supports_bidirectional_transfer(&self) -> Result<bool> {
92 Ok(true)
93 }
94
95 fn supports_tpm_poll(&self) -> Result<bool> {
97 Ok(false)
98 }
99
100 fn set_pins(
101 &self,
102 _serial_clock: Option<&Rc<dyn gpio::GpioPin>>,
103 _host_out_device_in: Option<&Rc<dyn gpio::GpioPin>>,
104 _host_in_device_out: Option<&Rc<dyn gpio::GpioPin>>,
105 _chip_select: Option<&Rc<dyn gpio::GpioPin>>,
106 _gsc_ready: Option<&Rc<dyn gpio::GpioPin>>,
107 ) -> Result<()> {
108 Err(TransportError::UnsupportedOperation.into())
109 }
110
111 fn get_max_transfer_count(&self) -> Result<usize> {
112 Ok(42)
114 }
115
116 fn get_max_transfer_sizes(&self) -> Result<MaxSizes> {
117 Ok(MaxSizes {
118 read: 1024,
119 write: 1024,
120 })
121 }
122
123 fn run_transaction(&self, transaction: &mut [Transfer]) -> Result<()> {
124 self.cs.write(false)?;
126 let result = self.spi_transaction(transaction);
128 self.cs.write(true)?;
130 result
131 }
132
133 fn assert_cs(self: Rc<Self>) -> Result<AssertChipSelect> {
134 Err(TransportError::UnsupportedOperation.into())
135 }
136}