1 /*
2  * Copyright 2024 Google LLC
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 
6 #include <zephyr/device.h>
7 #include <zephyr/logging/log.h>
8 #include <zephyr/sys/util.h>
9 #include <zephyr/kernel.h>
10 #include <zephyr/usb_c/usbc.h>
11 #include <zephyr/usb_c/tcpci.h>
12 #include <zephyr/sys/byteorder.h>
13 #include <zephyr/drivers/usb_c/tcpci_priv.h>
14 
15 LOG_MODULE_REGISTER(tcpci, CONFIG_USBC_LOG_LEVEL);
16 
17 #define LOG_COMM_ERR_STR "Can't communicate with TCPC %s@%x (%s %x = %04x)"
18 
19 const struct tcpci_reg_dump_map tcpci_std_regs[TCPCI_STD_REGS_SIZE] = {
20 	{
21 		.addr = TCPC_REG_VENDOR_ID,
22 		.name = "VENDOR_ID",
23 		.size = 2,
24 	},
25 	{
26 		.addr = TCPC_REG_PRODUCT_ID,
27 		.name = "PRODUCT_ID",
28 		.size = 2,
29 	},
30 	{
31 		.addr = TCPC_REG_BCD_DEV,
32 		.name = "DEVICE_ID",
33 		.size = 2,
34 	},
35 	{
36 		.addr = TCPC_REG_TC_REV,
37 		.name = "USBTYPEC_REV",
38 		.size = 2,
39 	},
40 	{
41 		.addr = TCPC_REG_PD_REV,
42 		.name = "USBPD_REV_VER",
43 		.size = 2,
44 	},
45 	{
46 		.addr = TCPC_REG_PD_INT_REV,
47 		.name = "PD_INTERFACE_REV",
48 		.size = 2,
49 	},
50 	{
51 		.addr = TCPC_REG_ALERT,
52 		.name = "ALERT",
53 		.size = 2,
54 	},
55 	{
56 		.addr = TCPC_REG_ALERT_MASK,
57 		.name = "ALERT_MASK",
58 		.size = 2,
59 	},
60 	{
61 		.addr = TCPC_REG_POWER_STATUS_MASK,
62 		.name = "POWER_STATUS_MASK",
63 		.size = 1,
64 	},
65 	{
66 		.addr = TCPC_REG_FAULT_STATUS_MASK,
67 		.name = "FAULT_STATUS_MASK",
68 		.size = 1,
69 	},
70 	{
71 		.addr = TCPC_REG_EXT_STATUS_MASK,
72 		.name = "EXTENDED_STATUS_MASK",
73 		.size = 1,
74 	},
75 	{
76 		.addr = TCPC_REG_ALERT_EXT_MASK,
77 		.name = "ALERT_EXTENDED_MASK",
78 		.size = 1,
79 	},
80 	{
81 		.addr = TCPC_REG_CONFIG_STD_OUTPUT,
82 		.name = "CFG_STANDARD_OUTPUT",
83 		.size = 1,
84 	},
85 	{
86 		.addr = TCPC_REG_TCPC_CTRL,
87 		.name = "TCPC_CONTROL",
88 		.size = 1,
89 	},
90 	{
91 		.addr = TCPC_REG_ROLE_CTRL,
92 		.name = "ROLE_CONTROL",
93 		.size = 1,
94 	},
95 	{
96 		.addr = TCPC_REG_FAULT_CTRL,
97 		.name = "FAULT_CONTROL",
98 		.size = 1,
99 	},
100 	{
101 		.addr = TCPC_REG_POWER_CTRL,
102 		.name = "POWER_CONTROL",
103 		.size = 1,
104 	},
105 	{
106 		.addr = TCPC_REG_CC_STATUS,
107 		.name = "CC_STATUS",
108 		.size = 1,
109 	},
110 	{
111 		.addr = TCPC_REG_POWER_STATUS,
112 		.name = "POWER_STATUS",
113 		.size = 1,
114 	},
115 	{
116 		.addr = TCPC_REG_FAULT_STATUS,
117 		.name = "FAULT_STATUS",
118 		.size = 1,
119 	},
120 	{
121 		.addr = TCPC_REG_EXT_STATUS,
122 		.name = "EXTENDED_STATUS",
123 		.size = 1,
124 	},
125 	{
126 		.addr = TCPC_REG_ALERT_EXT,
127 		.name = "ALERT_EXTENDED",
128 		.size = 1,
129 	},
130 	{
131 		.addr = TCPC_REG_DEV_CAP_1,
132 		.name = "DEVICE_CAPABILITIES_1",
133 		.size = 2,
134 	},
135 	{
136 		.addr = TCPC_REG_DEV_CAP_2,
137 		.name = "DEVICE_CAPABILITIES_2",
138 		.size = 2,
139 	},
140 	{
141 		.addr = TCPC_REG_STD_INPUT_CAP,
142 		.name = "STANDARD_INPUT_CAPABILITIES",
143 		.size = 1,
144 	},
145 	{
146 		.addr = TCPC_REG_STD_OUTPUT_CAP,
147 		.name = "STANDARD_OUTPUT_CAPABILITIES",
148 		.size = 1,
149 	},
150 	{
151 		.addr = TCPC_REG_CONFIG_EXT_1,
152 		.name = "CFG_EXTENDED1",
153 		.size = 1,
154 	},
155 	{
156 		.addr = TCPC_REG_GENERIC_TIMER,
157 		.name = "GENERIC_TIMER",
158 		.size = 2,
159 	},
160 	{
161 		.addr = TCPC_REG_MSG_HDR_INFO,
162 		.name = "MESSAGE_HEADER_INFO",
163 		.size = 1,
164 	},
165 	{
166 		.addr = TCPC_REG_RX_DETECT,
167 		.name = "RECEIVE_DETECT",
168 		.size = 1,
169 	},
170 	{
171 		.addr = TCPC_REG_TRANSMIT,
172 		.name = "TRANSMIT",
173 		.size = 1,
174 	},
175 	{
176 		.addr = TCPC_REG_VBUS_VOLTAGE,
177 		.name = "VBUS_VOLTAGE",
178 		.size = 2,
179 	},
180 	{
181 		.addr = TCPC_REG_VBUS_SINK_DISCONNECT_THRESH,
182 		.name = "VBUS_SINK_DISCONNECT_THRESHOLD",
183 		.size = 2,
184 	},
185 	{
186 		.addr = TCPC_REG_VBUS_STOP_DISCHARGE_THRESH,
187 		.name = "VBUS_STOP_DISCHARGE_THRESHOLD",
188 		.size = 2,
189 	},
190 	{
191 		.addr = TCPC_REG_VBUS_VOLTAGE_ALARM_HI_CFG,
192 		.name = "VBUS_VOLTAGE_ALARM_HI_CFG",
193 		.size = 2,
194 	},
195 	{
196 		.addr = TCPC_REG_VBUS_VOLTAGE_ALARM_LO_CFG,
197 		.name = "VBUS_VOLTAGE_ALARM_LO_CFG",
198 		.size = 2,
199 	},
200 	{
201 		.addr = TCPC_REG_VBUS_NONDEFAULT_TARGET,
202 		.name = "VBUS_NONDEFAULT_TARGET",
203 		.size = 2,
204 	},
205 	{
206 		.addr = TCPC_REG_DEV_CAP_3,
207 		.name = "DEVICE_CAPABILITIES_3",
208 		.size = 2,
209 	},
210 };
211 
tcpci_read_reg8(const struct i2c_dt_spec * i2c,uint8_t reg,uint8_t * value)212 int tcpci_read_reg8(const struct i2c_dt_spec *i2c, uint8_t reg, uint8_t *value)
213 {
214 	int ret;
215 
216 	for (int a = 0; a < CONFIG_USBC_TCPC_TCPCI_I2C_RETRIES; a++) {
217 		ret = i2c_write_read(i2c->bus, i2c->addr, &reg, sizeof(reg), value, sizeof(*value));
218 
219 		if (ret == 0) {
220 			break;
221 		}
222 	}
223 
224 	if (ret != 0) {
225 		LOG_ERR(LOG_COMM_ERR_STR, i2c->bus->name, i2c->addr, "r8", reg, *value);
226 	}
227 
228 	return ret;
229 }
230 
tcpci_write_reg8(const struct i2c_dt_spec * i2c,uint8_t reg,uint8_t value)231 int tcpci_write_reg8(const struct i2c_dt_spec *i2c, uint8_t reg, uint8_t value)
232 {
233 	uint8_t buf[2] = {reg, value};
234 	int ret;
235 
236 	for (int a = 0; a < CONFIG_USBC_TCPC_TCPCI_I2C_RETRIES; a++) {
237 		ret = i2c_write(i2c->bus, buf, 2, i2c->addr);
238 
239 		if (ret == 0) {
240 			break;
241 		}
242 	}
243 
244 	if (ret != 0) {
245 		LOG_ERR(LOG_COMM_ERR_STR, i2c->bus->name, i2c->addr, "w8", reg, value);
246 	}
247 
248 	return ret;
249 }
250 
tcpci_update_reg8(const struct i2c_dt_spec * i2c,uint8_t reg,uint8_t mask,uint8_t value)251 int tcpci_update_reg8(const struct i2c_dt_spec *i2c, uint8_t reg, uint8_t mask, uint8_t value)
252 {
253 	uint8_t old_value;
254 	int ret;
255 
256 	ret = tcpci_read_reg8(i2c, reg, &old_value);
257 	if (ret != 0) {
258 		return ret;
259 	}
260 
261 	old_value &= ~mask;
262 	old_value |= (value & mask);
263 
264 	ret = tcpci_write_reg8(i2c, reg, old_value);
265 
266 	return ret;
267 }
268 
tcpci_read_reg16(const struct i2c_dt_spec * i2c,uint8_t reg,uint16_t * value)269 int tcpci_read_reg16(const struct i2c_dt_spec *i2c, uint8_t reg, uint16_t *value)
270 {
271 	int ret;
272 
273 	for (int a = 0; a < CONFIG_USBC_TCPC_TCPCI_I2C_RETRIES; a++) {
274 		ret = i2c_write_read(i2c->bus, i2c->addr, &reg, sizeof(reg), value, sizeof(*value));
275 
276 		if (ret == 0) {
277 			*value = sys_le16_to_cpu(*value);
278 			break;
279 		}
280 	}
281 
282 	if (ret != 0) {
283 		LOG_ERR(LOG_COMM_ERR_STR, i2c->bus->name, i2c->addr, "r16", reg, *value);
284 	}
285 
286 	return ret;
287 }
288 
tcpci_write_reg16(const struct i2c_dt_spec * i2c,uint8_t reg,uint16_t value)289 int tcpci_write_reg16(const struct i2c_dt_spec *i2c, uint8_t reg, uint16_t value)
290 {
291 	value = sys_cpu_to_le16(value);
292 	uint8_t *value_ptr = (uint8_t *)&value;
293 	uint8_t buf[3] = {reg, value_ptr[0], value_ptr[1]};
294 	int ret;
295 
296 	for (int a = 0; a < CONFIG_USBC_TCPC_TCPCI_I2C_RETRIES; a++) {
297 		ret = i2c_write(i2c->bus, buf, 3, i2c->addr);
298 		if (ret == 0) {
299 			break;
300 		}
301 	}
302 
303 	if (ret != 0) {
304 		LOG_ERR(LOG_COMM_ERR_STR, i2c->bus->name, i2c->addr, "w16", reg, value);
305 	}
306 
307 	return ret;
308 }
309 
tcpci_alert_reg_to_enum(uint16_t reg)310 enum tcpc_alert tcpci_alert_reg_to_enum(uint16_t reg)
311 {
312 	/**
313 	 * Hard reset enum has priority since it causes other bits to be ignored. Other values
314 	 * are sorted by corresponding bits index in the register.
315 	 */
316 	if (reg & TCPC_REG_ALERT_RX_HARD_RST) {
317 		/** Received Hard Reset message */
318 		return TCPC_ALERT_HARD_RESET_RECEIVED;
319 	} else if (reg & TCPC_REG_ALERT_CC_STATUS) {
320 		/** CC status changed */
321 		return TCPC_ALERT_CC_STATUS;
322 	} else if (reg & TCPC_REG_ALERT_POWER_STATUS) {
323 		/** Power status changed */
324 		return TCPC_ALERT_POWER_STATUS;
325 	} else if (reg & TCPC_REG_ALERT_RX_STATUS) {
326 		/** Receive Buffer register changed */
327 		return TCPC_ALERT_MSG_STATUS;
328 	} else if (reg & TCPC_REG_ALERT_TX_FAILED) {
329 		/** SOP* message transmission not successful */
330 		return TCPC_ALERT_TRANSMIT_MSG_FAILED;
331 	} else if (reg & TCPC_REG_ALERT_TX_DISCARDED) {
332 		/**
333 		 * Reset or SOP* message transmission not sent
334 		 * due to an incoming receive message
335 		 */
336 		return TCPC_ALERT_TRANSMIT_MSG_DISCARDED;
337 	} else if (reg & TCPC_REG_ALERT_TX_SUCCESS) {
338 		/** Reset or SOP* message transmission successful */
339 		return TCPC_ALERT_TRANSMIT_MSG_SUCCESS;
340 	} else if (reg & TCPC_REG_ALERT_V_ALARM_HI) {
341 		/** A high-voltage alarm has occurred */
342 		return TCPC_ALERT_VBUS_ALARM_HI;
343 	} else if (reg & TCPC_REG_ALERT_V_ALARM_LO) {
344 		/** A low-voltage alarm has occurred */
345 		return TCPC_ALERT_VBUS_ALARM_LO;
346 	} else if (reg & TCPC_REG_ALERT_FAULT) {
347 		/** A fault has occurred. Read the FAULT_STATUS register */
348 		return TCPC_ALERT_FAULT_STATUS;
349 	} else if (reg & TCPC_REG_ALERT_RX_BUF_OVF) {
350 		/** TCPC RX buffer has overflowed */
351 		return TCPC_ALERT_RX_BUFFER_OVERFLOW;
352 	} else if (reg & TCPC_REG_ALERT_VBUS_DISCNCT) {
353 		/** The TCPC in Attached.SNK state has detected a sink disconnect */
354 		return TCPC_ALERT_VBUS_SNK_DISCONNECT;
355 	} else if (reg & TCPC_REG_ALERT_RX_BEGINNING) {
356 		/** Receive buffer register changed */
357 		return TCPC_ALERT_BEGINNING_MSG_STATUS;
358 	} else if (reg & TCPC_REG_ALERT_EXT_STATUS) {
359 		/** Extended status changed */
360 		return TCPC_ALERT_EXTENDED_STATUS;
361 	} else if (reg & TCPC_REG_ALERT_ALERT_EXT) {
362 		/**
363 		 * An extended interrupt event has occurred. Read the alert_extended
364 		 * register
365 		 */
366 		return TCPC_ALERT_EXTENDED;
367 	} else if (reg & TCPC_REG_ALERT_VENDOR_DEF) {
368 		/** A vendor defined alert has been detected */
369 		return TCPC_ALERT_VENDOR_DEFINED;
370 	}
371 
372 	LOG_ERR("Invalid alert register value");
373 	return -1;
374 }
375 
tcpci_tcpm_get_cc(const struct i2c_dt_spec * bus,enum tc_cc_voltage_state * cc1,enum tc_cc_voltage_state * cc2)376 int tcpci_tcpm_get_cc(const struct i2c_dt_spec *bus, enum tc_cc_voltage_state *cc1,
377 		      enum tc_cc_voltage_state *cc2)
378 {
379 	uint8_t role;
380 	uint8_t status;
381 	int cc1_present_rd, cc2_present_rd;
382 	int rv;
383 
384 	if (cc1 == NULL || cc2 == NULL) {
385 		return -EINVAL;
386 	}
387 
388 	/* errors will return CC as open */
389 	*cc1 = TC_CC_VOLT_OPEN;
390 	*cc2 = TC_CC_VOLT_OPEN;
391 
392 	/* Get the ROLE CONTROL and CC STATUS values */
393 	rv = tcpci_read_reg8(bus, TCPC_REG_ROLE_CTRL, &role);
394 	if (rv != 0) {
395 		return rv;
396 	}
397 
398 	rv = tcpci_read_reg8(bus, TCPC_REG_CC_STATUS, &status);
399 	if (rv != 0) {
400 		return rv;
401 	}
402 
403 	/* Get the current CC values from the CC STATUS */
404 	*cc1 = TCPC_REG_CC_STATUS_CC1_STATE(status);
405 	*cc2 = TCPC_REG_CC_STATUS_CC2_STATE(status);
406 
407 	/* Determine if we are presenting Rd */
408 	cc1_present_rd = 0;
409 	cc2_present_rd = 0;
410 	if (role & TCPC_REG_ROLE_CTRL_DRP_MASK) {
411 		/*
412 		 * We are doing DRP.  We will use the CC STATUS
413 		 * ConnectResult to determine if we are presenting
414 		 * Rd or Rp.
415 		 */
416 		int term;
417 
418 		term = !!(status & TCPC_REG_CC_STATUS_CONNECT_RESULT);
419 
420 		if (*cc1 != TC_CC_VOLT_OPEN) {
421 			cc1_present_rd = term;
422 		}
423 		if (*cc2 != TC_CC_VOLT_OPEN) {
424 			cc2_present_rd = term;
425 		}
426 	} else {
427 		/*
428 		 * We are not doing DRP.  We will use the ROLE CONTROL
429 		 * CC values to determine if we are presenting Rd or Rp.
430 		 */
431 		int role_cc1, role_cc2;
432 
433 		role_cc1 = TCPC_REG_ROLE_CTRL_CC1(role);
434 		role_cc2 = TCPC_REG_ROLE_CTRL_CC2(role);
435 
436 		if (*cc1 != TC_CC_VOLT_OPEN) {
437 			cc1_present_rd = (role_cc1 == TC_CC_RD);
438 		}
439 		if (*cc2 != TC_CC_VOLT_OPEN) {
440 			cc2_present_rd = (role_cc2 == TC_CC_RD);
441 		}
442 	}
443 
444 	*cc1 |= cc1_present_rd << 2;
445 	*cc2 |= cc2_present_rd << 2;
446 
447 	return 0;
448 }
449 
tcpci_tcpm_get_chip_info(const struct i2c_dt_spec * bus,struct tcpc_chip_info * chip_info)450 int tcpci_tcpm_get_chip_info(const struct i2c_dt_spec *bus, struct tcpc_chip_info *chip_info)
451 {
452 	int ret;
453 
454 	if (chip_info == NULL) {
455 		return -EIO;
456 	}
457 
458 	ret = tcpci_read_reg16(bus, TCPC_REG_VENDOR_ID, &chip_info->vendor_id);
459 	if (ret != 0) {
460 		return ret;
461 	}
462 
463 	ret = tcpci_read_reg16(bus, TCPC_REG_PRODUCT_ID, &chip_info->product_id);
464 	if (ret != 0) {
465 		return ret;
466 	}
467 
468 	return tcpci_read_reg16(bus, TCPC_REG_BCD_DEV, &chip_info->device_id);
469 }
470 
tcpci_tcpm_dump_std_reg(const struct i2c_dt_spec * bus)471 int tcpci_tcpm_dump_std_reg(const struct i2c_dt_spec *bus)
472 {
473 	uint16_t value;
474 
475 	for (unsigned int a = 0; a < ARRAY_SIZE(tcpci_std_regs); a++) {
476 		switch (tcpci_std_regs[a].size) {
477 		case 1:
478 			tcpci_read_reg8(bus, tcpci_std_regs[a].addr, (uint8_t *)&value);
479 			LOG_INF("- %-30s(0x%02x) =   0x%02x", tcpci_std_regs[a].name,
480 				tcpci_std_regs[a].addr, (uint8_t)value);
481 			break;
482 		case 2:
483 			tcpci_read_reg16(bus, tcpci_std_regs[a].addr, &value);
484 			LOG_INF("- %-30s(0x%02x) = 0x%04x", tcpci_std_regs[a].name,
485 				tcpci_std_regs[a].addr, value);
486 			break;
487 		}
488 	}
489 
490 	return 0;
491 }
492 
tcpci_tcpm_set_bist_test_mode(const struct i2c_dt_spec * bus,bool enable)493 int tcpci_tcpm_set_bist_test_mode(const struct i2c_dt_spec *bus, bool enable)
494 {
495 	return tcpci_update_reg8(bus, TCPC_REG_TCPC_CTRL, TCPC_REG_TCPC_CTRL_BIST_TEST_MODE,
496 				 enable ? TCPC_REG_TCPC_CTRL_BIST_TEST_MODE : 0);
497 }
498 
tcpci_tcpm_transmit_data(const struct i2c_dt_spec * bus,struct pd_msg * msg,const uint8_t retries)499 int tcpci_tcpm_transmit_data(const struct i2c_dt_spec *bus, struct pd_msg *msg,
500 			     const uint8_t retries)
501 {
502 	int reg = TCPC_REG_TX_BUFFER;
503 	int rv;
504 	int cnt = 4 * msg->header.number_of_data_objects;
505 
506 	/* If not SOP* transmission, just write to the transmit register */
507 	if (msg->header.message_type >= NUM_SOP_STAR_TYPES) {
508 		/*
509 		 * Per TCPCI spec, do not specify retry (although the TCPC
510 		 * should ignore retry field for these 3 types).
511 		 */
512 		return tcpci_write_reg8(
513 			bus, TCPC_REG_TRANSMIT,
514 			TCPC_REG_TRANSMIT_SET_WITHOUT_RETRY(msg->header.message_type));
515 	}
516 
517 	if (cnt > 0) {
518 		reg = TCPC_REG_TX_BUFFER;
519 		/* TX_BYTE_CNT includes extra bytes for message header */
520 		cnt += sizeof(msg->header.raw_value);
521 
522 		struct i2c_msg buf[3];
523 
524 		uint8_t tmp[2] = {TCPC_REG_TX_BUFFER, cnt};
525 
526 		buf[0].buf = tmp;
527 		buf[0].len = 2;
528 		buf[0].flags = I2C_MSG_WRITE;
529 
530 		buf[1].buf = (uint8_t *)&msg->header.raw_value;
531 		buf[1].len = sizeof(msg->header.raw_value);
532 		buf[1].flags = I2C_MSG_WRITE;
533 
534 		buf[2].buf = (uint8_t *)msg->data;
535 		buf[2].len = msg->len;
536 		buf[2].flags = I2C_MSG_WRITE | I2C_MSG_STOP;
537 
538 		if (cnt > sizeof(msg->header.raw_value)) {
539 			rv = i2c_transfer(bus->bus, buf, 3, bus->addr);
540 		} else {
541 			buf[1].flags |= I2C_MSG_STOP;
542 			rv = i2c_transfer(bus->bus, buf, 2, bus->addr);
543 		}
544 
545 		/* If tcpc write fails, return error */
546 		if (rv) {
547 			return rv;
548 		}
549 	}
550 
551 	/*
552 	 * We always retry in TCPC hardware since the TCPM is too slow to
553 	 * respond within tRetry (~195 usec).
554 	 *
555 	 * The retry count used is dependent on the maximum PD revision
556 	 * supported at build time.
557 	 */
558 	rv = tcpci_write_reg8(bus, TCPC_REG_TRANSMIT,
559 			      TCPC_REG_TRANSMIT_SET_WITH_RETRY(retries, msg->type));
560 
561 	return rv;
562 }
563 
tcpci_tcpm_select_rp_value(const struct i2c_dt_spec * bus,enum tc_rp_value rp)564 int tcpci_tcpm_select_rp_value(const struct i2c_dt_spec *bus, enum tc_rp_value rp)
565 {
566 	return tcpci_update_reg8(bus, TCPC_REG_ROLE_CTRL, TCPC_REG_ROLE_CTRL_RP_MASK,
567 				 TCPC_REG_ROLE_CTRL_SET(0, rp, 0, 0));
568 }
569 
tcpci_tcpm_get_rp_value(const struct i2c_dt_spec * bus,enum tc_rp_value * rp)570 int tcpci_tcpm_get_rp_value(const struct i2c_dt_spec *bus, enum tc_rp_value *rp)
571 {
572 	uint8_t reg_value = 0;
573 	int ret;
574 
575 	ret = tcpci_read_reg8(bus, TCPC_REG_ROLE_CTRL, &reg_value);
576 	*rp = TCPC_REG_ROLE_CTRL_RP(reg_value);
577 
578 	return ret;
579 }
580 
tcpci_tcpm_set_cc(const struct i2c_dt_spec * bus,enum tc_cc_pull pull)581 int tcpci_tcpm_set_cc(const struct i2c_dt_spec *bus, enum tc_cc_pull pull)
582 {
583 	return tcpci_update_reg8(bus, TCPC_REG_ROLE_CTRL,
584 				 TCPC_REG_ROLE_CTRL_CC1_MASK | TCPC_REG_ROLE_CTRL_CC2_MASK,
585 				 TCPC_REG_ROLE_CTRL_SET(0, 0, pull, pull));
586 }
587 
tcpci_tcpm_set_vconn(const struct i2c_dt_spec * bus,bool enable)588 int tcpci_tcpm_set_vconn(const struct i2c_dt_spec *bus, bool enable)
589 {
590 	return tcpci_update_reg8(bus, TCPC_REG_POWER_CTRL, TCPC_REG_POWER_CTRL_VCONN_EN,
591 				 enable ? TCPC_REG_POWER_CTRL_VCONN_EN : 0);
592 }
593 
tcpci_tcpm_set_roles(const struct i2c_dt_spec * bus,enum pd_rev_type pd_rev,enum tc_power_role power_role,enum tc_data_role data_role)594 int tcpci_tcpm_set_roles(const struct i2c_dt_spec *bus, enum pd_rev_type pd_rev,
595 			 enum tc_power_role power_role, enum tc_data_role data_role)
596 {
597 	return tcpci_update_reg8(bus, TCPC_REG_MSG_HDR_INFO, TCPC_REG_MSG_HDR_INFO_ROLES_MASK,
598 				 TCPC_REG_MSG_HDR_INFO_SET(pd_rev, data_role, power_role));
599 }
600 
tcpci_tcpm_set_drp_toggle(const struct i2c_dt_spec * bus,bool enable)601 int tcpci_tcpm_set_drp_toggle(const struct i2c_dt_spec *bus, bool enable)
602 {
603 	return tcpci_update_reg8(bus, TCPC_REG_ROLE_CTRL, TCPC_REG_ROLE_CTRL_DRP_MASK,
604 				 TCPC_REG_ROLE_CTRL_SET(enable, 0, 0, 0));
605 }
606 
tcpci_tcpm_set_rx_type(const struct i2c_dt_spec * bus,uint8_t rx_type)607 int tcpci_tcpm_set_rx_type(const struct i2c_dt_spec *bus, uint8_t rx_type)
608 {
609 	return tcpci_write_reg8(bus, TCPC_REG_RX_DETECT, rx_type);
610 }
611 
tcpci_tcpm_set_cc_polarity(const struct i2c_dt_spec * bus,enum tc_cc_polarity polarity)612 int tcpci_tcpm_set_cc_polarity(const struct i2c_dt_spec *bus, enum tc_cc_polarity polarity)
613 {
614 	return tcpci_update_reg8(
615 		bus, TCPC_REG_TCPC_CTRL, TCPC_REG_TCPC_CTRL_PLUG_ORIENTATION,
616 		(polarity == TC_POLARITY_CC1) ? 0 : TCPC_REG_TCPC_CTRL_PLUG_ORIENTATION);
617 }
618 
tcpci_tcpm_get_status_register(const struct i2c_dt_spec * bus,enum tcpc_status_reg reg,uint16_t * status)619 int tcpci_tcpm_get_status_register(const struct i2c_dt_spec *bus, enum tcpc_status_reg reg,
620 				   uint16_t *status)
621 {
622 	switch (reg) {
623 	case TCPC_ALERT_STATUS:
624 		return tcpci_read_reg16(bus, TCPC_REG_ALERT, status);
625 	case TCPC_CC_STATUS:
626 		return tcpci_read_reg8(bus, TCPC_REG_CC_STATUS, (uint8_t *)status);
627 	case TCPC_POWER_STATUS:
628 		return tcpci_read_reg8(bus, TCPC_REG_POWER_STATUS, (uint8_t *)status);
629 	case TCPC_FAULT_STATUS:
630 		return tcpci_read_reg8(bus, TCPC_REG_FAULT_STATUS, (uint8_t *)status);
631 	case TCPC_EXTENDED_STATUS:
632 		return tcpci_read_reg8(bus, TCPC_REG_EXT_STATUS, (uint8_t *)status);
633 	case TCPC_EXTENDED_ALERT_STATUS:
634 		return tcpci_read_reg8(bus, TCPC_REG_ALERT_EXT, (uint8_t *)status);
635 	default:
636 		LOG_ERR("Not a TCPCI-specified reg address");
637 		return -EINVAL;
638 	}
639 }
640 
tcpci_tcpm_clear_status_register(const struct i2c_dt_spec * bus,enum tcpc_status_reg reg,uint16_t mask)641 int tcpci_tcpm_clear_status_register(const struct i2c_dt_spec *bus, enum tcpc_status_reg reg,
642 				     uint16_t mask)
643 {
644 	switch (reg) {
645 	case TCPC_ALERT_STATUS:
646 		return tcpci_write_reg16(bus, TCPC_REG_ALERT, mask);
647 	case TCPC_CC_STATUS:
648 		LOG_ERR("CC_STATUS is cleared by the TCPC");
649 		return -EINVAL;
650 	case TCPC_POWER_STATUS:
651 		LOG_ERR("POWER_STATUS is cleared by the TCPC");
652 		return -EINVAL;
653 	case TCPC_FAULT_STATUS:
654 		return tcpci_write_reg8(bus, TCPC_REG_FAULT_STATUS, (uint8_t)mask);
655 	case TCPC_EXTENDED_STATUS:
656 		return tcpci_write_reg8(bus, TCPC_REG_EXT_STATUS, (uint8_t)mask);
657 	case TCPC_EXTENDED_ALERT_STATUS:
658 		return tcpci_write_reg8(bus, TCPC_REG_ALERT_EXT, (uint8_t)mask);
659 	default:
660 		LOG_ERR("Not a TCPCI-specified reg address");
661 		return -EINVAL;
662 	}
663 }
664 
tcpci_tcpm_mask_status_register(const struct i2c_dt_spec * bus,enum tcpc_status_reg reg,uint16_t mask)665 int tcpci_tcpm_mask_status_register(const struct i2c_dt_spec *bus, enum tcpc_status_reg reg,
666 				    uint16_t mask)
667 {
668 	switch (reg) {
669 	case TCPC_ALERT_STATUS:
670 		return tcpci_write_reg16(bus, TCPC_REG_ALERT_MASK, mask);
671 	case TCPC_CC_STATUS:
672 		LOG_ERR("CC_STATUS does not have a corresponding mask register");
673 		return -EINVAL;
674 	case TCPC_POWER_STATUS:
675 		return tcpci_write_reg8(bus, TCPC_REG_POWER_STATUS_MASK, (uint8_t)mask);
676 	case TCPC_FAULT_STATUS:
677 		return tcpci_write_reg8(bus, TCPC_REG_FAULT_STATUS_MASK, (uint8_t)mask);
678 	case TCPC_EXTENDED_STATUS:
679 		return tcpci_write_reg8(bus, TCPC_REG_EXT_STATUS_MASK, (uint8_t)mask);
680 	case TCPC_EXTENDED_ALERT_STATUS:
681 		return tcpci_write_reg8(bus, TCPC_REG_ALERT_EXT_MASK, (uint8_t)mask);
682 	default:
683 		LOG_ERR("Not a TCPCI-specified reg address");
684 		return -EINVAL;
685 	}
686 }
687