Software APIs
dif_i2c.c
1// Copyright lowRISC contributors (OpenTitan project).
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4
6
11
12#include "i2c_regs.h" // Generated
13
14/**
15 * Performs a 32-bit integer unsigned division, rounding up. The bottom
16 * 16 bits of the result are then returned.
17 *
18 * As usual, a divisor of 0 is still Undefined Behavior.
19 */
20static uint16_t round_up_divide(uint32_t a, uint32_t b) {
21 const uint32_t result = ((a - 1) / b) + 1;
22 return (uint16_t)result;
23}
24
25static void spin_while_status_bit(const dif_i2c_t *i2c, uint32_t bit,
26 bool set) {
27 uint32_t reg = 0;
28 do {
29 reg = mmio_region_read32(i2c->base_addr, I2C_STATUS_REG_OFFSET);
30 } while (bitfield_bit32_read(reg, bit) == set);
31}
32
33/**
34 * Reads i2c status bits from registers
35 */
36dif_result_t dif_i2c_get_status(const dif_i2c_t *i2c,
38 if (i2c == NULL || status == NULL) {
39 return kDifBadArg;
40 }
41
42 uint32_t reg = mmio_region_read32(i2c->base_addr, I2C_CTRL_REG_OFFSET);
43 status->enable_host = bitfield_bit32_read(reg, I2C_CTRL_ENABLEHOST_BIT);
44 status->enable_target = bitfield_bit32_read(reg, I2C_CTRL_ENABLETARGET_BIT);
45 status->line_loopback = bitfield_bit32_read(reg, I2C_CTRL_LLPBK_BIT);
46 status->ack_control_en = bitfield_bit32_read(reg, I2C_CTRL_ACK_CTRL_EN_BIT);
47 reg = mmio_region_read32(i2c->base_addr, I2C_STATUS_REG_OFFSET);
48 status->fmt_fifo_full = bitfield_bit32_read(reg, I2C_STATUS_FMTFULL_BIT);
49 status->rx_fifo_full = bitfield_bit32_read(reg, I2C_STATUS_RXFULL_BIT);
50 status->fmt_fifo_empty = bitfield_bit32_read(reg, I2C_STATUS_FMTEMPTY_BIT);
51 status->rx_fifo_empty = bitfield_bit32_read(reg, I2C_STATUS_RXEMPTY_BIT);
52 status->host_idle = bitfield_bit32_read(reg, I2C_STATUS_HOSTIDLE_BIT);
53 status->target_idle = bitfield_bit32_read(reg, I2C_STATUS_TARGETIDLE_BIT);
54 status->tx_fifo_full = bitfield_bit32_read(reg, I2C_STATUS_TXFULL_BIT);
55 status->acq_fifo_full = bitfield_bit32_read(reg, I2C_STATUS_ACQFULL_BIT);
56 status->tx_fifo_empty = bitfield_bit32_read(reg, I2C_STATUS_TXEMPTY_BIT);
57 status->acq_fifo_empty = bitfield_bit32_read(reg, I2C_STATUS_ACQEMPTY_BIT);
58 status->ack_ctrl_stretch =
59 bitfield_bit32_read(reg, I2C_STATUS_ACK_CTRL_STRETCH_BIT);
60
61 return kDifOk;
62}
63
64dif_result_t dif_i2c_get_controller_halt_events(
65 const dif_i2c_t *i2c, dif_i2c_controller_halt_events_t *events) {
66 if (i2c == NULL || events == NULL) {
67 return kDifBadArg;
68 }
69 uint32_t reg =
70 mmio_region_read32(i2c->base_addr, I2C_CONTROLLER_EVENTS_REG_OFFSET);
71 events->nack_received =
72 bitfield_bit32_read(reg, I2C_CONTROLLER_EVENTS_NACK_BIT);
73 events->unhandled_nack_timeout = bitfield_bit32_read(
74 reg, I2C_CONTROLLER_EVENTS_UNHANDLED_NACK_TIMEOUT_BIT);
75 events->bus_timeout =
76 bitfield_bit32_read(reg, I2C_CONTROLLER_EVENTS_BUS_TIMEOUT_BIT);
77 events->arbitration_lost =
78 bitfield_bit32_read(reg, I2C_CONTROLLER_EVENTS_ARBITRATION_LOST_BIT);
79 return kDifOk;
80}
81
82dif_result_t dif_i2c_clear_controller_halt_events(
83 const dif_i2c_t *i2c, dif_i2c_controller_halt_events_t events) {
84 if (i2c == NULL) {
85 return kDifBadArg;
86 }
87 uint32_t reg = 0;
88 reg = bitfield_bit32_write(reg, I2C_CONTROLLER_EVENTS_NACK_BIT,
89 events.nack_received);
90 reg = bitfield_bit32_write(reg,
91 I2C_CONTROLLER_EVENTS_UNHANDLED_NACK_TIMEOUT_BIT,
93 reg = bitfield_bit32_write(reg, I2C_CONTROLLER_EVENTS_BUS_TIMEOUT_BIT,
94 events.bus_timeout);
95 reg = bitfield_bit32_write(reg, I2C_CONTROLLER_EVENTS_ARBITRATION_LOST_BIT,
96 events.arbitration_lost);
97 mmio_region_write32(i2c->base_addr, I2C_CONTROLLER_EVENTS_REG_OFFSET, reg);
98 return kDifOk;
99}
100
101dif_result_t dif_i2c_get_target_tx_halt_events(
102 const dif_i2c_t *i2c, dif_i2c_target_tx_halt_events_t *events) {
103 if (i2c == NULL || events == NULL) {
104 return kDifBadArg;
105 }
106 uint32_t reg =
107 mmio_region_read32(i2c->base_addr, I2C_TARGET_EVENTS_REG_OFFSET);
108 events->tx_pending =
109 bitfield_bit32_read(reg, I2C_TARGET_EVENTS_TX_PENDING_BIT);
110 events->bus_timeout =
111 bitfield_bit32_read(reg, I2C_TARGET_EVENTS_BUS_TIMEOUT_BIT);
112 events->arbitration_lost =
113 bitfield_bit32_read(reg, I2C_TARGET_EVENTS_ARBITRATION_LOST_BIT);
114 return kDifOk;
115}
116
117dif_result_t dif_i2c_clear_target_tx_halt_events(
118 const dif_i2c_t *i2c, dif_i2c_target_tx_halt_events_t events) {
119 if (i2c == NULL) {
120 return kDifBadArg;
121 }
122 uint32_t reg = 0;
123 reg = bitfield_bit32_write(reg, I2C_TARGET_EVENTS_TX_PENDING_BIT,
124 events.tx_pending);
125 reg = bitfield_bit32_write(reg, I2C_TARGET_EVENTS_BUS_TIMEOUT_BIT,
126 events.bus_timeout);
127 reg = bitfield_bit32_write(reg, I2C_TARGET_EVENTS_ARBITRATION_LOST_BIT,
128 events.arbitration_lost);
129 mmio_region_write32(i2c->base_addr, I2C_TARGET_EVENTS_REG_OFFSET, reg);
130 return kDifOk;
131}
132
133/**
134 * Computes default timing parameters for a particular I2C speed, given the
135 * clock period, in nanoseconds.
136 *
137 * Returns an unspecified value for an invalid speed.
138 */
139static dif_i2c_config_t default_timing_for_speed(dif_i2c_speed_t speed,
140 uint32_t clock_period_nanos) {
141 // NOTE: All constants below are lifted from Table 10 of the I2C spec.
142 // All literal values are given in nanoseconds; we don't bother putting
143 // these into constants since they are not used anywhere else.
144 switch (speed) {
146 return (dif_i2c_config_t){
147 .scl_time_high_cycles = round_up_divide(4000, clock_period_nanos),
148 .scl_time_low_cycles = round_up_divide(4700, clock_period_nanos),
149 .start_signal_setup_cycles =
150 round_up_divide(4700, clock_period_nanos),
151 .start_signal_hold_cycles = round_up_divide(4000, clock_period_nanos),
152 .data_signal_setup_cycles = round_up_divide(250, clock_period_nanos),
153 .data_signal_hold_cycles = 1,
154 .stop_signal_setup_cycles = round_up_divide(4000, clock_period_nanos),
155 .stop_signal_hold_cycles = round_up_divide(4700, clock_period_nanos),
156 };
157 case kDifI2cSpeedFast:
158 return (dif_i2c_config_t){
159 .scl_time_high_cycles = round_up_divide(600, clock_period_nanos),
160 .scl_time_low_cycles = round_up_divide(1300, clock_period_nanos),
161 .start_signal_setup_cycles = round_up_divide(600, clock_period_nanos),
162 .start_signal_hold_cycles = round_up_divide(600, clock_period_nanos),
163 .data_signal_setup_cycles = round_up_divide(100, clock_period_nanos),
164 .data_signal_hold_cycles = 1,
165 .stop_signal_setup_cycles = round_up_divide(600, clock_period_nanos),
166 .stop_signal_hold_cycles = round_up_divide(1300, clock_period_nanos),
167 };
169 return (dif_i2c_config_t){
170 .scl_time_high_cycles = round_up_divide(260, clock_period_nanos),
171 .scl_time_low_cycles = round_up_divide(500, clock_period_nanos),
172 .start_signal_setup_cycles = round_up_divide(260, clock_period_nanos),
173 .start_signal_hold_cycles = round_up_divide(260, clock_period_nanos),
174 .data_signal_setup_cycles = round_up_divide(50, clock_period_nanos),
175 .data_signal_hold_cycles = 1,
176 .stop_signal_setup_cycles = round_up_divide(260, clock_period_nanos),
177 .stop_signal_hold_cycles = round_up_divide(500, clock_period_nanos),
178 };
179 default:
180 return (dif_i2c_config_t){0};
181 }
182}
183
184static const uint32_t kNanosPerKBaud = 1000000; // One million.
185
186dif_result_t dif_i2c_compute_timing(dif_i2c_timing_config_t timing_config,
187 dif_i2c_config_t *config) {
188 if (config == NULL) {
189 return kDifBadArg;
190 }
191 uint32_t lowest_target_device_speed_khz;
192 switch (timing_config.lowest_target_device_speed) {
194 lowest_target_device_speed_khz = 100;
195 break;
196 case kDifI2cSpeedFast:
197 lowest_target_device_speed_khz = 400;
198 break;
200 lowest_target_device_speed_khz = 1000;
201 break;
202 default:
203 return kDifBadArg;
204 }
205
206 // This code follows the algorithm given in
207 // https://docs.opentitan.org/hw/ip/i2c/doc/index.html#initialization
208
209 *config = default_timing_for_speed(timing_config.lowest_target_device_speed,
210 timing_config.clock_period_nanos);
211
212 config->rise_cycles = round_up_divide(timing_config.sda_rise_nanos,
213 timing_config.clock_period_nanos);
214 config->fall_cycles = round_up_divide(timing_config.sda_fall_nanos,
215 timing_config.clock_period_nanos);
216
217 uint32_t scl_period_nanos = timing_config.scl_period_nanos;
218 uint32_t slowest_scl_period_nanos =
219 kNanosPerKBaud / lowest_target_device_speed_khz;
220 if (scl_period_nanos < slowest_scl_period_nanos) {
221 scl_period_nanos = slowest_scl_period_nanos;
222 }
223 uint16_t scl_period_cycles =
224 round_up_divide(scl_period_nanos, timing_config.clock_period_nanos);
225
226 // Lengthen the SCL high period to accommodate the desired SCL period.
227 int32_t lengthened_high_cycles = scl_period_cycles -
228 config->scl_time_low_cycles -
229 config->rise_cycles - config->fall_cycles;
230 if (lengthened_high_cycles > (int32_t)config->scl_time_high_cycles) {
231 if (lengthened_high_cycles < 0 || lengthened_high_cycles > UINT16_MAX) {
232 return kDifOutOfRange;
233 }
234 config->scl_time_high_cycles = (uint16_t)lengthened_high_cycles;
235 }
236
237 // For clock stretching detection to work, the SCL high and low time must be
238 // at least 4 cycles.
239 if (config->scl_time_high_cycles < kDifI2cInputDelayCycles) {
240 config->scl_time_high_cycles = kDifI2cInputDelayCycles;
241 }
242 if (config->scl_time_low_cycles < kDifI2cInputDelayCycles) {
243 config->scl_time_low_cycles = kDifI2cInputDelayCycles;
244 }
245
246 return kDifOk;
247}
248
249dif_result_t dif_i2c_configure(const dif_i2c_t *i2c, dif_i2c_config_t config) {
250 if (i2c == NULL) {
251 return kDifBadArg;
252 }
253
254 uint32_t timing0 = 0;
255 timing0 = bitfield_field32_write(timing0, I2C_TIMING0_THIGH_FIELD,
256 config.scl_time_high_cycles);
257 timing0 = bitfield_field32_write(timing0, I2C_TIMING0_TLOW_FIELD,
258 config.scl_time_low_cycles);
259 mmio_region_write32(i2c->base_addr, I2C_TIMING0_REG_OFFSET, timing0);
260
261 uint32_t timing1 = 0;
262 timing1 = bitfield_field32_write(timing1, I2C_TIMING1_T_R_FIELD,
263 config.rise_cycles);
264 timing1 = bitfield_field32_write(timing1, I2C_TIMING1_T_F_FIELD,
265 config.fall_cycles);
266 mmio_region_write32(i2c->base_addr, I2C_TIMING1_REG_OFFSET, timing1);
267
268 uint32_t timing2 = 0;
269 timing2 = bitfield_field32_write(timing2, I2C_TIMING2_TSU_STA_FIELD,
270 config.start_signal_setup_cycles);
271 timing2 = bitfield_field32_write(timing2, I2C_TIMING2_THD_STA_FIELD,
272 config.start_signal_hold_cycles);
273 mmio_region_write32(i2c->base_addr, I2C_TIMING2_REG_OFFSET, timing2);
274
275 uint32_t timing3 = 0;
276 timing3 = bitfield_field32_write(timing3, I2C_TIMING3_TSU_DAT_FIELD,
277 config.data_signal_setup_cycles);
278 timing3 = bitfield_field32_write(timing3, I2C_TIMING3_THD_DAT_FIELD,
279 config.data_signal_hold_cycles);
280 mmio_region_write32(i2c->base_addr, I2C_TIMING3_REG_OFFSET, timing3);
281
282 uint32_t timing4 = 0;
283 timing4 = bitfield_field32_write(timing4, I2C_TIMING4_TSU_STO_FIELD,
284 config.stop_signal_setup_cycles);
285 timing4 = bitfield_field32_write(timing4, I2C_TIMING4_T_BUF_FIELD,
287 mmio_region_write32(i2c->base_addr, I2C_TIMING4_REG_OFFSET, timing4);
288
289 return kDifOk;
290}
291
292dif_result_t dif_i2c_reset_rx_fifo(const dif_i2c_t *i2c) {
293 if (i2c == NULL) {
294 return kDifBadArg;
295 }
296
297 uint32_t reg = mmio_region_read32(i2c->base_addr, I2C_FIFO_CTRL_REG_OFFSET);
298 reg = bitfield_bit32_write(reg, I2C_FIFO_CTRL_RXRST_BIT, true);
299 mmio_region_write32(i2c->base_addr, I2C_FIFO_CTRL_REG_OFFSET, reg);
300
301 return kDifOk;
302}
303
304dif_result_t dif_i2c_reset_fmt_fifo(const dif_i2c_t *i2c) {
305 if (i2c == NULL) {
306 return kDifBadArg;
307 }
308
309 uint32_t reg = mmio_region_read32(i2c->base_addr, I2C_FIFO_CTRL_REG_OFFSET);
310 reg = bitfield_bit32_write(reg, I2C_FIFO_CTRL_FMTRST_BIT, true);
311 mmio_region_write32(i2c->base_addr, I2C_FIFO_CTRL_REG_OFFSET, reg);
312
313 return kDifOk;
314}
315
316dif_result_t dif_i2c_reset_tx_fifo(const dif_i2c_t *i2c) {
317 if (i2c == NULL) {
318 return kDifBadArg;
319 }
320
321 uint32_t reg = mmio_region_read32(i2c->base_addr, I2C_FIFO_CTRL_REG_OFFSET);
322 reg = bitfield_bit32_write(reg, I2C_FIFO_CTRL_TXRST_BIT, true);
323 mmio_region_write32(i2c->base_addr, I2C_FIFO_CTRL_REG_OFFSET, reg);
324
325 return kDifOk;
326}
327
328dif_result_t dif_i2c_reset_acq_fifo(const dif_i2c_t *i2c) {
329 if (i2c == NULL) {
330 return kDifBadArg;
331 }
332
333 uint32_t reg = mmio_region_read32(i2c->base_addr, I2C_FIFO_CTRL_REG_OFFSET);
334 reg = bitfield_bit32_write(reg, I2C_FIFO_CTRL_ACQRST_BIT, true);
335 mmio_region_write32(i2c->base_addr, I2C_FIFO_CTRL_REG_OFFSET, reg);
336
337 return kDifOk;
338}
339
340dif_result_t dif_i2c_set_host_watermarks(const dif_i2c_t *i2c,
341 dif_i2c_level_t rx_level,
342 dif_i2c_level_t fmt_level) {
343 // Check that the FIFO levels are sensible; setting RX level equal to the
344 // depth deactivates its interrupt, but setting FMT level to that would result
345 // in continual interrupt assertion.
346 if (i2c == NULL || rx_level > I2C_PARAM_FIFO_DEPTH ||
347 fmt_level >= I2C_PARAM_FIFO_DEPTH) {
348 return kDifBadArg;
349 }
350
351 uint32_t ctrl_value =
352 mmio_region_read32(i2c->base_addr, I2C_HOST_FIFO_CONFIG_REG_OFFSET);
353 ctrl_value = bitfield_field32_write(
354 ctrl_value, I2C_HOST_FIFO_CONFIG_RX_THRESH_FIELD, rx_level);
355 ctrl_value = bitfield_field32_write(
356 ctrl_value, I2C_HOST_FIFO_CONFIG_FMT_THRESH_FIELD, fmt_level);
357 mmio_region_write32(i2c->base_addr, I2C_HOST_FIFO_CONFIG_REG_OFFSET,
358 ctrl_value);
359
360 return kDifOk;
361}
362
363dif_result_t dif_i2c_set_target_watermarks(const dif_i2c_t *i2c,
364 dif_i2c_level_t tx_level,
365 dif_i2c_level_t acq_level) {
366 // Check that the FIFO levels are sensible; setting ACQ level equal to the
367 // depth deactivates its interrupt, but setting TX level to that would result
368 // in continual interrupt assertion.
369 if (i2c == NULL || acq_level > I2C_PARAM_ACQ_FIFO_DEPTH ||
370 tx_level >= I2C_PARAM_FIFO_DEPTH) {
371 return kDifBadArg;
372 }
373
374 uint32_t ctrl_value =
375 mmio_region_read32(i2c->base_addr, I2C_TARGET_FIFO_CONFIG_REG_OFFSET);
376 ctrl_value = bitfield_field32_write(
377 ctrl_value, I2C_TARGET_FIFO_CONFIG_TX_THRESH_FIELD, tx_level);
378 ctrl_value = bitfield_field32_write(
379 ctrl_value, I2C_TARGET_FIFO_CONFIG_ACQ_THRESH_FIELD, acq_level);
380 mmio_region_write32(i2c->base_addr, I2C_TARGET_FIFO_CONFIG_REG_OFFSET,
381 ctrl_value);
382
383 return kDifOk;
384}
385
386dif_result_t dif_i2c_host_set_enabled(const dif_i2c_t *i2c,
387 dif_toggle_t state) {
388 if (i2c == NULL) {
389 return kDifBadArg;
390 }
391
392 if (!dif_is_valid_toggle(state)) {
393 return kDifBadArg;
394 }
395 bool flag = dif_toggle_to_bool(state);
396
397 uint32_t reg = mmio_region_read32(i2c->base_addr, I2C_CTRL_REG_OFFSET);
398 reg = bitfield_bit32_write(reg, I2C_CTRL_ENABLEHOST_BIT, flag);
399 mmio_region_write32(i2c->base_addr, I2C_CTRL_REG_OFFSET, reg);
400
401 return kDifOk;
402}
403
404dif_result_t dif_i2c_device_set_enabled(const dif_i2c_t *i2c,
405 dif_toggle_t state) {
406 if (i2c == NULL) {
407 return kDifBadArg;
408 }
409
410 if (!dif_is_valid_toggle(state)) {
411 return kDifBadArg;
412 }
413 bool flag = dif_toggle_to_bool(state);
414
415 uint32_t reg = mmio_region_read32(i2c->base_addr, I2C_CTRL_REG_OFFSET);
416 reg = bitfield_bit32_write(reg, I2C_CTRL_ENABLETARGET_BIT, flag);
417 mmio_region_write32(i2c->base_addr, I2C_CTRL_REG_OFFSET, reg);
418
419 return kDifOk;
420}
421
422dif_result_t dif_i2c_line_loopback_set_enabled(const dif_i2c_t *i2c,
423 dif_toggle_t state) {
424 if (i2c == NULL) {
425 return kDifBadArg;
426 }
427
428 if (!dif_is_valid_toggle(state)) {
429 return kDifBadArg;
430 }
431 bool flag = dif_toggle_to_bool(state);
432
433 uint32_t reg = mmio_region_read32(i2c->base_addr, I2C_CTRL_REG_OFFSET);
434 reg = bitfield_bit32_write(reg, I2C_CTRL_LLPBK_BIT, flag);
435 mmio_region_write32(i2c->base_addr, I2C_CTRL_REG_OFFSET, reg);
436
437 return kDifOk;
438}
439
440dif_result_t dif_i2c_addr_nack_set_enabled(const dif_i2c_t *i2c,
441 dif_toggle_t state) {
442 if (i2c == NULL) {
443 return kDifBadArg;
444 }
445
446 if (!dif_is_valid_toggle(state)) {
447 return kDifBadArg;
448 }
449 bool flag = dif_toggle_to_bool(state);
450
451 uint32_t reg = mmio_region_read32(i2c->base_addr, I2C_CTRL_REG_OFFSET);
452 reg = bitfield_bit32_write(reg, I2C_CTRL_NACK_ADDR_AFTER_TIMEOUT_BIT, flag);
453 mmio_region_write32(i2c->base_addr, I2C_CTRL_REG_OFFSET, reg);
454
455 return kDifOk;
456}
457
458dif_result_t dif_i2c_ack_ctrl_set_enabled(const dif_i2c_t *i2c,
459 dif_toggle_t state) {
460 if (i2c == NULL) {
461 return kDifBadArg;
462 }
463
464 if (!dif_is_valid_toggle(state)) {
465 return kDifBadArg;
466 }
467 bool flag = dif_toggle_to_bool(state);
468
469 uint32_t reg = mmio_region_read32(i2c->base_addr, I2C_CTRL_REG_OFFSET);
470 reg = bitfield_bit32_write(reg, I2C_CTRL_ACK_CTRL_EN_BIT, flag);
471 mmio_region_write32(i2c->base_addr, I2C_CTRL_REG_OFFSET, reg);
472
473 return kDifOk;
474}
475
476dif_result_t dif_i2c_multi_controller_monitor_set_enabled(const dif_i2c_t *i2c,
477 dif_toggle_t state) {
478 if (i2c == NULL) {
479 return kDifBadArg;
480 }
481
482 if (!dif_is_valid_toggle(state)) {
483 return kDifBadArg;
484 }
485 bool flag = dif_toggle_to_bool(state);
486
487 uint32_t reg = mmio_region_read32(i2c->base_addr, I2C_CTRL_REG_OFFSET);
488 reg =
489 bitfield_bit32_write(reg, I2C_CTRL_MULTI_CONTROLLER_MONITOR_EN_BIT, flag);
490 mmio_region_write32(i2c->base_addr, I2C_CTRL_REG_OFFSET, reg);
491
492 return kDifOk;
493}
494
495dif_result_t dif_i2c_target_tx_stretch_ctrl_set_enabled(const dif_i2c_t *i2c,
496 dif_toggle_t state) {
497 if (i2c == NULL) {
498 return kDifBadArg;
499 }
500
501 if (!dif_is_valid_toggle(state)) {
502 return kDifBadArg;
503 }
504 bool flag = dif_toggle_to_bool(state);
505
506 uint32_t reg = mmio_region_read32(i2c->base_addr, I2C_CTRL_REG_OFFSET);
507 reg = bitfield_bit32_write(reg, I2C_CTRL_TX_STRETCH_CTRL_EN_BIT, flag);
508 mmio_region_write32(i2c->base_addr, I2C_CTRL_REG_OFFSET, reg);
509
510 return kDifOk;
511}
512
513dif_result_t dif_i2c_override_set_enabled(const dif_i2c_t *i2c,
514 dif_toggle_t state) {
515 if (i2c == NULL) {
516 return kDifBadArg;
517 }
518
519 if (!dif_is_valid_toggle(state)) {
520 return kDifBadArg;
521 }
522 bool flag = dif_toggle_to_bool(state);
523
524 uint32_t reg = mmio_region_read32(i2c->base_addr, I2C_OVRD_REG_OFFSET);
525 reg = bitfield_bit32_write(reg, I2C_OVRD_TXOVRDEN_BIT, flag);
526 mmio_region_write32(i2c->base_addr, I2C_OVRD_REG_OFFSET, reg);
527
528 return kDifOk;
529}
530
531dif_result_t dif_i2c_override_drive_pins(const dif_i2c_t *i2c, bool scl,
532 bool sda) {
533 if (i2c == NULL) {
534 return kDifBadArg;
535 }
536
537 uint32_t override_val =
538 mmio_region_read32(i2c->base_addr, I2C_OVRD_REG_OFFSET);
539 override_val = bitfield_bit32_write(override_val, I2C_OVRD_SCLVAL_BIT, scl);
540 override_val = bitfield_bit32_write(override_val, I2C_OVRD_SDAVAL_BIT, sda);
541 mmio_region_write32(i2c->base_addr, I2C_OVRD_REG_OFFSET, override_val);
542
543 return kDifOk;
544}
545
546dif_result_t dif_i2c_override_sample_pins(const dif_i2c_t *i2c,
547 uint16_t *scl_samples,
548 uint16_t *sda_samples) {
549 if (i2c == NULL) {
550 return kDifBadArg;
551 }
552
553 uint32_t samples = mmio_region_read32(i2c->base_addr, I2C_VAL_REG_OFFSET);
554 if (scl_samples != NULL) {
555 *scl_samples =
556 (uint16_t)bitfield_field32_read(samples, I2C_VAL_SCL_RX_FIELD);
557 }
558
559 if (sda_samples != NULL) {
560 *sda_samples =
561 (uint16_t)bitfield_field32_read(samples, I2C_VAL_SDA_RX_FIELD);
562 }
563
564 return kDifOk;
565}
566
567dif_result_t dif_i2c_get_fifo_levels(const dif_i2c_t *i2c,
568 dif_i2c_level_t *fmt_fifo_level,
569 dif_i2c_level_t *rx_fifo_level,
570 dif_i2c_level_t *tx_fifo_level,
571 dif_i2c_level_t *acq_fifo_level) {
572 if (i2c == NULL) {
573 return kDifBadArg;
574 }
575
576 // Host-side FIFO levels
577 uint32_t values =
578 mmio_region_read32(i2c->base_addr, I2C_HOST_FIFO_STATUS_REG_OFFSET);
579 if (fmt_fifo_level != NULL) {
580 *fmt_fifo_level = (dif_i2c_level_t)bitfield_field32_read(
581 values, I2C_HOST_FIFO_STATUS_FMTLVL_FIELD);
582 }
583 if (rx_fifo_level != NULL) {
584 *rx_fifo_level = (dif_i2c_level_t)bitfield_field32_read(
585 values, I2C_HOST_FIFO_STATUS_RXLVL_FIELD);
586 }
587
588 // Target-side FIFO levels
589 values =
590 mmio_region_read32(i2c->base_addr, I2C_TARGET_FIFO_STATUS_REG_OFFSET);
591 if (tx_fifo_level != NULL) {
592 *tx_fifo_level = (dif_i2c_level_t)bitfield_field32_read(
593 values, I2C_TARGET_FIFO_STATUS_TXLVL_FIELD);
594 }
595 if (acq_fifo_level != NULL) {
596 *acq_fifo_level = (dif_i2c_level_t)bitfield_field32_read(
597 values, I2C_TARGET_FIFO_STATUS_ACQLVL_FIELD);
598 }
599
600 return kDifOk;
601}
602
603dif_result_t dif_i2c_get_auto_ack_count(const dif_i2c_t *i2c, uint16_t *count) {
604 if (i2c == NULL || count == NULL) {
605 return kDifBadArg;
606 }
607
608 uint32_t reg =
609 mmio_region_read32(i2c->base_addr, I2C_TARGET_ACK_CTRL_REG_OFFSET);
610 *count =
611 (uint16_t)bitfield_field32_read(reg, I2C_TARGET_ACK_CTRL_NBYTES_FIELD);
612
613 return kDifOk;
614}
615
616dif_result_t dif_i2c_set_auto_ack_count(const dif_i2c_t *i2c, uint16_t count) {
617 if (i2c == NULL) {
618 return kDifBadArg;
619 }
620 if (count > I2C_TARGET_ACK_CTRL_NBYTES_MASK) {
621 return kDifBadArg;
622 }
623
624 uint32_t reg =
625 bitfield_field32_write(0, I2C_TARGET_ACK_CTRL_NBYTES_FIELD, count);
626 mmio_region_write32(i2c->base_addr, I2C_TARGET_ACK_CTRL_REG_OFFSET, reg);
627
628 return kDifOk;
629}
630
631dif_result_t dif_i2c_nack_transaction(const dif_i2c_t *i2c) {
632 if (i2c == NULL) {
633 return kDifBadArg;
634 }
635
636 uint32_t reg = bitfield_bit32_write(0, I2C_TARGET_ACK_CTRL_NACK_BIT, true);
637 mmio_region_write32(i2c->base_addr, I2C_TARGET_ACK_CTRL_REG_OFFSET, reg);
638
639 return kDifOk;
640}
641
642dif_result_t dif_i2c_get_pending_acq_byte(const dif_i2c_t *i2c, uint8_t *data) {
643 if (i2c == NULL || data == NULL) {
644 return kDifBadArg;
645 }
646
647 *data = 0xffu &
648 mmio_region_read32(i2c->base_addr, I2C_ACQ_FIFO_NEXT_DATA_REG_OFFSET);
649
650 return kDifOk;
651}
652
653dif_result_t dif_i2c_read_byte(const dif_i2c_t *i2c, uint8_t *byte) {
654 if (i2c == NULL) {
655 return kDifBadArg;
656 }
657
658 uint32_t values = mmio_region_read32(i2c->base_addr, I2C_RDATA_REG_OFFSET);
659 if (byte != NULL) {
660 *byte = (uint8_t)bitfield_field32_read(values, I2C_RDATA_RDATA_FIELD);
661 }
662
663 return kDifOk;
664}
665
666dif_result_t dif_i2c_read_bytes(const dif_i2c_t *i2c, size_t size,
667 uint8_t *buffer) {
668 if (i2c == NULL || buffer == NULL) {
669 return kDifBadArg;
670 }
671
672 while (size--) {
673 spin_while_status_bit(i2c, I2C_STATUS_RXEMPTY_BIT, /*set*/ true);
674 uint32_t values = mmio_region_read32(i2c->base_addr, I2C_RDATA_REG_OFFSET);
675 *(buffer++) = (uint8_t)bitfield_field32_read(values, I2C_RDATA_RDATA_FIELD);
676 }
677
678 return kDifOk;
679}
680
681static inline dif_result_t parse_flags(dif_i2c_fmt_flags_t flags,
682 uint32_t *fmt_byte) {
683 // Validate that "write only" flags and "read only" flags are not set
684 // simultaneously.
685 bool has_write_flags = flags.start || flags.suppress_nak_irq;
686 bool has_read_flags = flags.read || flags.read_cont;
687 if (has_write_flags && has_read_flags) {
688 return kDifBadArg;
689 }
690 // Also, read_cont requires read.
691 if (flags.read_cont && !flags.read) {
692 return kDifBadArg;
693 }
694
695 *fmt_byte = bitfield_bit32_write(*fmt_byte, 8, flags.start);
696 *fmt_byte = bitfield_bit32_write(*fmt_byte, I2C_FDATA_STOP_BIT, flags.stop);
697 *fmt_byte = bitfield_bit32_write(*fmt_byte, I2C_FDATA_READB_BIT, flags.read);
698 *fmt_byte =
699 bitfield_bit32_write(*fmt_byte, I2C_FDATA_RCONT_BIT, flags.read_cont);
700 *fmt_byte = bitfield_bit32_write(*fmt_byte, I2C_FDATA_NAKOK_BIT,
701 flags.suppress_nak_irq);
702
703 return kDifOk;
704}
705dif_result_t dif_i2c_write_bytes_raw(const dif_i2c_t *i2c, size_t size,
706 const uint8_t *bytes,
707 dif_i2c_fmt_flags_t flags) {
708 if (i2c == NULL || bytes == NULL || size == 0) {
709 return kDifBadArg;
710 }
711 uint32_t fmt_byte = 0;
712 DIF_RETURN_IF_ERROR(parse_flags(flags, &fmt_byte));
713
714 for (size_t i = 0; i < size; ++i) {
715 uint32_t reg =
716 bitfield_field32_write(fmt_byte, I2C_FDATA_FBYTE_FIELD, bytes[i]);
717 mmio_region_write32(i2c->base_addr, I2C_FDATA_REG_OFFSET, reg);
718 spin_while_status_bit(i2c, I2C_STATUS_FMTFULL_BIT, /*set*/ true);
719 }
720
721 return kDifOk;
722}
723
724dif_result_t dif_i2c_write_byte_raw(const dif_i2c_t *i2c, uint8_t byte,
725 dif_i2c_fmt_flags_t flags) {
726 if (i2c == NULL) {
727 return kDifBadArg;
728 }
729
730 uint32_t fmt_byte = 0;
731 DIF_RETURN_IF_ERROR(parse_flags(flags, &fmt_byte));
732 fmt_byte = bitfield_field32_write(fmt_byte, I2C_FDATA_FBYTE_FIELD, byte);
733 mmio_region_write32(i2c->base_addr, I2C_FDATA_REG_OFFSET, fmt_byte);
734
735 return kDifOk;
736}
737
738dif_result_t dif_i2c_write_byte(const dif_i2c_t *i2c, uint8_t byte,
739 dif_i2c_fmt_t code, bool suppress_nak_irq) {
740 if (i2c == NULL) {
741 return kDifBadArg;
742 }
743
744 // Validate that `suppress_nak_irq` has not been mixed with an Rx code.
745 if (suppress_nak_irq) {
746 switch (code) {
747 case kDifI2cFmtRx:
749 case kDifI2cFmtRxStop:
750 return kDifBadArg;
751 default:
752 break;
753 }
754 }
755
756 // Convert the format code into flags.
757 dif_i2c_fmt_flags_t flags = {.suppress_nak_irq = suppress_nak_irq};
758 switch (code) {
759 case kDifI2cFmtStart:
760 flags.start = true;
761 break;
762 case kDifI2cFmtTx:
763 break;
764 case kDifI2cFmtTxStop:
765 flags.stop = true;
766 break;
767 case kDifI2cFmtRx:
768 flags.read = true;
769 break;
771 flags.read = true;
772 flags.read_cont = true;
773 break;
774 case kDifI2cFmtRxStop:
775 flags.read = true;
776 flags.stop = true;
777 break;
778 default:
779 return kDifBadArg;
780 }
781
782 return dif_i2c_write_byte_raw(i2c, byte, flags);
783}
784
785dif_result_t dif_i2c_transmit_byte(const dif_i2c_t *i2c, uint8_t byte) {
786 if (i2c == NULL) {
787 return kDifBadArg;
788 }
789
790 uint32_t tx_byte = 0;
791 tx_byte = bitfield_field32_write(tx_byte, I2C_TXDATA_TXDATA_FIELD, byte);
792 mmio_region_write32(i2c->base_addr, I2C_TXDATA_REG_OFFSET, tx_byte);
793
794 return kDifOk;
795}
796
797dif_result_t dif_i2c_acquire_byte(const dif_i2c_t *i2c, uint8_t *byte,
798 dif_i2c_signal_t *signal) {
799 if (i2c == NULL) {
800 return kDifBadArg;
801 }
802
803 uint32_t acq_byte =
804 mmio_region_read32(i2c->base_addr, I2C_ACQDATA_REG_OFFSET);
805 if (byte != NULL) {
806 *byte = (uint8_t)bitfield_field32_read(acq_byte, I2C_ACQDATA_ABYTE_FIELD);
807 }
808 if (signal != NULL) {
809 *signal = bitfield_field32_read(acq_byte, I2C_ACQDATA_SIGNAL_FIELD);
810 }
811 return kDifOk;
812}
813
814dif_result_t dif_i2c_enable_clock_timeout(const dif_i2c_t *i2c,
815 dif_i2c_scl_timeout_t timeout_type,
816 uint32_t cycles) {
817 if (i2c == NULL) {
818 return kDifBadArg;
819 }
820
821 bool timeout_en = false;
822 uint8_t timeout_mode = 0;
823 switch (timeout_type) {
825 timeout_en = false;
826 break;
828 timeout_en = true;
829 timeout_mode = I2C_TIMEOUT_CTRL_MODE_VALUE_STRETCH_TIMEOUT;
830 break;
832 timeout_en = true;
833 timeout_mode = I2C_TIMEOUT_CTRL_MODE_VALUE_BUS_TIMEOUT;
834 break;
835 default:
836 return kDifBadArg;
837 }
838
839 uint32_t config = 0;
840 config = bitfield_bit32_write(config, I2C_TIMEOUT_CTRL_EN_BIT, timeout_en);
841 config =
842 bitfield_bit32_write(config, I2C_TIMEOUT_CTRL_MODE_BIT, timeout_mode);
843 config = bitfield_field32_write(config, I2C_TIMEOUT_CTRL_VAL_FIELD, cycles);
844 mmio_region_write32(i2c->base_addr, I2C_TIMEOUT_CTRL_REG_OFFSET, config);
845 return kDifOk;
846}
847
848dif_result_t dif_i2c_set_device_id(const dif_i2c_t *i2c,
849 const dif_i2c_id_t *id0,
850 const dif_i2c_id_t *id1) {
851 if (i2c == NULL) {
852 return kDifBadArg;
853 }
854
855 uint32_t config = 0;
856 if (id0 != NULL) {
857 config = bitfield_field32_write(config, I2C_TARGET_ID_ADDRESS0_FIELD,
858 id0->address);
859 config =
860 bitfield_field32_write(config, I2C_TARGET_ID_MASK0_FIELD, id0->mask);
861 } else {
862 // Don't listen by default
863 config = bitfield_field32_write(config, I2C_TARGET_ID_ADDRESS0_FIELD, 0x7f);
864 }
865
866 if (id1 != NULL) {
867 config = bitfield_field32_write(config, I2C_TARGET_ID_ADDRESS1_FIELD,
868 id1->address);
869 config =
870 bitfield_field32_write(config, I2C_TARGET_ID_MASK1_FIELD, id1->mask);
871 } else {
872 // Don't listen by default
873 config = bitfield_field32_write(config, I2C_TARGET_ID_ADDRESS1_FIELD, 0x7f);
874 }
875
876 mmio_region_write32(i2c->base_addr, I2C_TARGET_ID_REG_OFFSET, config);
877 return kDifOk;
878}
879
880dif_result_t dif_i2c_set_host_timeout(const dif_i2c_t *i2c, uint32_t cycles) {
881 if (i2c == NULL) {
882 return kDifBadArg;
883 }
884
885 mmio_region_write32(i2c->base_addr, I2C_HOST_TIMEOUT_CTRL_REG_OFFSET, cycles);
886 return kDifOk;
887}