1 /*
2  * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include "hardware/i2c.h"
8 #include "hardware/resets.h"
9 #include "hardware/clocks.h"
10 #include "pico/timeout_helper.h"
11 
12 check_hw_layout(i2c_hw_t, enable, I2C_IC_ENABLE_OFFSET);
13 check_hw_layout(i2c_hw_t, clr_restart_det, I2C_IC_CLR_RESTART_DET_OFFSET);
14 
15 i2c_inst_t i2c0_inst = {i2c0_hw, false};
16 i2c_inst_t i2c1_inst = {i2c1_hw, false};
17 
i2c_reset(i2c_inst_t * i2c)18 static inline void i2c_reset(i2c_inst_t *i2c) {
19     invalid_params_if(I2C, i2c != i2c0 && i2c != i2c1);
20     reset_block(i2c == i2c0 ? RESETS_RESET_I2C0_BITS : RESETS_RESET_I2C1_BITS);
21 }
22 
i2c_unreset(i2c_inst_t * i2c)23 static inline void i2c_unreset(i2c_inst_t *i2c) {
24     invalid_params_if(I2C, i2c != i2c0 && i2c != i2c1);
25     unreset_block_wait(i2c == i2c0 ? RESETS_RESET_I2C0_BITS : RESETS_RESET_I2C1_BITS);
26 }
27 
28 // Addresses of the form 000 0xxx or 111 1xxx are reserved. No slave should
29 // have these addresses.
i2c_reserved_addr(uint8_t addr)30 static inline bool i2c_reserved_addr(uint8_t addr) {
31     return (addr & 0x78) == 0 || (addr & 0x78) == 0x78;
32 }
33 
i2c_init(i2c_inst_t * i2c,uint baudrate)34 uint i2c_init(i2c_inst_t *i2c, uint baudrate) {
35     i2c_reset(i2c);
36     i2c_unreset(i2c);
37     i2c->restart_on_next = false;
38 
39     i2c->hw->enable = 0;
40 
41     // Configure as a fast-mode master with RepStart support, 7-bit addresses
42     i2c->hw->con =
43             I2C_IC_CON_SPEED_VALUE_FAST << I2C_IC_CON_SPEED_LSB |
44             I2C_IC_CON_MASTER_MODE_BITS |
45             I2C_IC_CON_IC_SLAVE_DISABLE_BITS |
46             I2C_IC_CON_IC_RESTART_EN_BITS;
47 
48     // Set FIFO watermarks to 1 to make things simpler. This is encoded by a register value of 0.
49     i2c->hw->tx_tl = 0;
50     i2c->hw->rx_tl = 0;
51 
52     // Always enable the DREQ signalling -- harmless if DMA isn't listening
53     i2c->hw->dma_cr = I2C_IC_DMA_CR_TDMAE_BITS | I2C_IC_DMA_CR_RDMAE_BITS;
54 
55     // Re-sets i2c->hw->enable upon returning:
56     return i2c_set_baudrate(i2c, baudrate);
57 }
58 
i2c_deinit(i2c_inst_t * i2c)59 void i2c_deinit(i2c_inst_t *i2c) {
60     i2c_reset(i2c);
61 }
62 
i2c_set_baudrate(i2c_inst_t * i2c,uint baudrate)63 uint i2c_set_baudrate(i2c_inst_t *i2c, uint baudrate) {
64     invalid_params_if(I2C, baudrate == 0);
65     // I2C is synchronous design that runs from clk_sys
66     uint freq_in = clock_get_hz(clk_sys);
67 
68     // TODO there are some subtleties to I2C timing which we are completely ignoring here
69     uint period = (freq_in + baudrate / 2) / baudrate;
70     uint hcnt = period * 3 / 5; // oof this one hurts
71     uint lcnt = period - hcnt;
72     // Check for out-of-range divisors:
73     invalid_params_if(I2C, hcnt > I2C_IC_FS_SCL_HCNT_IC_FS_SCL_HCNT_BITS);
74     invalid_params_if(I2C, lcnt > I2C_IC_FS_SCL_LCNT_IC_FS_SCL_LCNT_BITS);
75     invalid_params_if(I2C, hcnt < 8);
76     invalid_params_if(I2C, lcnt < 8);
77 
78     i2c->hw->enable = 0;
79     // Always use "fast" mode (<= 400 kHz, works fine for standard mode too)
80     hw_write_masked(&i2c->hw->con,
81                    I2C_IC_CON_SPEED_VALUE_FAST << I2C_IC_CON_SPEED_LSB,
82                    I2C_IC_CON_SPEED_BITS
83     );
84     i2c->hw->fs_scl_hcnt = hcnt;
85     i2c->hw->fs_scl_lcnt = lcnt;
86     i2c->hw->fs_spklen = lcnt < 16 ? 1 : lcnt / 16;
87 
88     i2c->hw->enable = 1;
89     return freq_in / period;
90 }
91 
i2c_set_slave_mode(i2c_inst_t * i2c,bool slave,uint8_t addr)92 void i2c_set_slave_mode(i2c_inst_t *i2c, bool slave, uint8_t addr) {
93     invalid_params_if(I2C, addr >= 0x80); // 7-bit addresses
94     invalid_params_if(I2C, i2c_reserved_addr(addr));
95     i2c->hw->enable = 0;
96     if (slave) {
97         hw_clear_bits(&i2c->hw->con,
98                       I2C_IC_CON_MASTER_MODE_BITS |
99                       I2C_IC_CON_IC_SLAVE_DISABLE_BITS
100         );
101         i2c->hw->sar = addr;
102     } else {
103         hw_set_bits(&i2c->hw->con,
104                     I2C_IC_CON_MASTER_MODE_BITS |
105                     I2C_IC_CON_IC_SLAVE_DISABLE_BITS
106         );
107     }
108     i2c->hw->enable = 1;
109 }
110 
i2c_write_blocking_internal(i2c_inst_t * i2c,uint8_t addr,const uint8_t * src,size_t len,bool nostop,check_timeout_fn timeout_check,struct timeout_state * ts)111 static int i2c_write_blocking_internal(i2c_inst_t *i2c, uint8_t addr, const uint8_t *src, size_t len, bool nostop,
112                                        check_timeout_fn timeout_check, struct timeout_state *ts) {
113     invalid_params_if(I2C, addr >= 0x80); // 7-bit addresses
114     invalid_params_if(I2C, i2c_reserved_addr(addr));
115     // Synopsys hw accepts start/stop flags alongside data items in the same
116     // FIFO word, so no 0 byte transfers.
117     invalid_params_if(I2C, len == 0);
118 
119     i2c->hw->enable = 0;
120     i2c->hw->tar = addr;
121     i2c->hw->enable = 1;
122 
123     bool abort = false;
124     bool timeout = false;
125 
126     uint32_t abort_reason;
127     size_t byte_ctr;
128 
129     for (byte_ctr = 0; byte_ctr < len; ++byte_ctr) {
130         bool first = byte_ctr == 0;
131         bool last = byte_ctr == len - 1;
132 
133         i2c->hw->data_cmd =
134                 !!(first && i2c->restart_on_next) << I2C_IC_DATA_CMD_RESTART_LSB |
135                 !!(last && !nostop) << I2C_IC_DATA_CMD_STOP_LSB |
136                 *src++;
137 
138         do {
139             // Note clearing the abort flag also clears the reason, and this
140             // instance of flag is clear-on-read!
141             abort_reason = i2c->hw->tx_abrt_source;
142             abort = (bool) i2c->hw->clr_tx_abrt;
143             if (timeout_check) {
144                 timeout = timeout_check(ts);
145                 abort |= timeout;
146             }
147             tight_loop_contents();
148         } while (!abort && !(i2c->hw->status & I2C_IC_STATUS_TFE_BITS));
149 
150         // Note the hardware issues a STOP automatically on an abort condition.
151         // Note also the hardware clears RX FIFO as well as TX on abort,
152         // because we set hwparam IC_AVOID_RX_FIFO_FLUSH_ON_TX_ABRT to 0.
153         if (abort)
154             break;
155     }
156 
157     int rval;
158 
159     // A lot of things could have just happened due to the ingenious and
160     // creative design of I2C. Try to figure things out.
161     if (abort) {
162         if (timeout)
163             rval = PICO_ERROR_TIMEOUT;
164         else if (!abort_reason || abort_reason & I2C_IC_TX_ABRT_SOURCE_ABRT_7B_ADDR_NOACK_BITS) {
165             // No reported errors - seems to happen if there is nothing connected to the bus.
166             // Address byte not acknowledged
167             rval = PICO_ERROR_GENERIC;
168         } else if (abort_reason & I2C_IC_TX_ABRT_SOURCE_ABRT_TXDATA_NOACK_BITS) {
169             // Address acknowledged, some data not acknowledged
170             rval = byte_ctr;
171         } else {
172             //panic("Unknown abort from I2C instance @%08x: %08x\n", (uint32_t) i2c->hw, abort_reason);
173             rval = PICO_ERROR_GENERIC;
174         }
175     } else {
176         rval = byte_ctr;
177     }
178 
179     // nostop means we are now at the end of a *message* but not the end of a *transfer*
180     i2c->restart_on_next = nostop;
181     return rval;
182 }
183 
i2c_write_blocking(i2c_inst_t * i2c,uint8_t addr,const uint8_t * src,size_t len,bool nostop)184 int i2c_write_blocking(i2c_inst_t *i2c, uint8_t addr, const uint8_t *src, size_t len, bool nostop) {
185     return i2c_write_blocking_internal(i2c, addr, src, len, nostop, NULL, NULL);
186 }
187 
i2c_write_blocking_until(i2c_inst_t * i2c,uint8_t addr,const uint8_t * src,size_t len,bool nostop,absolute_time_t until)188 int i2c_write_blocking_until(i2c_inst_t *i2c, uint8_t addr, const uint8_t *src, size_t len, bool nostop,
189                              absolute_time_t until) {
190     timeout_state_t ts;
191     return i2c_write_blocking_internal(i2c, addr, src, len, nostop, init_single_timeout_until(&ts, until), &ts);
192 }
193 
i2c_write_timeout_per_char_us(i2c_inst_t * i2c,uint8_t addr,const uint8_t * src,size_t len,bool nostop,uint timeout_per_char_us)194 int i2c_write_timeout_per_char_us(i2c_inst_t *i2c, uint8_t addr, const uint8_t *src, size_t len, bool nostop,
195                                   uint timeout_per_char_us) {
196     timeout_state_t ts;
197     return i2c_write_blocking_internal(i2c, addr, src, len, nostop,
198                                        init_per_iteration_timeout_us(&ts, timeout_per_char_us), &ts);
199 }
200 
i2c_read_blocking_internal(i2c_inst_t * i2c,uint8_t addr,uint8_t * dst,size_t len,bool nostop,check_timeout_fn timeout_check,timeout_state_t * ts)201 static int i2c_read_blocking_internal(i2c_inst_t *i2c, uint8_t addr, uint8_t *dst, size_t len, bool nostop,
202                                check_timeout_fn timeout_check, timeout_state_t *ts) {
203     invalid_params_if(I2C, addr >= 0x80); // 7-bit addresses
204     invalid_params_if(I2C, i2c_reserved_addr(addr));
205     invalid_params_if(I2C, len == 0);
206 
207     i2c->hw->enable = 0;
208     i2c->hw->tar = addr;
209     i2c->hw->enable = 1;
210 
211     bool abort = false;
212     bool timeout = false;
213     uint32_t abort_reason;
214     size_t byte_ctr;
215 
216     for (byte_ctr = 0; byte_ctr < len; ++byte_ctr) {
217         bool first = byte_ctr == 0;
218         bool last = byte_ctr == len - 1;
219         while (!i2c_get_write_available(i2c))
220             tight_loop_contents();
221 
222         i2c->hw->data_cmd =
223                 !!(first && i2c->restart_on_next) << I2C_IC_DATA_CMD_RESTART_LSB |
224                 !!(last && !nostop) << I2C_IC_DATA_CMD_STOP_LSB |
225                 I2C_IC_DATA_CMD_CMD_BITS; // -> 1 for read
226 
227         do {
228             abort_reason = i2c->hw->tx_abrt_source;
229             abort = (bool) i2c->hw->clr_tx_abrt;
230             if (timeout_check) {
231                 timeout = timeout_check(ts);
232                 abort |= timeout;
233             }
234         } while (!abort && !i2c_get_read_available(i2c));
235 
236         if (abort)
237             break;
238 
239         *dst++ = i2c->hw->data_cmd;
240     }
241 
242     int rval;
243 
244     if (abort) {
245         if (timeout)
246             rval = PICO_ERROR_TIMEOUT;
247         else if (!abort_reason || abort_reason & I2C_IC_TX_ABRT_SOURCE_ABRT_7B_ADDR_NOACK_BITS) {
248             // No reported errors - seems to happen if there is nothing connected to the bus.
249             // Address byte not acknowledged
250             rval = PICO_ERROR_GENERIC;
251         } else {
252 //            panic("Unknown abort from I2C instance @%08x: %08x\n", (uint32_t) i2c->hw, abort_reason);
253             rval = PICO_ERROR_GENERIC;
254         }
255     } else {
256         rval = byte_ctr;
257     }
258 
259     i2c->restart_on_next = nostop;
260     return rval;
261 }
262 
i2c_read_blocking(i2c_inst_t * i2c,uint8_t addr,uint8_t * dst,size_t len,bool nostop)263 int i2c_read_blocking(i2c_inst_t *i2c, uint8_t addr, uint8_t *dst, size_t len, bool nostop) {
264     return i2c_read_blocking_internal(i2c, addr, dst, len, nostop, NULL, NULL);
265 }
266 
i2c_read_blocking_until(i2c_inst_t * i2c,uint8_t addr,uint8_t * dst,size_t len,bool nostop,absolute_time_t until)267 int i2c_read_blocking_until(i2c_inst_t *i2c, uint8_t addr, uint8_t *dst, size_t len, bool nostop, absolute_time_t until) {
268     timeout_state_t ts;
269     return i2c_read_blocking_internal(i2c, addr, dst, len, nostop, init_single_timeout_until(&ts, until), &ts);
270 }
271 
i2c_read_timeout_per_char_us(i2c_inst_t * i2c,uint8_t addr,uint8_t * dst,size_t len,bool nostop,uint timeout_per_char_us)272 int i2c_read_timeout_per_char_us(i2c_inst_t *i2c, uint8_t addr, uint8_t *dst, size_t len, bool nostop,
273                                  uint timeout_per_char_us) {
274     timeout_state_t ts;
275     return i2c_read_blocking_internal(i2c, addr, dst, len, nostop,
276                                       init_per_iteration_timeout_us(&ts, timeout_per_char_us), &ts);
277 }
278