capsules_extra/
fm25cl.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//! SyscallDriver for the FM25CL FRAM chip.
6//!
7//! <http://www.cypress.com/part/fm25cl64b-dg>
8//!
9//! From the FM25CL website:
10//!
11//! > The FM25CL64B is a 64-Kbit nonvolatile memory employing an advanced
12//! > ferroelectric process. A ferroelectric random access memory or F-RAM is
13//! > nonvolatile and performs reads and writes similar to a RAM. It provides
14//! > reliable data retention for 151 years while eliminating the complexities,
15//! > overhead, and system level reliability problems caused by serial flash,
16//! > EEPROM, and other nonvolatile memories.
17//!
18//! Usage
19//! -----
20//!
21//! ```rust,ignore
22//! # use kernel::static_init;
23//!
24//! // Create a SPI device for this chip.
25//! let fm25cl_spi = static_init!(
26//!     capsules::virtual_spi::VirtualSpiMasterDevice<'static, usart::USART>,
27//!     capsules::virtual_spi::VirtualSpiMasterDevice::new(mux_spi, Some(&sam4l::gpio::PA[25])));
28//! // Setup the actual FM25CL driver.
29//! let fm25cl = static_init!(
30//!     capsules::fm25cl::FM25CL<'static,
31//!     capsules::virtual_spi::VirtualSpiMasterDevice<'static, usart::USART>>,
32//!     capsules::fm25cl::FM25CL::new(fm25cl_spi,
33//!         &mut capsules::fm25cl::TXBUFFER, &mut capsules::fm25cl::RXBUFFER));
34//! fm25cl_spi.set_client(fm25cl);
35//! ```
36//!
37//! This capsule provides two interfaces:
38//!
39//! - `hil::nonvolatile_storage::NonvolatileStorage`
40//! - `FM25CLCustom`
41//!
42//! The first is the generic interface for nonvolatile storage. This allows
43//! this driver to work with capsules like the `nonvolatile_storage_driver`
44//! that provide virtualization and a userspace interface. The second is a
45//! custom interface that exposes other chip-specific functions.
46
47use core::cell::Cell;
48use core::cmp;
49use kernel::hil;
50use kernel::utilities::cells::{MapCell, OptionalCell, TakeCell};
51use kernel::utilities::leasable_buffer::SubSliceMut;
52use kernel::ErrorCode;
53
54pub const BUF_LEN: usize = 512;
55
56const SPI_SPEED: u32 = 4000000;
57
58#[allow(dead_code)]
59enum Opcodes {
60    WriteEnable = 0x06,
61    WriteDisable = 0x04,
62    ReadStatusRegister = 0x05,
63    WriteStatusRegister = 0x01,
64    ReadMemory = 0x03,
65    WriteMemory = 0x02,
66}
67
68#[derive(Clone, Copy, PartialEq)]
69enum State {
70    Idle,
71
72    /// Simple read states
73    ReadStatus,
74
75    /// Write to the FRAM
76    WriteEnable,
77    WriteMemory,
78
79    /// Read from the FRAM
80    ReadMemory,
81}
82
83pub trait FM25CLCustom {
84    fn read_status(&self) -> Result<(), ErrorCode>;
85}
86
87pub trait FM25CLClient {
88    fn status(&self, status: u8);
89    fn read(&self, data: &'static mut [u8], len: usize);
90    fn done(&self, buffer: &'static mut [u8]);
91}
92
93pub struct FM25CL<'a, S: hil::spi::SpiMasterDevice<'a>> {
94    spi: &'a S,
95    state: Cell<State>,
96    txbuffer: MapCell<SubSliceMut<'static, u8>>,
97    rxbuffer: MapCell<SubSliceMut<'static, u8>>,
98    client: OptionalCell<&'a dyn hil::nonvolatile_storage::NonvolatileStorageClient>,
99    client_custom: OptionalCell<&'a dyn FM25CLClient>,
100    client_buffer: TakeCell<'static, [u8]>, // Store buffer and state for passing back to client
101    client_write_address: Cell<u16>,
102    client_write_len: Cell<u16>,
103}
104
105impl<'a, S: hil::spi::SpiMasterDevice<'a>> FM25CL<'a, S> {
106    pub fn new(
107        spi: &'a S,
108        txbuffer: &'static mut [u8],
109        rxbuffer: &'static mut [u8],
110    ) -> FM25CL<'a, S> {
111        // setup and return struct
112        FM25CL {
113            spi,
114            state: Cell::new(State::Idle),
115            txbuffer: MapCell::new(txbuffer.into()),
116            rxbuffer: MapCell::new(rxbuffer.into()),
117            client: OptionalCell::empty(),
118            client_custom: OptionalCell::empty(),
119            client_buffer: TakeCell::empty(),
120            client_write_address: Cell::new(0),
121            client_write_len: Cell::new(0),
122        }
123    }
124
125    pub fn set_client<C: FM25CLClient>(&self, client: &'a C) {
126        self.client_custom.set(client);
127    }
128
129    /// Setup SPI for this chip
130    fn configure_spi(&self) -> Result<(), ErrorCode> {
131        self.spi.configure(
132            hil::spi::ClockPolarity::IdleLow,
133            hil::spi::ClockPhase::SampleLeading,
134            SPI_SPEED,
135        )
136    }
137
138    pub fn write(
139        &self,
140        address: u16,
141        buffer: &'static mut [u8],
142        len: u16,
143    ) -> Result<(), ErrorCode> {
144        self.configure_spi()?;
145
146        self.txbuffer
147            .take()
148            .map_or(Err(ErrorCode::RESERVE), move |mut txbuffer| {
149                let write_len = cmp::min(txbuffer.len(), len as usize);
150
151                // Need to save the buffer passed to us so we can give it back.
152                self.client_buffer.replace(buffer);
153                // Also save address and len for the actual write.
154                self.client_write_address.set(address);
155                self.client_write_len.set(write_len as u16);
156
157                self.state.set(State::WriteEnable);
158                txbuffer[0] = Opcodes::WriteEnable as u8;
159                txbuffer.slice(..1);
160                let res = self.spi.read_write_bytes(txbuffer, None);
161
162                match res {
163                    Ok(()) => Ok(()),
164                    Err((err, txbuffer, _)) => {
165                        self.txbuffer.replace(txbuffer);
166                        Err(err)
167                    }
168                }
169            })
170    }
171
172    pub fn read(&self, address: u16, buffer: &'static mut [u8], len: u16) -> Result<(), ErrorCode> {
173        self.configure_spi()?;
174
175        self.txbuffer
176            .take()
177            .map_or(Err(ErrorCode::RESERVE), |mut txbuffer| {
178                self.rxbuffer
179                    .take()
180                    .map_or(Err(ErrorCode::RESERVE), move |mut rxbuffer| {
181                        txbuffer[0] = Opcodes::ReadMemory as u8;
182                        txbuffer[1] = ((address >> 8) & 0xFF) as u8;
183                        txbuffer[2] = (address & 0xFF) as u8;
184
185                        // Save the user buffer for later
186                        self.client_buffer.replace(buffer);
187
188                        rxbuffer.reset();
189                        let read_len = cmp::min(rxbuffer.len(), 3 + len as usize);
190                        rxbuffer.slice(..read_len);
191
192                        self.state.set(State::ReadMemory);
193                        let res = self.spi.read_write_bytes(txbuffer, Some(rxbuffer));
194                        match res {
195                            Ok(()) => Ok(()),
196                            Err((err, txbuffer, rxbuffer)) => {
197                                self.txbuffer.replace(txbuffer);
198                                self.rxbuffer.replace(rxbuffer.unwrap());
199                                Err(err)
200                            }
201                        }
202                    })
203            })
204    }
205}
206
207impl<'a, S: hil::spi::SpiMasterDevice<'a>> hil::spi::SpiMasterClient for FM25CL<'a, S> {
208    fn read_write_done(
209        &self,
210        mut write_buffer: SubSliceMut<'static, u8>,
211        read_buffer: Option<SubSliceMut<'static, u8>>,
212        _status: Result<usize, ErrorCode>,
213    ) {
214        write_buffer.reset();
215        match self.state.get() {
216            State::ReadStatus => {
217                self.state.set(State::Idle);
218
219                // Put back buffers that we got back from SPI layer.
220                self.txbuffer.replace(write_buffer);
221
222                read_buffer.map(|read_buffer| {
223                    let status = read_buffer[1];
224
225                    // Also replace this buffer
226                    self.rxbuffer.replace(read_buffer);
227
228                    self.client_custom.map(|client| client.status(status));
229                });
230            }
231            State::WriteEnable => {
232                self.state.set(State::WriteMemory);
233
234                self.client_buffer.map(move |buffer| {
235                    write_buffer[0] = Opcodes::WriteMemory as u8;
236                    write_buffer[1] = ((self.client_write_address.get() >> 8) & 0xFF) as u8;
237                    write_buffer[2] = (self.client_write_address.get() & 0xFF) as u8;
238
239                    let write_len =
240                        cmp::min(write_buffer.len(), self.client_write_len.get() as usize);
241
242                    write_buffer[3..(write_len + 3)].copy_from_slice(&buffer[..write_len]);
243                    write_buffer.slice(..write_len + 3);
244
245                    let _ = self.spi.read_write_bytes(write_buffer, read_buffer);
246                });
247            }
248            State::WriteMemory => {
249                self.state.set(State::Idle);
250
251                let write_len = cmp::min(write_buffer.len(), self.client_write_len.get() as usize);
252
253                // Replace these buffers
254                self.txbuffer.replace(write_buffer);
255                read_buffer.map(|read_buffer| {
256                    self.rxbuffer.replace(read_buffer);
257                });
258
259                // Call done with the write() buffer
260                self.client_buffer.take().map(move |buffer| {
261                    self.client
262                        .map(move |client| client.write_done(buffer, write_len));
263                });
264            }
265            State::ReadMemory => {
266                self.state.set(State::Idle);
267
268                // Replace the TX buffer
269                self.txbuffer.replace(write_buffer);
270
271                read_buffer.map(|read_buffer| {
272                    self.client_buffer.take().map(move |buffer| {
273                        let read_len = buffer.len();
274
275                        buffer[..(read_len - 3)]
276                            .copy_from_slice(&read_buffer[3..((read_len - 3) + 3)]);
277
278                        self.rxbuffer.replace(read_buffer);
279
280                        self.client
281                            .map(move |client| client.read_done(buffer, read_len - 3));
282                    });
283                });
284            }
285            _ => {}
286        }
287    }
288}
289
290// Implement the custom interface that exposes chip-specific commands.
291impl<'a, S: hil::spi::SpiMasterDevice<'a>> FM25CLCustom for FM25CL<'a, S> {
292    fn read_status(&self) -> Result<(), ErrorCode> {
293        self.configure_spi()?;
294
295        self.txbuffer
296            .take()
297            .map_or(Err(ErrorCode::RESERVE), |mut txbuffer| {
298                self.rxbuffer
299                    .take()
300                    .map_or(Err(ErrorCode::RESERVE), move |mut rxbuffer| {
301                        txbuffer[0] = Opcodes::ReadStatusRegister as u8;
302
303                        // Use 4 bytes instead of the required 2 because that works better
304                        // with DMA for some reason.
305                        // TODO verify SPI return value
306                        rxbuffer.reset();
307                        rxbuffer.slice(..4);
308                        let _ = self.spi.read_write_bytes(txbuffer, Some(rxbuffer));
309                        self.state.set(State::ReadStatus);
310                        Ok(())
311                    })
312            })
313    }
314}
315
316/// Implement the generic `NonvolatileStorage` interface common to chips that
317/// provide nonvolatile memory.
318impl<'a, S: hil::spi::SpiMasterDevice<'a>> hil::nonvolatile_storage::NonvolatileStorage<'a>
319    for FM25CL<'a, S>
320{
321    fn set_client(&self, client: &'a dyn hil::nonvolatile_storage::NonvolatileStorageClient) {
322        self.client.set(client);
323    }
324
325    fn read(
326        &self,
327        buffer: &'static mut [u8],
328        address: usize,
329        length: usize,
330    ) -> Result<(), ErrorCode> {
331        self.read(address as u16, buffer, length as u16)
332    }
333
334    fn write(
335        &self,
336        buffer: &'static mut [u8],
337        address: usize,
338        length: usize,
339    ) -> Result<(), ErrorCode> {
340        self.write(address as u16, buffer, length as u16)
341    }
342}