lowrisc/
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//! I2C Master Driver
6
7use crate::registers::i2c_regs::{
8    CTRL, FDATA, FIFO_CTRL, INTR, RDATA, STATUS, TIMING0, TIMING1, TIMING2, TIMING3, TIMING4,
9};
10use core::cell::Cell;
11use kernel::hil;
12use kernel::hil::i2c;
13use kernel::utilities::cells::OptionalCell;
14use kernel::utilities::cells::TakeCell;
15use kernel::utilities::registers::interfaces::{ReadWriteable, Readable, Writeable};
16use kernel::utilities::StaticRef;
17
18pub use crate::registers::i2c_regs::I2cRegisters;
19
20pub struct I2c<'a> {
21    registers: StaticRef<I2cRegisters>,
22    clock_period_nanos: u32,
23
24    master_client: OptionalCell<&'a dyn hil::i2c::I2CHwMasterClient>,
25
26    // Set when calling the write_read operation
27    // This specifies the address of the read operation
28    // after the write operation. Set to 0 for single read/write operations.
29    slave_read_address: Cell<u8>,
30
31    buffer: TakeCell<'static, [u8]>,
32    write_len: Cell<usize>,
33    write_index: Cell<usize>,
34
35    read_len: Cell<usize>,
36    read_index: Cell<usize>,
37}
38
39impl<'a> I2c<'a> {
40    pub fn new(base: StaticRef<I2cRegisters>, clock_period_nanos: u32) -> I2c<'a> {
41        I2c {
42            registers: base,
43            clock_period_nanos,
44            master_client: OptionalCell::empty(),
45            slave_read_address: Cell::new(0),
46            buffer: TakeCell::empty(),
47            write_len: Cell::new(0),
48            write_index: Cell::new(0),
49            read_len: Cell::new(0),
50            read_index: Cell::new(0),
51        }
52    }
53
54    pub fn handle_interrupt(&self) {
55        let regs = self.registers;
56        let irqs = regs.intr_state.extract();
57
58        // Clear all interrupts
59        regs.intr_state.modify(
60            INTR::FMT_THRESHOLD::SET
61                + INTR::RX_THRESHOLD::SET
62                + INTR::FMT_OVERFLOW::SET
63                + INTR::RX_OVERFLOW::SET
64                + INTR::NAK::SET
65                + INTR::SCL_INTERFERENCE::SET
66                + INTR::SDA_INTERFERENCE::SET
67                + INTR::STRETCH_TIMEOUT::SET
68                + INTR::SDA_UNSTABLE::SET,
69        );
70
71        if irqs.is_set(INTR::FMT_THRESHOLD) {
72            // FMT Watermark
73            if self.slave_read_address.get() != 0 {
74                self.write_read_data();
75            } else {
76                self.write_data();
77            }
78        }
79
80        if irqs.is_set(INTR::RX_THRESHOLD) {
81            // RX Watermark
82            self.read_data();
83        }
84    }
85
86    fn timing_parameter_init(&self, clock_period_nanos: u32) {
87        let regs = self.registers;
88
89        // Setup the timing variables for Fast I2C
90        regs.timing0.modify(
91            TIMING0::THIGH.val(600 / clock_period_nanos)
92                + TIMING0::TLOW.val(1300 / clock_period_nanos),
93        );
94        regs.timing1
95            .modify(TIMING1::T_F.val(167) + TIMING1::T_R.val(40));
96        regs.timing2.modify(
97            TIMING2::THD_STA.val(600 / clock_period_nanos)
98                + TIMING2::TSU_STA.val(600 / clock_period_nanos),
99        );
100        regs.timing3
101            .modify(TIMING3::THD_DAT.val(100 / clock_period_nanos) + TIMING3::TSU_DAT.val(0));
102        regs.timing4.modify(
103            TIMING4::T_BUF.val(600 / clock_period_nanos)
104                + TIMING4::TSU_STO.val(1300 / clock_period_nanos),
105        );
106    }
107
108    fn fifo_reset(&self) {
109        let regs = self.registers;
110
111        regs.fifo_ctrl
112            .modify(FIFO_CTRL::RXRST::SET + FIFO_CTRL::FMTRST::SET);
113    }
114
115    fn read_data(&self) {
116        let regs = self.registers;
117        let mut data_popped = self.read_index.get();
118        let len = self.read_len.get();
119
120        self.buffer.map(|buf| {
121            for i in self.read_index.get()..len {
122                if regs.status.is_set(STATUS::RXEMPTY) {
123                    // The RX buffer is empty
124                    data_popped = i;
125                    break;
126                }
127                // Read the data
128                buf[i] = regs.rdata.read(RDATA::RDATA) as u8;
129                data_popped = i;
130            }
131
132            if data_popped == len {
133                // Finished call the callback
134                self.master_client.map(|client| {
135                    client.command_complete(self.buffer.take().unwrap(), Ok(()));
136                });
137            } else {
138                self.read_index.set(data_popped + 1);
139
140                // Update the FIFO depth
141                if len - data_popped > 8 {
142                    regs.fifo_ctrl.modify(FIFO_CTRL::RXILVL::RXLVL8);
143                } else if len - data_popped > 4 {
144                    regs.fifo_ctrl.modify(FIFO_CTRL::RXILVL::RXLVL4);
145                } else {
146                    regs.fifo_ctrl.modify(FIFO_CTRL::RXILVL::RXLVL1);
147                }
148            }
149        });
150    }
151
152    fn write_data(&self) {
153        let regs = self.registers;
154        let mut data_pushed = self.write_index.get();
155        let len = self.write_len.get();
156
157        self.buffer.map(|buf| {
158            for i in self.write_index.get()..(len - 1) {
159                if regs.status.read(STATUS::FMTFULL) != 0 {
160                    // The FMT buffer is full
161                    data_pushed = i;
162                    break;
163                }
164                // Send the data
165                regs.fdata
166                    .write(FDATA::FBYTE.val(*buf.get(i).unwrap_or(&0) as u32));
167                data_pushed = i;
168            }
169
170            // Check if we can send the last byte
171            if regs.status.read(STATUS::FMTFULL) == 0 && data_pushed == (len - 1) {
172                // Send the last byte with the stop signal
173                regs.fdata
174                    .write(FDATA::FBYTE.val(*buf.get(len).unwrap_or(&0) as u32) + FDATA::STOP::SET);
175
176                data_pushed = len;
177            }
178
179            if data_pushed == len {
180                // Finished call the callback
181                self.master_client.map(|client| {
182                    client.command_complete(self.buffer.take().unwrap(), Ok(()));
183                });
184            } else {
185                self.write_index.set(data_pushed + 1);
186
187                // Update the FIFO depth
188                if len - data_pushed > 8 {
189                    regs.fifo_ctrl.modify(FIFO_CTRL::FMTILVL::FMTLVL8);
190                } else if len - data_pushed > 4 {
191                    regs.fifo_ctrl.modify(FIFO_CTRL::FMTILVL::FMTLVL4);
192                } else {
193                    regs.fifo_ctrl.modify(FIFO_CTRL::FMTILVL::FMTLVL1);
194                }
195            }
196        });
197    }
198
199    fn write_read_data(&self) {
200        let regs = self.registers;
201        let mut data_pushed = self.write_index.get();
202        let len = self.write_len.get();
203
204        self.buffer.map(|buf| {
205            let start_index = data_pushed;
206            for i in start_index..(len - 1) {
207                if regs.status.read(STATUS::FMTFULL) != 0 {
208                    // The FMT buffer is full
209                    data_pushed = i;
210                    break;
211                }
212                // Send the data
213                regs.fdata
214                    .write(FDATA::FBYTE.val(*buf.get(i).unwrap_or(&0) as u32));
215                data_pushed = i;
216            }
217
218            // Check if we can send the last byte
219            if regs.status.read(STATUS::FMTFULL) == 0 && data_pushed == (len - 1) {
220                // Send the last byte with the stop signal
221                regs.fdata
222                    .write(FDATA::FBYTE.val(*buf.get(len).unwrap_or(&0) as u32) + FDATA::STOP::SET);
223
224                data_pushed = len;
225            }
226
227            if data_pushed == len {
228                // Finished writing. Read the data as well.
229                // Set the LSB to signal a read
230                let read_addr = self.slave_read_address.get() | 1;
231
232                // Set the start condition and the address
233                regs.fdata
234                    .write(FDATA::START::SET + FDATA::FBYTE.val(read_addr as u32));
235
236                self.read_data();
237            } else {
238                self.write_index.set(data_pushed + 1);
239
240                // Update the FIFO depth
241                if len - data_pushed > 8 {
242                    regs.fifo_ctrl.modify(FIFO_CTRL::FMTILVL::FMTLVL8);
243                } else if len - data_pushed > 4 {
244                    regs.fifo_ctrl.modify(FIFO_CTRL::FMTILVL::FMTLVL4);
245                } else {
246                    regs.fifo_ctrl.modify(FIFO_CTRL::FMTILVL::FMTLVL1);
247                }
248            }
249        });
250    }
251}
252
253impl<'a> hil::i2c::I2CMaster<'a> for I2c<'a> {
254    fn set_master_client(&self, master_client: &'a dyn i2c::I2CHwMasterClient) {
255        self.master_client.set(master_client);
256    }
257
258    fn enable(&self) {
259        let regs = self.registers;
260
261        self.timing_parameter_init(self.clock_period_nanos);
262        self.fifo_reset();
263
264        // Enable all interrupts
265        regs.intr_enable.modify(
266            INTR::FMT_THRESHOLD::SET
267                + INTR::RX_THRESHOLD::SET
268                + INTR::FMT_OVERFLOW::SET
269                + INTR::RX_OVERFLOW::SET
270                + INTR::NAK::SET
271                + INTR::SCL_INTERFERENCE::SET
272                + INTR::SDA_INTERFERENCE::SET
273                + INTR::STRETCH_TIMEOUT::SET
274                + INTR::SDA_UNSTABLE::SET,
275        );
276
277        // Enable I2C Host
278        regs.ctrl.modify(CTRL::ENABLEHOST::SET);
279    }
280
281    fn disable(&self) {
282        let regs = self.registers;
283
284        regs.ctrl.modify(CTRL::ENABLEHOST::CLEAR);
285    }
286
287    fn write_read(
288        &self,
289        addr: u8,
290        data: &'static mut [u8],
291        write_len: usize,
292        read_len: usize,
293    ) -> Result<(), (hil::i2c::Error, &'static mut [u8])> {
294        let regs = self.registers;
295
296        // Set the FIFO depth and reset the FIFO
297        if write_len > 8 {
298            regs.fifo_ctrl.modify(FIFO_CTRL::FMTILVL::FMTLVL8);
299        } else if write_len > 4 {
300            regs.fifo_ctrl.modify(FIFO_CTRL::FMTILVL::FMTLVL4);
301        } else {
302            regs.fifo_ctrl.modify(FIFO_CTRL::FMTILVL::FMTLVL1);
303        }
304
305        if read_len > 8 {
306            regs.fifo_ctrl.modify(FIFO_CTRL::RXILVL::RXLVL8);
307        } else if read_len > 4 {
308            regs.fifo_ctrl.modify(FIFO_CTRL::RXILVL::RXLVL4);
309        } else {
310            regs.fifo_ctrl.modify(FIFO_CTRL::RXILVL::RXLVL1);
311        }
312
313        self.fifo_reset();
314
315        // Zero out the LSB to signal a write
316        let write_addr = addr & !1;
317
318        // Set the start condition and the address
319        regs.fdata
320            .write(FDATA::START::SET + FDATA::FBYTE.val(write_addr as u32));
321
322        // Save all the data and offsets we still need to send and receive
323        self.slave_read_address.set(addr);
324        self.buffer.replace(data);
325        self.write_len.set(write_len);
326        self.read_len.set(read_len);
327        self.write_index.set(0);
328        self.read_index.set(0);
329
330        self.write_read_data();
331
332        Ok(())
333    }
334
335    fn write(
336        &self,
337        addr: u8,
338        data: &'static mut [u8],
339        len: usize,
340    ) -> Result<(), (hil::i2c::Error, &'static mut [u8])> {
341        let regs = self.registers;
342
343        // Set the FIFO depth and reset the FIFO
344        if len > 8 {
345            regs.fifo_ctrl.modify(FIFO_CTRL::FMTILVL::FMTLVL8);
346        } else if len > 4 {
347            regs.fifo_ctrl.modify(FIFO_CTRL::FMTILVL::FMTLVL4);
348        } else {
349            regs.fifo_ctrl.modify(FIFO_CTRL::FMTILVL::FMTLVL1);
350        }
351
352        self.fifo_reset();
353
354        // Zero out the LSB to signal a write
355        let write_addr = addr & !1;
356
357        // Set the start condition and the address
358        regs.fdata
359            .write(FDATA::START::SET + FDATA::FBYTE.val(write_addr as u32));
360
361        // Save all the data and offsets we still need to send
362        self.slave_read_address.set(0);
363        self.buffer.replace(data);
364        self.write_len.set(len);
365        self.write_index.set(0);
366
367        self.write_data();
368
369        Ok(())
370    }
371
372    fn read(
373        &self,
374        addr: u8,
375        buffer: &'static mut [u8],
376        len: usize,
377    ) -> Result<(), (hil::i2c::Error, &'static mut [u8])> {
378        let regs = self.registers;
379
380        // Set the FIFO depth and reset the FIFO
381        if len > 8 {
382            regs.fifo_ctrl.modify(FIFO_CTRL::RXILVL::RXLVL8);
383        } else if len > 4 {
384            regs.fifo_ctrl.modify(FIFO_CTRL::RXILVL::RXLVL4);
385        } else {
386            regs.fifo_ctrl.modify(FIFO_CTRL::RXILVL::RXLVL1);
387        }
388
389        self.fifo_reset();
390
391        // Set the LSB to signal a read
392        let read_addr = addr | 1;
393
394        // Set the start condition and the address
395        regs.fdata
396            .write(FDATA::START::SET + FDATA::FBYTE.val(read_addr as u32));
397
398        // Save all the data and offsets we still need to read
399        self.slave_read_address.set(0);
400        self.buffer.replace(buffer);
401        self.read_len.set(len);
402        self.read_index.set(0);
403
404        self.read_data();
405
406        Ok(())
407    }
408}