1 /* $OpenBSD: tcpci.c,v 1.1 2020/04/27 21:30:52 patrick Exp $ */ 2 /* 3 * Copyright (c) 2018 Patrick Wildt <patrick@blueri.se> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 #include <sys/systm.h> 20 #include <sys/kernel.h> 21 #include <sys/device.h> 22 #include <sys/malloc.h> 23 #include <sys/stdint.h> 24 #include <sys/task.h> 25 26 #include <machine/bus.h> 27 #include <machine/fdt.h> 28 29 #include <dev/i2c/i2cvar.h> 30 #include <dev/ofw/openfirm.h> 31 #include <dev/ofw/ofw_gpio.h> 32 #include <dev/ofw/ofw_misc.h> 33 #include <dev/ofw/ofw_pinctrl.h> 34 35 /* #define TCPCI_DEBUG */ 36 37 #ifdef TCPCI_DEBUG 38 #define DPRINTF(x) printf x 39 #else 40 #define DPRINTF(x) 41 #endif 42 43 #define TCPC_VENDOR_ID 0x00 44 #define TCPC_PRODUCT_ID 0x02 45 #define TCPC_BCD_DEV 0x04 46 #define TCPC_TC_REV 0x06 47 #define TCPC_PD_REV 0x08 48 #define TCPC_PD_INT_REV 0x0a 49 #define TCPC_ALERT 0x10 50 #define TCPC_ALERT_CC_STATUS (1 << 0) 51 #define TCPC_ALERT_POWER_STATUS (1 << 1) 52 #define TCPC_ALERT_RX_STATUS (1 << 2) 53 #define TCPC_ALERT_RX_HARD_RST (1 << 3) 54 #define TCPC_ALERT_TX_FAILED (1 << 4) 55 #define TCPC_ALERT_TX_DISCARDED (1 << 5) 56 #define TCPC_ALERT_TX_SUCCESS (1 << 6) 57 #define TCPC_ALERT_V_ALARM_HI (1 << 7) 58 #define TCPC_ALERT_V_ALARM_LO (1 << 8) 59 #define TCPC_ALERT_FAULT (1 << 9) 60 #define TCPC_ALERT_RX_BUF_OVF (1 << 10) 61 #define TCPC_ALERT_VBUS_DISCNCT (1 << 11) 62 #define TCPC_ALERT_MASK 0x12 63 #define TCPC_POWER_STATUS_MASK 0x14 64 #define TCPC_POWER_STATUS_VBUS_PRES (1 << 2) 65 #define TCPC_FAULT_STATUS_MASK 0x15 66 #define TCPC_CONFIG_STD_OUTPUT 0x18 67 #define TCPC_TCPC_CTRL 0x19 68 #define TCPC_TCPC_CTRL_ORIENTATION (1 << 0) 69 #define TCPC_TCPC_CTRL_BIST_MODE (1 << 1) 70 #define TCPC_ROLE_CTRL 0x1a 71 #define TCPC_ROLE_CTRL_CC1_SHIFT 0 72 #define TCPC_ROLE_CTRL_CC2_SHIFT 2 73 #define TCPC_ROLE_CTRL_CC_RA 0x0 74 #define TCPC_ROLE_CTRL_CC_RP 0x1 75 #define TCPC_ROLE_CTRL_CC_RD 0x2 76 #define TCPC_ROLE_CTRL_CC_OPEN 0x3 77 #define TCPC_ROLE_CTRL_CC_MASK 0x3 78 #define TCPC_ROLE_CTRL_RP_VAL_MASK (0x3 << 4) 79 #define TCPC_ROLE_CTRL_RP_VAL_DEF (0x0 << 4) 80 #define TCPC_ROLE_CTRL_RP_VAL_1_5 (0x1 << 4) 81 #define TCPC_ROLE_CTRL_RP_VAL_3_0 (0x2 << 4) 82 #define TCPC_ROLE_CTRL_DRP (1 << 6) 83 #define TCPC_FAULT_CTRL 0x1b 84 #define TCPC_POWER_CTRL 0x1c 85 #define TCPC_POWER_CTRL_VCONN_ENABLE (1 << 0) 86 #define TCPC_POWER_CTRL_FORCEDISCH (1 << 2) 87 #define TCPC_POWER_CTRL_DIS_VOL_ALARM (1 << 5) 88 #define TCPC_CC_STATUS 0x1d 89 #define TCPC_CC_STATUS_CC1_SHIFT 0 90 #define TCPC_CC_STATUS_CC2_SHIFT 2 91 #define TCPC_CC_STATUS_CC_MASK 0x3 92 #define TCPC_CC_STATUS_TERM (1 << 4) 93 #define TCPC_CC_STATUS_TOGGLING (1 << 5) 94 #define TCPC_POWER_STATUS 0x1e 95 #define TCPC_FAULT_STATUS 0x1f 96 #define TCPC_FAULT_STATUS_CLEAR (1 << 7) 97 #define TCPC_COMMAND 0x23 98 #define TCPC_COMMAND_WAKE_I2C 0x11 99 #define TCPC_COMMAND_DISABLE_VBUS_DETECT 0x22 100 #define TCPC_COMMAND_ENABLE_VBUS_DETECT 0x33 101 #define TCPC_COMMAND_DISABLE_SINK_VBUS 0x44 102 #define TCPC_COMMAND_SINK_VBUS 0x55 103 #define TCPC_COMMAND_DISABLE_SRC_VBUS 0x66 104 #define TCPC_COMMAND_SRC_VBUS_DEFAULT 0x77 105 #define TCPC_COMMAND_SRC_VBUS_HIGH 0x88 106 #define TCPC_COMMAND_LOOK4CONNECTION 0x99 107 #define TCPC_COMMAND_RXONEMORE 0xAA 108 #define TCPC_COMMAND_I2C_IDLE 0xFF 109 #define TCPC_DEV_CAP_1 0x24 110 #define TCPC_DEV_CAP_2 0x26 111 #define TCPC_STD_INPUT_CAP 0x28 112 #define TCPC_STD_OUTPUT_CAP 0x29 113 #define TCPC_MSG_HDR_INFO 0x2e 114 #define TCPC_MSG_HDR_INFO_PWR_ROLE (1 << 0) 115 #define TCPC_MSG_HDR_INFO_PD_REV10 (0 << 1) 116 #define TCPC_MSG_HDR_INFO_PD_REV20 (1 << 1) 117 #define TCPC_MSG_HDR_INFO_DATA_ROLE (1 << 3) 118 #define TCPC_RX_DETECT 0x2f 119 #define TCPC_RX_DETECT_SOP (1 << 0) 120 #define TCPC_RX_DETECT_HARD_RESET (1 << 5) 121 #define TCPC_RX_BYTE_CNT 0x30 122 #define TCPC_RX_BUF_FRAME_TYPE 0x31 123 #define TCPC_RX_HDR 0x32 124 #define TCPC_RX_DATA 0x34 /* through 0x4f */ 125 #define TCPC_TRANSMIT 0x50 126 #define TCPC_TX_BYTE_CNT 0x51 127 #define TCPC_TX_HDR 0x52 128 #define TCPC_TX_DATA 0x54 /* through 0x6f */ 129 #define TCPC_VBUS_VOLTAGE 0x70 130 #define TCPC_VBUS_SINK_DISCONNECT_THRESH 0x72 131 #define TCPC_VBUS_STOP_DISCHARGE_THRESH 0x74 132 #define TCPC_VBUS_VOLTAGE_ALARM_HI_CFG 0x76 133 #define TCPC_VBUS_VOLTAGE_ALARM_LO_CFG 0x78 134 135 enum typec_cc_status { 136 TYPEC_CC_OPEN, 137 TYPEC_CC_RA, 138 TYPEC_CC_RD, 139 TYPEC_CC_RP_DEF, 140 TYPEC_CC_RP_1_5, 141 TYPEC_CC_RP_3_0, 142 }; 143 144 enum typec_data_role { 145 TYPEC_DEVICE, 146 TYPEC_HOST, 147 }; 148 149 enum typec_power_role { 150 TYPEC_SINK, 151 TYPEC_SOURCE, 152 }; 153 154 enum typec_polarity { 155 TYPEC_POLARITY_CC1, 156 TYPEC_POLARITY_CC2, 157 }; 158 159 struct tcpci_softc { 160 struct device sc_dev; 161 i2c_tag_t sc_tag; 162 i2c_addr_t sc_addr; 163 int sc_node; 164 void *sc_ih; 165 166 struct task sc_task; 167 168 int sc_attached; 169 enum typec_data_role sc_try_data; 170 enum typec_power_role sc_try_power; 171 172 uint32_t *sc_ss_sel; 173 uint8_t sc_cc; 174 uint8_t sc_vbus_det; 175 }; 176 177 int tcpci_match(struct device *, void *, void *); 178 void tcpci_attach(struct device *, struct device *, void *); 179 int tcpci_detach(struct device *, int); 180 181 int tcpci_intr(void *); 182 void tcpci_task(void *); 183 void tcpci_cc_change(struct tcpci_softc *); 184 void tcpci_power_change(struct tcpci_softc *); 185 void tcpci_set_polarity(struct tcpci_softc *, int); 186 void tcpci_set_vbus(struct tcpci_softc *, int, int); 187 void tcpci_set_roles(struct tcpci_softc *, enum typec_data_role, 188 enum typec_power_role); 189 190 void tcpci_write_reg16(struct tcpci_softc *, uint8_t, uint16_t); 191 uint16_t tcpci_read_reg16(struct tcpci_softc *, uint8_t); 192 void tcpci_write_reg8(struct tcpci_softc *, uint8_t, uint8_t); 193 uint8_t tcpci_read_reg8(struct tcpci_softc *, uint8_t); 194 195 struct cfattach tcpci_ca = { 196 sizeof(struct tcpci_softc), 197 tcpci_match, 198 tcpci_attach, 199 tcpci_detach, 200 }; 201 202 struct cfdriver tcpci_cd = { 203 NULL, "tcpci", DV_DULL 204 }; 205 206 int 207 tcpci_match(struct device *parent, void *match, void *aux) 208 { 209 struct i2c_attach_args *ia = aux; 210 211 if (strcmp(ia->ia_name, "nxp,ptn5110") == 0) 212 return 1; 213 214 return 0; 215 } 216 217 void 218 tcpci_attach(struct device *parent, struct device *self, void *aux) 219 { 220 struct tcpci_softc *sc = (struct tcpci_softc *)self; 221 struct i2c_attach_args *ia = aux; 222 int len; 223 224 sc->sc_tag = ia->ia_tag; 225 sc->sc_addr = ia->ia_addr; 226 sc->sc_node = *(int *)ia->ia_cookie; 227 228 /* Automatic DRP toggling should try first as ... */ 229 sc->sc_try_data = TYPEC_HOST; 230 sc->sc_try_power = TYPEC_SOURCE; 231 232 pinctrl_byname(sc->sc_node, "default"); 233 234 task_set(&sc->sc_task, tcpci_task, sc); 235 sc->sc_ih = arm_intr_establish_fdt(sc->sc_node, IPL_BIO, 236 tcpci_intr, sc, sc->sc_dev.dv_xname); 237 if (sc->sc_ih == NULL) { 238 printf(": unable to establish interrupt\n"); 239 return; 240 } 241 242 len = OF_getproplen(sc->sc_node, "ss-sel-gpios"); 243 if (len > 0) { 244 sc->sc_ss_sel = malloc(len, M_TEMP, M_WAITOK); 245 OF_getpropintarray(sc->sc_node, "ss-sel-gpios", 246 sc->sc_ss_sel, len); 247 gpio_controller_config_pin(sc->sc_ss_sel, 248 GPIO_CONFIG_OUTPUT); 249 gpio_controller_set_pin(sc->sc_ss_sel, 1); 250 } 251 252 tcpci_write_reg16(sc, TCPC_ALERT, 0xffff); 253 tcpci_write_reg8(sc, TCPC_FAULT_STATUS, 0x80); 254 tcpci_write_reg8(sc, TCPC_POWER_STATUS_MASK, 255 TCPC_POWER_STATUS_VBUS_PRES); 256 tcpci_write_reg8(sc, TCPC_POWER_CTRL, tcpci_read_reg8(sc, 257 TCPC_POWER_CTRL) & ~TCPC_POWER_CTRL_DIS_VOL_ALARM); 258 tcpci_write_reg16(sc, TCPC_ALERT_MASK, 259 TCPC_ALERT_TX_SUCCESS | TCPC_ALERT_TX_FAILED | 260 TCPC_ALERT_TX_DISCARDED | TCPC_ALERT_RX_STATUS | 261 TCPC_ALERT_RX_HARD_RST | TCPC_ALERT_CC_STATUS | 262 TCPC_ALERT_RX_BUF_OVF | TCPC_ALERT_FAULT | 263 TCPC_ALERT_V_ALARM_LO | TCPC_ALERT_POWER_STATUS); 264 265 if (sc->sc_try_data == TYPEC_HOST) 266 tcpci_write_reg8(sc, TCPC_ROLE_CTRL, TCPC_ROLE_CTRL_DRP | 0xa); 267 else 268 tcpci_write_reg8(sc, TCPC_ROLE_CTRL, TCPC_ROLE_CTRL_DRP | 0x5); 269 tcpci_write_reg8(sc, TCPC_COMMAND, TCPC_COMMAND_LOOK4CONNECTION); 270 271 printf("\n"); 272 } 273 274 int 275 tcpci_detach(struct device *self, int flags) 276 { 277 return 0; 278 } 279 280 int 281 tcpci_intr(void *args) 282 { 283 struct tcpci_softc *sc = args; 284 fdt_intr_disable(sc->sc_ih); 285 task_add(systq, &sc->sc_task); 286 return 1; 287 } 288 289 void 290 tcpci_task(void *args) 291 { 292 struct tcpci_softc *sc = args; 293 uint16_t status; 294 295 status = tcpci_read_reg16(sc, TCPC_ALERT); 296 tcpci_write_reg16(sc, TCPC_ALERT, status); 297 298 DPRINTF(("%s: alert %x\n", __func__, status)); 299 300 if (status & TCPC_ALERT_CC_STATUS) 301 tcpci_cc_change(sc); 302 303 if (status & TCPC_ALERT_POWER_STATUS) 304 tcpci_power_change(sc); 305 306 if (status & TCPC_ALERT_V_ALARM_LO) { 307 tcpci_write_reg8(sc, TCPC_VBUS_VOLTAGE_ALARM_LO_CFG, 0); 308 tcpci_write_reg8(sc, TCPC_POWER_CTRL, tcpci_read_reg8(sc, 309 TCPC_POWER_CTRL) & ~TCPC_POWER_CTRL_FORCEDISCH); 310 } 311 312 if (status & TCPC_ALERT_FAULT) 313 tcpci_write_reg8(sc, TCPC_FAULT_STATUS, tcpci_read_reg8(sc, 314 TCPC_FAULT_STATUS) | TCPC_FAULT_STATUS_CLEAR); 315 316 fdt_intr_enable(sc->sc_ih); 317 } 318 319 uint8_t 320 tcpci_typec_to_rp(int typec) 321 { 322 switch (typec) { 323 case TYPEC_CC_RP_DEF: 324 return TCPC_ROLE_CTRL_RP_VAL_DEF; 325 case TYPEC_CC_RP_1_5: 326 return TCPC_ROLE_CTRL_RP_VAL_1_5; 327 case TYPEC_CC_RP_3_0: 328 return TCPC_ROLE_CTRL_RP_VAL_3_0; 329 default: 330 panic("%s:%d", __func__, __LINE__); 331 } 332 } 333 334 int 335 tcpci_cc_to_typec(int cc, int sink) 336 { 337 if (sink) { 338 if (cc == 0x1) 339 return TYPEC_CC_RP_DEF; 340 if (cc == 0x2) 341 return TYPEC_CC_RP_1_5; 342 if (cc == 0x3) 343 return TYPEC_CC_RP_3_0; 344 } else { 345 if (cc == 0x1) 346 return TYPEC_CC_RA; 347 if (cc == 0x2) 348 return TYPEC_CC_RD; 349 } 350 351 return TYPEC_CC_OPEN; 352 } 353 354 int 355 tcpci_cc_is_sink(int cc1, int cc2) 356 { 357 if ((cc1 == TYPEC_CC_RP_DEF || cc1 == TYPEC_CC_RP_1_5 || 358 cc1 == TYPEC_CC_RP_3_0) && cc2 == TYPEC_CC_OPEN) 359 return 1; 360 if ((cc2 == TYPEC_CC_RP_DEF || cc2 == TYPEC_CC_RP_1_5 || 361 cc2 == TYPEC_CC_RP_3_0) && cc1 == TYPEC_CC_OPEN) 362 return 1; 363 return 0; 364 } 365 366 int 367 tcpci_cc_is_source(int cc1, int cc2) 368 { 369 if (cc1 == TYPEC_CC_RD && cc2 != TYPEC_CC_RD) 370 return 1; 371 if (cc2 == TYPEC_CC_RD && cc1 != TYPEC_CC_RD) 372 return 1; 373 return 0; 374 } 375 376 int 377 tcpci_cc_is_audio(int cc1, int cc2) 378 { 379 if (cc1 == TYPEC_CC_RA && cc2 == TYPEC_CC_RA) 380 return 1; 381 return 0; 382 } 383 384 int 385 tcpci_cc_is_audio_detached(int cc1, int cc2) 386 { 387 if (cc1 == TYPEC_CC_RA && cc2 == TYPEC_CC_OPEN) 388 return 1; 389 if (cc2 == TYPEC_CC_RA && cc1 == TYPEC_CC_OPEN) 390 return 1; 391 return 0; 392 } 393 394 void 395 tcpci_cc_change(struct tcpci_softc *sc) 396 { 397 uint8_t cc, cc1, cc2; 398 399 cc = tcpci_read_reg8(sc, TCPC_CC_STATUS); 400 if (sc->sc_cc == cc) 401 return; 402 403 cc1 = (cc >> TCPC_ROLE_CTRL_CC1_SHIFT) & TCPC_ROLE_CTRL_CC_MASK; 404 cc1 = tcpci_cc_to_typec(cc1, cc & TCPC_CC_STATUS_TERM); 405 cc2 = (cc >> TCPC_ROLE_CTRL_CC2_SHIFT) & TCPC_ROLE_CTRL_CC_MASK; 406 cc2 = tcpci_cc_to_typec(cc2, cc & TCPC_CC_STATUS_TERM); 407 408 if (cc1 == TYPEC_CC_OPEN && cc2 == TYPEC_CC_OPEN) { 409 /* No CC, wait for new connection. */ 410 DPRINTF(("%s: disconnected\n", __func__)); 411 tcpci_write_reg8(sc, TCPC_RX_DETECT, 0); 412 tcpci_set_vbus(sc, 0, 0); 413 tcpci_write_reg8(sc, TCPC_POWER_CTRL, tcpci_read_reg8(sc, 414 TCPC_POWER_CTRL) & ~TCPC_POWER_CTRL_VCONN_ENABLE); 415 tcpci_set_polarity(sc, TYPEC_POLARITY_CC1); 416 if (sc->sc_try_data == TYPEC_HOST) { 417 tcpci_write_reg8(sc, TCPC_ROLE_CTRL, 418 TCPC_ROLE_CTRL_DRP | 0xa); 419 } else { 420 tcpci_write_reg8(sc, TCPC_ROLE_CTRL, 421 TCPC_ROLE_CTRL_DRP | 0x5); 422 } 423 tcpci_write_reg8(sc, TCPC_COMMAND, 424 TCPC_COMMAND_LOOK4CONNECTION); 425 sc->sc_attached = 0; 426 } else if (tcpci_cc_is_source(cc1, cc2)) { 427 /* Host */ 428 DPRINTF(("%s: attached as source\n", __func__)); 429 if (cc1 == TYPEC_CC_RD) 430 tcpci_set_polarity(sc, TYPEC_POLARITY_CC1); 431 else 432 tcpci_set_polarity(sc, TYPEC_POLARITY_CC2); 433 tcpci_set_roles(sc, TYPEC_HOST, TYPEC_SOURCE); 434 tcpci_write_reg8(sc, TCPC_RX_DETECT, 435 TCPC_RX_DETECT_SOP | TCPC_RX_DETECT_HARD_RESET); 436 if ((cc1 == TYPEC_CC_RD && cc2 == TYPEC_CC_RA) || 437 (cc2 == TYPEC_CC_RD && cc1 == TYPEC_CC_RA)) 438 tcpci_write_reg8(sc, TCPC_POWER_CTRL, tcpci_read_reg8(sc, 439 TCPC_POWER_CTRL) | TCPC_POWER_CTRL_VCONN_ENABLE); 440 tcpci_set_vbus(sc, 1, 0); 441 sc->sc_attached = 1; 442 } else if (tcpci_cc_is_sink(cc1, cc2)) { 443 /* Device */ 444 DPRINTF(("%s: attached as sink\n", __func__)); 445 if (cc1 != TYPEC_CC_OPEN) { 446 tcpci_set_polarity(sc, TYPEC_POLARITY_CC1); 447 tcpci_write_reg8(sc, TCPC_ROLE_CTRL, 448 TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC1_SHIFT | 449 TCPC_ROLE_CTRL_CC_OPEN << TCPC_ROLE_CTRL_CC2_SHIFT); 450 } else { 451 tcpci_set_polarity(sc, TYPEC_POLARITY_CC2); 452 tcpci_write_reg8(sc, TCPC_ROLE_CTRL, 453 TCPC_ROLE_CTRL_CC_OPEN << TCPC_ROLE_CTRL_CC1_SHIFT | 454 TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC2_SHIFT); 455 } 456 tcpci_set_roles(sc, TYPEC_DEVICE, TYPEC_SINK); 457 tcpci_set_vbus(sc, 0, 0); 458 sc->sc_attached = 1; 459 } else if (tcpci_cc_is_audio_detached(cc1, cc2)) { 460 /* Audio Detached */ 461 DPRINTF(("%s: audio detached\n", __func__)); 462 } else { 463 panic("%s: unknown combination cc %x", __func__, cc); 464 } 465 466 sc->sc_cc = cc; 467 } 468 469 void 470 tcpci_power_change(struct tcpci_softc *sc) 471 { 472 uint8_t power; 473 474 if (tcpci_read_reg8(sc, TCPC_POWER_STATUS_MASK) == 0xff) 475 DPRINTF(("%s: power reset\n", __func__)); 476 477 power = tcpci_read_reg8(sc, TCPC_POWER_STATUS); 478 power &= TCPC_POWER_STATUS_VBUS_PRES; 479 if (sc->sc_vbus_det == power) 480 return; 481 482 DPRINTF(("%s: power %d\n", __func__, power)); 483 sc->sc_vbus_det = power; 484 } 485 486 void 487 tcpci_set_roles(struct tcpci_softc *sc, enum typec_data_role data, 488 enum typec_power_role power) 489 { 490 uint8_t reg; 491 492 reg = TCPC_MSG_HDR_INFO_PD_REV20; 493 if (power == TYPEC_SOURCE) 494 reg |= TCPC_MSG_HDR_INFO_PWR_ROLE; 495 if (data == TYPEC_HOST) 496 reg |= TCPC_MSG_HDR_INFO_DATA_ROLE; 497 498 tcpci_write_reg8(sc, TCPC_MSG_HDR_INFO, reg); 499 500 if (data == TYPEC_HOST) 501 printf("%s: connected in host mode\n", 502 sc->sc_dev.dv_xname); 503 else 504 printf("%s: connected in device mode\n", 505 sc->sc_dev.dv_xname); 506 } 507 508 void 509 tcpci_set_polarity(struct tcpci_softc *sc, int cc) 510 { 511 if (cc == TYPEC_POLARITY_CC1) { 512 tcpci_write_reg8(sc, TCPC_TCPC_CTRL, 0); 513 if (sc->sc_ss_sel) 514 gpio_controller_set_pin(sc->sc_ss_sel, 1); 515 } 516 if (cc == TYPEC_POLARITY_CC2) { 517 tcpci_write_reg8(sc, TCPC_TCPC_CTRL, 518 TCPC_TCPC_CTRL_ORIENTATION); 519 if (sc->sc_ss_sel) 520 gpio_controller_set_pin(sc->sc_ss_sel, 0); 521 } 522 } 523 524 void 525 tcpci_set_vbus(struct tcpci_softc *sc, int source, int sink) 526 { 527 if (!source) 528 tcpci_write_reg8(sc, TCPC_COMMAND, 529 TCPC_COMMAND_DISABLE_SRC_VBUS); 530 531 if (!sink) 532 tcpci_write_reg8(sc, TCPC_COMMAND, 533 TCPC_COMMAND_DISABLE_SINK_VBUS); 534 535 if (!source && !sink) { 536 tcpci_write_reg8(sc, TCPC_VBUS_VOLTAGE_ALARM_LO_CFG, 0x1c); 537 tcpci_write_reg8(sc, TCPC_POWER_CTRL, tcpci_read_reg8(sc, 538 TCPC_POWER_CTRL) | TCPC_POWER_CTRL_FORCEDISCH); 539 } 540 541 if (source) 542 tcpci_write_reg8(sc, TCPC_COMMAND, 543 TCPC_COMMAND_SRC_VBUS_DEFAULT); 544 545 if (sink) 546 tcpci_write_reg8(sc, TCPC_COMMAND, 547 TCPC_COMMAND_SINK_VBUS); 548 } 549 550 uint8_t 551 tcpci_read_reg8(struct tcpci_softc *sc, uint8_t reg) 552 { 553 uint8_t val = 0; 554 555 iic_acquire_bus(sc->sc_tag, 0); 556 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 557 sc->sc_addr, ®, sizeof(reg), &val, sizeof(val), 0)) { 558 printf("%s: cannot read register 0x%x\n", 559 sc->sc_dev.dv_xname, reg); 560 } 561 iic_release_bus(sc->sc_tag, 0); 562 563 return val; 564 } 565 566 void 567 tcpci_write_reg8(struct tcpci_softc *sc, uint8_t reg, uint8_t val) 568 { 569 iic_acquire_bus(sc->sc_tag, 0); 570 if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, 571 sc->sc_addr, ®, sizeof(reg), &val, sizeof(val), 0)) { 572 printf("%s: cannot write register 0x%x\n", 573 sc->sc_dev.dv_xname, reg); 574 } 575 iic_release_bus(sc->sc_tag, 0); 576 } 577 578 uint16_t 579 tcpci_read_reg16(struct tcpci_softc *sc, uint8_t reg) 580 { 581 uint16_t val = 0; 582 583 iic_acquire_bus(sc->sc_tag, 0); 584 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 585 sc->sc_addr, ®, sizeof(reg), &val, sizeof(val), 0)) { 586 printf("%s: cannot read register 0x%x\n", 587 sc->sc_dev.dv_xname, reg); 588 } 589 iic_release_bus(sc->sc_tag, 0); 590 591 return val; 592 } 593 594 void 595 tcpci_write_reg16(struct tcpci_softc *sc, uint8_t reg, uint16_t val) 596 { 597 iic_acquire_bus(sc->sc_tag, 0); 598 if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, 599 sc->sc_addr, ®, sizeof(reg), &val, sizeof(val), 0)) { 600 printf("%s: cannot write register 0x%x\n", 601 sc->sc_dev.dv_xname, reg); 602 } 603 iic_release_bus(sc->sc_tag, 0); 604 } 605