summaryrefslogtreecommitdiff
path: root/zephyr/include/emul/tcpc/emul_tcpci.h
blob: 3a5a3047d73332c41302a2629f57bf25579db91b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
/* Copyright 2021 The Chromium OS Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

/**
 * @file
 *
 * @brief Backend API for TCPCI emulator
 */

#ifndef __EMUL_TCPCI_H
#define __EMUL_TCPCI_H

#include <emul.h>
#include <drivers/i2c.h>
#include <drivers/i2c_emul.h>
#include <usb_pd_tcpm.h>

/**
 * @brief TCPCI emulator backend API
 * @defgroup tcpci_emul TCPCI emulator
 * @{
 *
 * TCPCI emulator supports access to its registers using I2C messages.
 * It follows Type-C Port Controller Interface Specification. It is possible
 * to use this emulator as base for implementation of specific TCPC emulator
 * which follows TCPCI specification. Emulator allows to set callbacks
 * on change of CC status or transmitting message to implement partner emulator.
 * There is also callback used to inform about alert line state change.
 * Application may alter emulator state:
 *
 * - call @ref tcpci_emul_set_reg and @ref tcpci_emul_get_reg to set and get
 *   value of TCPCI registers
 * - call functions from emul_common_i2c.h to setup custom handlers for I2C
 *   messages
 * - call @ref tcpci_emul_add_rx_msg to setup received SOP messages
 * - call @ref tcpci_emul_get_tx_msg to examine sended message
 * - call @ref tcpci_emul_set_rev to set revision of emulated TCPCI
 */

/** SOP message structure */
struct tcpci_emul_msg {
	/** Pointer to buffer for header and message */
	uint8_t *buf;
	/** Number of bytes in buf */
	int cnt;
	/** Type of message (SOP, SOP', etc) */
	uint8_t type;
	/** Index used to mark accessed byte */
	int idx;
	/** Pointer to optional second message */
	struct tcpci_emul_msg *next;
};

/**
 * @brief Function type that is used by TCPCI emulator to provide information
 *        about alert line state
 *
 * @param emul Pointer to emulator
 * @param alert State of alert line (false - low, true - high)
 * @param data Pointer to custom function data
 */
typedef void (*tcpci_emul_alert_state_func)(const struct emul *emul, bool alert,
					    void *data);

/** Response from TCPCI specific device operations */
enum tcpci_emul_ops_resp {
	TCPCI_EMUL_CONTINUE = 0,
	TCPCI_EMUL_DONE,
	TCPCI_EMUL_ERROR
};

/** Revisions supported by TCPCI emaluator */
enum tcpci_emul_rev {
	TCPCI_EMUL_REV1_0_VER1_0 = 0,
	TCPCI_EMUL_REV2_0_VER1_1
};

/** Status of TX message send to TCPCI emulator partner */
enum tcpci_emul_tx_status {
	TCPCI_EMUL_TX_SUCCESS,
	TCPCI_EMUL_TX_DISCARDED,
	TCPCI_EMUL_TX_FAILED
};

/** TCPCI specific device operations. Not all of them need to be implemented. */
struct tcpci_emul_dev_ops {
	/**
	 * @brief Function called for each byte of read message
	 *
	 * @param emul Pointer to TCPCI emulator
	 * @param ops Pointer to device operations structure
	 * @param reg First byte of last write message
	 * @param val Pointer where byte to read should be stored
	 * @param bytes Number of bytes already readded
	 *
	 * @return TCPCI_EMUL_CONTINUE to continue with default handler
	 * @return TCPCI_EMUL_DONE to immedietly return success
	 * @return TCPCI_EMUL_ERROR to immedietly return error
	 */
	enum tcpci_emul_ops_resp (*read_byte)(const struct emul *emul,
					const struct tcpci_emul_dev_ops *ops,
					int reg, uint8_t *val, int bytes);

	/**
	 * @brief Function called for each byte of write message
	 *
	 * @param emul Pointer to TCPCI emulator
	 * @param ops Pointer to device operations structure
	 * @param reg First byte of write message
	 * @param val Received byte of write message
	 * @param bytes Number of bytes already received
	 *
	 * @return TCPCI_EMUL_CONTINUE to continue with default handler
	 * @return TCPCI_EMUL_DONE to immedietly return success
	 * @return TCPCI_EMUL_ERROR to immedietly return error
	 */
	enum tcpci_emul_ops_resp (*write_byte)(const struct emul *emul,
					const struct tcpci_emul_dev_ops *ops,
					int reg, uint8_t val, int bytes);

	/**
	 * @brief Function called on the end of write message
	 *
	 * @param emul Pointer to TCPCI emulator
	 * @param ops Pointer to device operations structure
	 * @param reg Register which is written
	 * @param msg_len Length of handled I2C message
	 *
	 * @return TCPCI_EMUL_CONTINUE to continue with default handler
	 * @return TCPCI_EMUL_DONE to immedietly return success
	 * @return TCPCI_EMUL_ERROR to immedietly return error
	 */
	enum tcpci_emul_ops_resp (*handle_write)(const struct emul *emul,
					const struct tcpci_emul_dev_ops *ops,
					int reg, int msg_len);

	/**
	 * @brief Function called on reset
	 *
	 * @param emul Pointer to TCPCI emulator
	 * @param ops Pointer to device operations structure
	 */
	void (*reset)(const struct emul *emul, struct tcpci_emul_dev_ops *ops);
};

/** TCPCI partner operations. Not all of them need to be implemented. */
struct tcpci_emul_partner_ops {
	/**
	 * @brief Function called when TCPM wants to transmit message to partner
	 *        connected to TCPCI
	 *
	 * @param emul Pointer to TCPCI emulator
	 * @param ops Pointer to partner operations structure
	 * @param tx_msg Pointer to TX message buffer
	 * @param type Type of message
	 * @param retry Count of retries
	 */
	void (*transmit)(const struct emul *emul,
			 const struct tcpci_emul_partner_ops *ops,
			 const struct tcpci_emul_msg *tx_msg,
			 enum tcpci_msg_type type,
			 int retry);

	/**
	 * @brief Function called when control settings change to allow partner
	 *        to react
	 *
	 * @param emul Pointer to TCPCI emulator
	 * @param ops Pointer to partner operations structure
	 */
	void (*control_change)(const struct emul *emul,
			       const struct tcpci_emul_partner_ops *ops);

	/**
	 * @brief Function called when TCPM consumes message send by partner
	 *
	 * @param emul Pointer to TCPCI emulator
	 * @param ops Pointer to partner operations structure
	 * @param rx_msg Message that was consumed by TCPM
	 */
	void (*rx_consumed)(const struct emul *emul,
			    const struct tcpci_emul_partner_ops *ops,
			    const struct tcpci_emul_msg *rx_msg);
};

/**
 * @brief Get i2c_emul for TCPCI emulator
 *
 * @param emul Pointer to TCPCI emulator
 *
 * @return Pointer to I2C TCPCI emulator
 */
struct i2c_emul *tcpci_emul_get_i2c_emul(const struct emul *emul);

/**
 * @brief Set value of given register of TCPCI
 *
 * @param emul Pointer to TCPCI emulator
 * @param reg Register address which value will be changed
 * @param val New value of the register
 *
 * @return 0 on success
 * @return -EINVAL when register is out of range defined in TCPCI specification
 */
int tcpci_emul_set_reg(const struct emul *emul, int reg, uint16_t val);

/**
 * @brief Get value of given register of TCPCI
 *
 * @param emul Pointer to TCPCI emulator
 * @param reg Register address
 * @param val Pointer where value should be stored
 *
 * @return 0 on success
 * @return -EINVAL when register is out of range defined in TCPCI specification
 *                 or val is NULL
 */
int tcpci_emul_get_reg(const struct emul *emul, int reg, uint16_t *val);

/**
 * @brief Add up to two SOP RX messages
 *
 * @param emul Pointer to TCPCI emulator
 * @param rx_msg Pointer to message that is added
 * @param alert Select if alert register should be updated
 *
 * @return 0 on success
 * @return -EINVAL on error (too long message or adding third message)
 */
int tcpci_emul_add_rx_msg(const struct emul *emul,
			  struct tcpci_emul_msg *rx_msg, bool alert);

/**
 * @brief Get SOP TX message to examine what was sended by TCPM
 *
 * @param emul Pointer to TCPCI emulator
 *
 * @return Pointer to TX message
 */
struct tcpci_emul_msg *tcpci_emul_get_tx_msg(const struct emul *emul);

/**
 * @brief Set TCPCI revision in PD_INT_REV register
 *
 * @param emul Pointer to TCPCI emulator
 * @param rev Requested revision
 */
void tcpci_emul_set_rev(const struct emul *emul, enum tcpci_emul_rev rev);

/**
 * @brief Set callbacks for specific TCPC device emulator
 *
 * @param emul Pointer to TCPCI emulator
 * @param dev_ops Pointer to callbacks
 */
void tcpci_emul_set_dev_ops(const struct emul *emul,
			    struct tcpci_emul_dev_ops *dev_ops);

/**
 * @brief Set callback which is called when alert register is changed
 *
 * @param emul Pointer to TCPCI emulator
 * @param alert_callback Pointer to callback
 * @param alert_callback_data Pointer to data passed to callback as an argument
 */
void tcpci_emul_set_alert_callback(const struct emul *emul,
				   tcpci_emul_alert_state_func alert_callback,
				   void *alert_callback_data);

/**
 * @brief Set callbacks for port partner device emulator
 *
 * @param emul Pointer to TCPCI emulator
 * @param partner Pointer to callbacks
 */
void tcpci_emul_set_partner_ops(const struct emul *emul,
				struct tcpci_emul_partner_ops *partner);

/**
 * @brief Emulate connection of specific device to emulated TCPCI
 *
 * @param emul Pointer to TCPCI emulator
 * @param partner_power_role Power role of connected partner (sink or source)
 * @param partner_cc1 Voltage on partner CC1 line (usually Rd or Rp)
 * @param partner_cc2 Voltage on partner CC2 line (usually open or Ra if active
 *                    cable is emulated)
 * @param polarity Polarity of plug. If POLARITY_CC1 then partner_cc1 is
 *                 connected to TCPCI CC1 line. Otherwise partner_cc1 is
 *                 connected to TCPCI CC2 line.
 *
 * @return 0 on success
 * @return negative on error
 */
int tcpci_emul_connect_partner(const struct emul *emul,
			       enum pd_power_role partner_power_role,
			       enum tcpc_cc_voltage_status partner_cc1,
			       enum tcpc_cc_voltage_status partner_cc2,
			       enum tcpc_cc_polarity polarity);

/** @brief Emulate the disconnection of the partner device to emulated TCPCI
 *
 * @param emul Pointer to TCPCI emulator
 *
 * @return 0 on success
 */
int tcpci_emul_disconnect_partner(const struct emul *emul);

/**
 * @brief Allows port partner to select if message was received correctly
 *
 * @param emul Pointer to TCPCI emulator
 * @param status Status of sended message
 */
void tcpci_emul_partner_msg_status(const struct emul *emul,
				   enum tcpci_emul_tx_status status);

/**
 * @}
 */

#endif /* __EMUL_TCPCI */