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, ®, 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, ®, 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, ®_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