Software APIs
i2c_testutils.h
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
5#ifndef OPENTITAN_SW_DEVICE_LIB_TESTING_I2C_TESTUTILS_H_
6#define OPENTITAN_SW_DEVICE_LIB_TESTING_I2C_TESTUTILS_H_
7
8#include <stdint.h>
9
10#include "sw/device/lib/base/status.h"
13
14/**
15 * Construct an I2C write as an I2C host.
16 *
17 * @param i2c An I2C DIF handle.
18 * @param addr The device address for the transaction.
19 * @param byte_count The number of bytes to be written.
20 * @param data Stream of data bytes to be written.
21 * @param skip_stop Skip the stop bit as this may be chained with a read.
22 * @return The result of the operation.
23 */
25status_t i2c_testutils_write(const dif_i2c_t *i2c, uint8_t addr,
26 size_t byte_count, const uint8_t *data,
27 bool skip_stop);
28
29/**
30 * Construct and issue an I2C read transaction as an I2C host.
31 *
32 * @param i2c An I2C DIF handle.
33 * @param addr The device address for the transaction.
34 * @param byte_count The number of bytes to be read.
35 * @return kOk(nak) Where nak indicates whether the device acknowledged the read
36 * transaction (false) or not (true), otherwise an error.
37 */
39status_t i2c_testutils_issue_read(const dif_i2c_t *i2c, uint8_t addr,
40 uint8_t byte_count);
41
42/**
43 * Check that the target I2C device received the start of a transaction.
44 *
45 * @param i2c An I2C DIF handle.
46 * @param[out] addr The address that was used for the transaction.
47 * @return kOk(dir) Where dir indicates the direction of transaction is signaled
48 * as Read(1) and not Write(0), or an error.
49 */
51status_t i2c_testutils_target_check_start(const dif_i2c_t *i2c, uint8_t *addr);
52
53/**
54 * Check that the target I2C device received the end of a transaction.
55 *
56 * @param i2c An I2C DIF handle.
57 * @param[out] cont_byte The contents of the acquired restart byte if host has
58 * signaled a repeated START, can be null if test doesn't
59 * accept a repeated start.
60 * @return kOk(dir) Where dir indicates that repeated start has signaled that
61 * the transaction should continue and the contents of cont_byte are valid, or
62 * an error.
63 */
65status_t i2c_testutils_target_check_end(const dif_i2c_t *i2c,
66 uint8_t *cont_byte);
67
68/**
69 * Prepare for, and respond to, an I2C read as an I2C device.
70 *
71 * @param i2c An I2C DIF handle.
72 * @param byte_count The number of bytes to be read.
73 * @param data Array of data bytes to be sent.
74 * @return The result of the operation.
75 */
77status_t i2c_testutils_target_read(const dif_i2c_t *i2c, uint16_t byte_count,
78 const uint8_t *data);
79
80/**
81 * Check completion of an I2C read as an I2C device.
82 *
83 * @param i2c An I2C DIF handle.
84 * @param[out] addr Address that received the I2C read.
85 * @param[out] cont_byte received continuation byte. Can be null if test
86 * expects STOP signal.
87 * @return kOk(dir) Where dir indicates that repeated start has signaled that
88 * the transaction should continue and the contents of cont_byte are valid, or
89 * an error.
90 */
92status_t i2c_testutils_target_check_read(const dif_i2c_t *i2c, uint8_t *addr,
93 uint8_t *cont_byte);
94
95/**
96 * Prepare for an I2C write as an I2C device.
97 *
98 * @param i2c A I2C DIF handle.
99 * @param byte_count The number of bytes to be written.
100 * @return The result of the operation.
101 */
103status_t i2c_testutils_target_write(const dif_i2c_t *i2c, uint16_t byte_count);
104
105/**
106 * Check completion of an I2C write as an I2C device.
107 *
108 * @param i2c A I2C DIF handle.
109 * @param byte_count The number of bytes to be written.
110 * @param[out] addr Address that received the I2C write.
111 * @param[out] bytes Array of bytes to stores the result of the write.
112 * @param[out] cont_byte Received continuation byte. Can be null if test expects
113 * STOP signal.
114 * @return kOk(dir) Where dir indicates that repeated START has signaled that
115 * the transaction should continue and the contents of cont_byte are valid, or
116 * an error.
117 */
119status_t i2c_testutils_target_check_write(const dif_i2c_t *i2c,
120 uint16_t byte_count, uint8_t *addr,
121 uint8_t *bytes, uint8_t *cont_byte);
122
123/**
124 * Define the available platforms which i2c is mapped
125 */
126typedef enum i2c_pinmux_platform_id {
127 I2cPinmuxPlatformIdHyper310 = 0,
128 I2cPinmuxPlatformIdDvsim,
129 I2cPinmuxPlatformIdCw310Pmod,
130 I2cPinmuxPlatformIdCount,
131} i2c_pinmux_platform_id_t;
132
133/**
134 * Connect the i2c pins to mio pins via pinmux based on the platform the test is
135 * running.
136 *
137 * @param pimmux A pinmux handler.
138 * @param kI2cIdx The i2c instance identifier.
139 * @param platform The platform which the test is running.
140 * @return The result of the operation.
141 */
143status_t i2c_testutils_select_pinmux(const dif_pinmux_t *pinmux,
144 uint8_t kI2cIdx,
145 i2c_pinmux_platform_id_t platform);
146
147/**
148 * Disconnect the i2c input pins from mio pads and wire it to zero.
149 *
150 * @param pimmux A pinmux handler.
151 * @param i2c_id The i2c instance identifier.
152 * @return The result of the operation.
153 */
155status_t i2c_testutils_detach_pinmux(const dif_pinmux_t *pinmux,
156 uint8_t i2c_id);
157
158/**
159 * Return whether the fifo is empty.
160 *
161 * @param i2c An I2C DIF handle.
162 * @return `kOk(dir)` Where `dir` is true if the fifo is empty. Or an error.
163 */
165static inline status_t i2c_testutils_fifo_empty(const dif_i2c_t *i2c) {
167 TRY(dif_i2c_get_status(i2c, &status));
168 return OK_STATUS(status.rx_fifo_empty);
169}
170
171/**
172 * Return whether the tx fifo is full.
173 *
174 * @param i2c An I2C DIF handle.
175 * @return `kOk(dir)` Where `dir` is true if the tx fifo is full. Or an error.
176 */
178static inline status_t i2c_testutils_tx_fifo_full(const dif_i2c_t *i2c) {
180 TRY(dif_i2c_get_status(i2c, &status));
181 return OK_STATUS(status.tx_fifo_full);
182}
183
184/**
185 * Return whether the tx fifo is empty.
186 *
187 * @param i2c An I2C DIF handle.
188 * @return `kOk(dir)` Where `dir` is true if the tx fifo is empty. Or an error.
189 */
191static inline status_t i2c_testutils_tx_fifo_empty(const dif_i2c_t *i2c) {
193 TRY(dif_i2c_get_status(i2c, &status));
194 return OK_STATUS(status.tx_fifo_empty);
195}
196
197/**
198 * Return whether the fmt fifo is empty.
199 *
200 * @param i2c An I2C DIF handle.
201 * @return `kOk(dir)` Where `dir` is true if the fmt fifo is empty. Or an error.
202 */
204static inline status_t i2c_testutils_fmt_fifo_empty(const dif_i2c_t *i2c) {
206 TRY(dif_i2c_get_status(i2c, &status));
207 return OK_STATUS(status.fmt_fifo_empty);
208}
209
210/**
211 * Issue an i2c read transaction, check for a nak and retry until timeout in
212 * case of nak or read the fifo in case of ack.
213 *
214 * @param i2c An I2C DIF handle.
215 * @param addr The device address for the transaction.
216 * @param byte_count The number of bytes to be read.
217 * @param[out] data Buffer to receive the fifo data.
218 * @param timeout Timeout in microseconds.
219 * @return Return an error code if fails to read, otherwise `kOk(nak_count)`,
220 * where `nak_count` is the number of NAKs received or attempts needed before
221 * the success`.
222 */
224status_t i2c_testutils_read(const dif_i2c_t *i2c, uint8_t addr,
225 size_t byte_count, uint8_t *data, size_t timeout);
226
227/**
228 * Set the i2c timing parameters based on the desired speed mode.
229 *
230 * @param i2c An I2C DIF handle.
231 * @param speed The speed mode.
232 * @return The result of the operation.
233 */
235status_t i2c_testutils_set_speed(const dif_i2c_t *i2c, dif_i2c_speed_t speed);
236
237/**
238 * Busy spin until the i2c host get idle.
239 *
240 * @param i2c An I2C DIF handle.
241 * @return The result of the operation.
242 */
244status_t i2c_testutils_wait_host_idle(const dif_i2c_t *i2c);
245
246/**
247 * Busy spin until the fmt_fifo gets empty (meaning that it has finished the all
248 * the transactions issued) or until a controller halted event is detected.
249 * In the latter case, it will not clear the controller halt event.
250 *
251 * @param i2c An I2C DIF handle.
252 * @return Return an error code if something went wrong, otherwise `kOk(halted)`
253 * where `halted` is 1 if the controller was halted and 0 if fmt_fifo was empty.
254 */
255status_t i2c_testutils_wait_transaction_finish(const dif_i2c_t *i2c);
256#endif // OPENTITAN_SW_DEVICE_LIB_TESTING_I2C_TESTUTILS_H_