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 I2cPinmuxPlatformIdCw340,
131 I2cPinmuxPlatformIdSilicon,
132 I2cPinmuxPlatformIdCount,
133} i2c_pinmux_platform_id_t;
134
135/**
136 * Connect the i2c pins to mio pins via pinmux based on the platform the test is
137 * running.
138 *
139 * @param pimmux A pinmux handler.
140 * @param kI2cIdx The i2c instance identifier.
141 * @param platform The platform which the test is running.
142 * @return The result of the operation.
143 */
145status_t i2c_testutils_select_pinmux(const dif_pinmux_t *pinmux,
146 uint8_t kI2cIdx,
147 i2c_pinmux_platform_id_t platform);
148
149/**
150 * Disconnect the i2c input pins from mio pads and wire it to zero.
151 *
152 * @param pimmux A pinmux handler.
153 * @param i2c_id The i2c instance identifier.
154 * @return The result of the operation.
155 */
157status_t i2c_testutils_detach_pinmux(const dif_pinmux_t *pinmux,
158 uint8_t i2c_id);
159
160/**
161 * Return whether the fifo is empty.
162 *
163 * @param i2c An I2C DIF handle.
164 * @return `kOk(dir)` Where `dir` is true if the fifo is empty. Or an error.
165 */
167static inline status_t i2c_testutils_fifo_empty(const dif_i2c_t *i2c) {
169 TRY(dif_i2c_get_status(i2c, &status));
170 return OK_STATUS(status.rx_fifo_empty);
171}
172
173/**
174 * Return whether the tx fifo is full.
175 *
176 * @param i2c An I2C DIF handle.
177 * @return `kOk(dir)` Where `dir` is true if the tx fifo is full. Or an error.
178 */
180static inline status_t i2c_testutils_tx_fifo_full(const dif_i2c_t *i2c) {
182 TRY(dif_i2c_get_status(i2c, &status));
183 return OK_STATUS(status.tx_fifo_full);
184}
185
186/**
187 * Return whether the tx fifo is empty.
188 *
189 * @param i2c An I2C DIF handle.
190 * @return `kOk(dir)` Where `dir` is true if the tx fifo is empty. Or an error.
191 */
193static inline status_t i2c_testutils_tx_fifo_empty(const dif_i2c_t *i2c) {
195 TRY(dif_i2c_get_status(i2c, &status));
196 return OK_STATUS(status.tx_fifo_empty);
197}
198
199/**
200 * Return whether the fmt fifo is empty.
201 *
202 * @param i2c An I2C DIF handle.
203 * @return `kOk(dir)` Where `dir` is true if the fmt fifo is empty. Or an error.
204 */
206static inline status_t i2c_testutils_fmt_fifo_empty(const dif_i2c_t *i2c) {
208 TRY(dif_i2c_get_status(i2c, &status));
209 return OK_STATUS(status.fmt_fifo_empty);
210}
211
212/**
213 * Issue an i2c read transaction, check for a nak and retry until timeout in
214 * case of nak or read the fifo in case of ack.
215 *
216 * @param i2c An I2C DIF handle.
217 * @param addr The device address for the transaction.
218 * @param byte_count The number of bytes to be read.
219 * @param[out] data Buffer to receive the fifo data.
220 * @param timeout Timeout in microseconds.
221 * @return Return an error code if fails to read, otherwise `kOk(nak_count)`,
222 * where `nak_count` is the number of NAKs received or attempts needed before
223 * the success`.
224 */
226status_t i2c_testutils_read(const dif_i2c_t *i2c, uint8_t addr,
227 size_t byte_count, uint8_t *data, size_t timeout);
228
229/**
230 * Set the i2c timing parameters based on the desired speed mode.
231 * Also see
232 * https://opentitan.org/book/hw/ip/i2c/doc/programmers_guide.html#initialization
233 *
234 * @param i2c An I2C DIF handle.
235 * @param speed The speed mode.
236 * @param sda_rise_nanos The expected time it takes for the I2C bus signal to
237 * rise. This depends on hardware interconnect properties.
238 * @param sda_fall_nanos The expected time it takes for the I2C bus signal to
239 * fall. This depends on hardware interconnect properties.
240 * @return The result of the operation.
241 */
243status_t i2c_testutils_set_speed(const dif_i2c_t *i2c, dif_i2c_speed_t speed,
244 uint32_t sda_rise_nanos,
245 uint32_t sda_fall_nanos);
246
247/**
248 * Busy spin until the i2c host get idle.
249 *
250 * @param i2c An I2C DIF handle.
251 * @return The result of the operation.
252 */
254status_t i2c_testutils_wait_host_idle(const dif_i2c_t *i2c);
255
256/**
257 * Busy spin until the fmt_fifo gets empty (meaning that it has finished the all
258 * the transactions issued) or until a controller halted event is detected.
259 * In the latter case, it will not clear the controller halt event.
260 *
261 * @param i2c An I2C DIF handle.
262 * @return Return an error code if something went wrong, otherwise `kOk(halted)`
263 * where `halted` is 1 if the controller was halted and 0 if fmt_fifo was empty.
264 */
265status_t i2c_testutils_wait_transaction_finish(const dif_i2c_t *i2c);
266#endif // OPENTITAN_SW_DEVICE_LIB_TESTING_I2C_TESTUTILS_H_