1 /* $OpenBSD: fusbtc.c,v 1.1 2019/05/11 14:43:27 patrick Exp $ */ 2 /* 3 * Copyright (c) 2019 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/timeout.h> 25 #include <sys/task.h> 26 27 #include <machine/bus.h> 28 #include <machine/fdt.h> 29 30 #include <dev/i2c/i2cvar.h> 31 #include <dev/ofw/openfirm.h> 32 #include <dev/ofw/ofw_gpio.h> 33 #include <dev/ofw/ofw_misc.h> 34 #include <dev/ofw/ofw_pinctrl.h> 35 #include <dev/ofw/ofw_regulator.h> 36 37 /* #define FUSB_DEBUG */ 38 #define FUSB_DEBUG 39 40 #ifdef FUSB_DEBUG 41 #define DPRINTF(x) printf x 42 #else 43 #define DPRINTF(x) 44 #endif 45 46 #define FUSB_DEVICE_ID 0x01 47 #define FUSB_SWITCHES0 0x02 48 #define FUSB_SWITCHES0_PD_EN1 (1 << 0) 49 #define FUSB_SWITCHES0_PD_EN2 (1 << 1) 50 #define FUSB_SWITCHES0_MEAS_CC1 (1 << 2) 51 #define FUSB_SWITCHES0_MEAS_CC2 (1 << 3) 52 #define FUSB_SWITCHES0_VCONN_CC1 (1 << 4) 53 #define FUSB_SWITCHES0_VCONN_CC2 (1 << 5) 54 #define FUSB_SWITCHES0_PU_EN1 (1 << 6) 55 #define FUSB_SWITCHES0_PU_EN2 (1 << 7) 56 #define FUSB_SWITCHES1 0x03 57 #define FUSB_SWITCHES1_TXCC1 (1 << 0) 58 #define FUSB_SWITCHES1_TXCC2 (1 << 1) 59 #define FUSB_SWITCHES1_AUTO_CRC (1 << 2) 60 #define FUSB_SWITCHES1_DATAROLE (1 << 4) 61 #define FUSB_SWITCHES1_SPECREV0 (1 << 5) 62 #define FUSB_SWITCHES1_SPECREV1 (1 << 6) 63 #define FUSB_SWITCHES1_POWERROLE (1 << 7) 64 #define FUSB_MEASURE 0x04 65 #define FUSB_SLICE 0x05 66 #define FUSB_CONTROL0 0x06 67 #define FUSB_CONTROL0_HOST_CUR0 (1 << 2) 68 #define FUSB_CONTROL0_HOST_CUR1 (1 << 3) 69 #define FUSB_CONTROL0_INT_MASK (1 << 5) 70 #define FUSB_CONTROL1 0x07 71 #define FUSB_CONTROL2 0x08 72 #define FUSB_CONTROL2_TOGGLE (1 << 0) 73 #define FUSB_CONTROL2_MODE_NONE (0 << 1) 74 #define FUSB_CONTROL2_MODE_DRP (1 << 1) 75 #define FUSB_CONTROL2_MODE_SNK (2 << 1) 76 #define FUSB_CONTROL2_MODE_SRC (3 << 1) 77 #define FUSB_CONTROL2_MODE_MASK (0x3 << 1) 78 #define FUSB_CONTROL3 0x09 79 #define FUSB_CONTROL3_AUTO_RETRY (1 << 0) 80 #define FUSB_CONTROL3_N_RETRIES(x) (((x) & 0x3) << 1) 81 #define FUSB_MASK 0x0a 82 #define FUSB_MASK_BC_LVL (1 << 0) 83 #define FUSB_MASK_COLLISION (1 << 1) 84 #define FUSB_MASK_WAKE (1 << 2) 85 #define FUSB_MASK_ALERT (1 << 3) 86 #define FUSB_MASK_CRC_CHK (1 << 4) 87 #define FUSB_MASK_COMP_CHNG (1 << 5) 88 #define FUSB_MASK_ACTIVITY (1 << 6) 89 #define FUSB_MASK_VBUSOK (1 << 7) 90 #define FUSB_POWER 0x0b 91 #define FUSB_POWER_ALL (0x7 << 0) 92 #define FUSB_RESET 0x0c 93 #define FUSB_RESET_SW (1 << 0) 94 #define FUSB_RESET_PD (1 << 1) 95 #define FUSB_OCPREG 0x0d 96 #define FUSB_MASKA 0x0e 97 #define FUSB_MASKA_HARDRST (1 << 0) 98 #define FUSB_MASKA_SOFTRST (1 << 1) 99 #define FUSB_MASKA_TXSENT (1 << 2) 100 #define FUSB_MASKA_HARDSENT (1 << 3) 101 #define FUSB_MASKA_RETRYFAIL (1 << 4) 102 #define FUSB_MASKA_SOFTFAIL (1 << 5) 103 #define FUSB_MASKA_TOGDONE (1 << 6) 104 #define FUSB_MASKA_OCP_TEMP (1 << 7) 105 #define FUSB_MASKB 0x0f 106 #define FUSB_MASKB_GCRCSENT (1 << 0) 107 #define FUSB_CONTROL4 0x10 108 #define FUSB_STATUS0A 0x3c 109 #define FUSB_STATUS1A 0x3d 110 #define FUSB_STATUS1A_TOGSS_RUNNING (0x0 << 3) 111 #define FUSB_STATUS1A_TOGSS_CC1(x) (((x) & (0x1 << 3)) != 0) 112 #define FUSB_STATUS1A_TOGSS_CC2(x) (((x) & (0x1 << 3)) == 0) 113 #define FUSB_STATUS1A_TOGSS_SRC1 (0x1 << 3) 114 #define FUSB_STATUS1A_TOGSS_SRC2 (0x2 << 3) 115 #define FUSB_STATUS1A_TOGSS_SNK1 (0x5 << 3) 116 #define FUSB_STATUS1A_TOGSS_SNK2 (0x6 << 3) 117 #define FUSB_STATUS1A_TOGSS_AA (0x7 << 3) 118 #define FUSB_STATUS1A_TOGSS_MASK (0x7 << 3) 119 #define FUSB_INTERRUPTA 0x3e 120 #define FUSB_INTERRUPTA_HARDRST (1 << 0) 121 #define FUSB_INTERRUPTA_SOFTRST (1 << 1) 122 #define FUSB_INTERRUPTA_TXSENT (1 << 2) 123 #define FUSB_INTERRUPTA_HARDSENT (1 << 3) 124 #define FUSB_INTERRUPTA_RETRYFAIL (1 << 4) 125 #define FUSB_INTERRUPTA_SOFTFAIL (1 << 5) 126 #define FUSB_INTERRUPTA_TOGDONE (1 << 6) 127 #define FUSB_INTERRUPTA_OCP_TEMP (1 << 7) 128 #define FUSB_INTERRUPTB 0x3f 129 #define FUSB_INTERRUPTB_GCRCSENT (1 << 0) 130 #define FUSB_STATUS0 0x40 131 #define FUSB_STATUS0_BC_LVL_0_200 (0x0 << 0) 132 #define FUSB_STATUS0_BC_LVL_200_600 (0x1 << 0) 133 #define FUSB_STATUS0_BC_LVL_600_1230 (0x2 << 0) 134 #define FUSB_STATUS0_BC_LVL_1230_MAX (0x3 << 0) 135 #define FUSB_STATUS0_BC_LVL_MASK (0x3 << 0) 136 #define FUSB_STATUS0_COMP (1 << 5) 137 #define FUSB_STATUS0_ACTIVITY (1 << 6) 138 #define FUSB_STATUS0_VBUSOK (1 << 7) 139 #define FUSB_STATUS1 0x41 140 #define FUSB_INTERRUPT 0x42 141 #define FUSB_INTERRUPT_BC_LVL (1 << 0) 142 #define FUSB_INTERRUPT_COLLISION (1 << 1) 143 #define FUSB_INTERRUPT_WAKE (1 << 2) 144 #define FUSB_INTERRUPT_ALERT (1 << 3) 145 #define FUSB_INTERRUPT_CRC_CHK (1 << 4) 146 #define FUSB_INTERRUPT_COMP_CHNG (1 << 5) 147 #define FUSB_INTERRUPT_ACTIVITY (1 << 6) 148 #define FUSB_INTERRUPT_VBUSOK (1 << 7) 149 #define FUSB_FIFOS 0x43 150 151 enum typec_cc_status { 152 TYPEC_CC_OPEN, 153 TYPEC_CC_RA, 154 TYPEC_CC_RD, 155 TYPEC_CC_RP_DEF, 156 TYPEC_CC_RP_1_5, 157 TYPEC_CC_RP_3_0, 158 }; 159 160 enum typec_data_role { 161 TYPEC_DEVICE, 162 TYPEC_HOST, 163 }; 164 165 enum typec_power_role { 166 TYPEC_SINK, 167 TYPEC_SOURCE, 168 }; 169 170 enum typec_polarity { 171 TYPEC_POLARITY_CC1, 172 TYPEC_POLARITY_CC2, 173 }; 174 175 enum fusbtc_src_current_mode { 176 SRC_CURRENT_DEFAULT, 177 SRC_CURRENT_MEDIUM, 178 SRC_CURRENT_HIGH, 179 }; 180 181 uint8_t fusbtc_ra_mda[] = { 182 [SRC_CURRENT_DEFAULT] = 4, /* 210 mV */ 183 [SRC_CURRENT_MEDIUM] = 9, /* 420 mV */ 184 [SRC_CURRENT_HIGH] = 18, /* 798 mV */ 185 }; 186 187 uint8_t fusbtc_rd_mda[] = { 188 [SRC_CURRENT_DEFAULT] = 38, /* 1638 mV */ 189 [SRC_CURRENT_MEDIUM] = 38, /* 1638 mV */ 190 [SRC_CURRENT_HIGH] = 61, /* 2604 mV */ 191 }; 192 193 struct fusbtc_softc { 194 struct device sc_dev; 195 i2c_tag_t sc_tag; 196 i2c_addr_t sc_addr; 197 int sc_node; 198 void *sc_ih; 199 struct task sc_task; 200 201 int sc_attached; 202 uint8_t sc_drp_mode; 203 int sc_data_role; 204 int sc_power_role; 205 206 uint32_t *sc_ss_sel; 207 208 int sc_vbus; 209 uint8_t sc_vbus_det; 210 211 struct timeout sc_bclvl_tmo; 212 }; 213 214 int fusbtc_match(struct device *, void *, void *); 215 void fusbtc_attach(struct device *, struct device *, void *); 216 int fusbtc_detach(struct device *, int); 217 218 int fusbtc_intr(void *); 219 void fusbtc_task(void *); 220 void fusbtc_toggle(struct fusbtc_softc *, int); 221 void fusbtc_toggle_change(struct fusbtc_softc *); 222 void fusbtc_power_change(struct fusbtc_softc *); 223 void fusbtc_bclvl_change(void *args); 224 void fusbtc_comp_change(struct fusbtc_softc *); 225 void fusbtc_set_polarity(struct fusbtc_softc *, int); 226 void fusbtc_set_vbus(struct fusbtc_softc *, int, int); 227 void fusbtc_set_roles(struct fusbtc_softc *, enum typec_data_role, 228 enum typec_power_role); 229 void fusbtc_set_cc_pull(struct fusbtc_softc *, int, int, int); 230 231 void fusbtc_set_reg(struct fusbtc_softc *, uint8_t, uint8_t); 232 void fusbtc_clr_reg(struct fusbtc_softc *, uint8_t, uint8_t); 233 234 void fusbtc_write_reg(struct fusbtc_softc *, uint8_t, uint8_t); 235 uint8_t fusbtc_read_reg(struct fusbtc_softc *, uint8_t); 236 237 struct cfattach fusbtc_ca = { 238 sizeof(struct fusbtc_softc), 239 fusbtc_match, 240 fusbtc_attach, 241 fusbtc_detach, 242 }; 243 244 struct cfdriver fusbtc_cd = { 245 NULL, "fusbtc", DV_DULL 246 }; 247 248 int 249 fusbtc_match(struct device *parent, void *match, void *aux) 250 { 251 struct i2c_attach_args *ia = aux; 252 253 if (strcmp(ia->ia_name, "fcs,fusb302") == 0) 254 return 1; 255 256 return 0; 257 } 258 259 void 260 fusbtc_attach(struct device *parent, struct device *self, void *aux) 261 { 262 struct fusbtc_softc *sc = (struct fusbtc_softc *)self; 263 struct i2c_attach_args *ia = aux; 264 uint8_t reg; 265 char *role; 266 int child; 267 int len; 268 269 sc->sc_tag = ia->ia_tag; 270 sc->sc_addr = ia->ia_addr; 271 sc->sc_node = *(int *)ia->ia_cookie; 272 273 sc->sc_vbus = OF_getpropint(sc->sc_node, "vbus-supply", 0); 274 275 sc->sc_drp_mode = FUSB_CONTROL2_MODE_NONE; 276 for (child = OF_child(sc->sc_node); child != 0; child = OF_peer(child)){ 277 if (!OF_is_compatible(child, "usb-c-connector")) 278 continue; 279 len = OF_getproplen(child, "power-role"); 280 role = malloc(len, M_TEMP, M_WAITOK); 281 OF_getprop(child, "power-role", role, len); 282 if (!strcmp(role, "dual")) 283 sc->sc_drp_mode = FUSB_CONTROL2_MODE_DRP; 284 if (!strcmp(role, "sink")) 285 sc->sc_drp_mode = FUSB_CONTROL2_MODE_SNK; 286 if (!strcmp(role, "source")) 287 sc->sc_drp_mode = FUSB_CONTROL2_MODE_SRC; 288 free(role, M_TEMP, len); 289 } 290 /* For broken device trees without children. */ 291 if (sc->sc_drp_mode == FUSB_CONTROL2_MODE_NONE && 292 sc->sc_vbus) 293 sc->sc_drp_mode = FUSB_CONTROL2_MODE_SRC; 294 if (sc->sc_drp_mode == FUSB_CONTROL2_MODE_NONE) { 295 printf(": no USB-C connector defined\n"); 296 return; 297 } 298 299 timeout_set_proc(&sc->sc_bclvl_tmo, fusbtc_bclvl_change, sc); 300 301 pinctrl_byname(sc->sc_node, "default"); 302 303 task_set(&sc->sc_task, fusbtc_task, sc); 304 sc->sc_ih = fdt_intr_establish(sc->sc_node, IPL_BIO, 305 fusbtc_intr, sc, sc->sc_dev.dv_xname); 306 if (sc->sc_ih == NULL) { 307 printf(": unable to establish interrupt\n"); 308 return; 309 } 310 311 len = OF_getproplen(sc->sc_node, "ss-sel-gpios"); 312 if (len > 0) { 313 sc->sc_ss_sel = malloc(len, M_TEMP, M_WAITOK); 314 OF_getpropintarray(sc->sc_node, "ss-sel-gpios", 315 sc->sc_ss_sel, len); 316 gpio_controller_config_pin(sc->sc_ss_sel, 317 GPIO_CONFIG_OUTPUT); 318 gpio_controller_set_pin(sc->sc_ss_sel, 1); 319 } 320 321 fusbtc_write_reg(sc, FUSB_RESET, FUSB_RESET_SW); 322 reg = fusbtc_read_reg(sc, FUSB_CONTROL3); 323 reg |= FUSB_CONTROL3_AUTO_RETRY; 324 reg |= FUSB_CONTROL3_N_RETRIES(3); 325 fusbtc_write_reg(sc, FUSB_CONTROL3, reg); 326 fusbtc_write_reg(sc, FUSB_MASK, ~FUSB_MASK_VBUSOK); 327 fusbtc_write_reg(sc, FUSB_MASKA, ~FUSB_MASKA_TOGDONE); 328 fusbtc_write_reg(sc, FUSB_MASKB, 0xff); 329 reg = fusbtc_read_reg(sc, FUSB_CONTROL0); 330 reg &= ~FUSB_CONTROL0_INT_MASK; 331 fusbtc_write_reg(sc, FUSB_CONTROL0, reg); 332 fusbtc_write_reg(sc, FUSB_POWER, FUSB_POWER_ALL); 333 334 sc->sc_vbus_det = 335 fusbtc_read_reg(sc, FUSB_STATUS0) & FUSB_STATUS0_VBUSOK; 336 fusbtc_toggle(sc, 1); 337 338 printf("\n"); 339 } 340 341 int 342 fusbtc_detach(struct device *self, int flags) 343 { 344 return 0; 345 } 346 347 int 348 fusbtc_intr(void *args) 349 { 350 struct fusbtc_softc *sc = args; 351 fdt_intr_disable(sc->sc_ih); 352 task_add(systq, &sc->sc_task); 353 return 1; 354 } 355 356 void 357 fusbtc_task(void *args) 358 { 359 struct fusbtc_softc *sc = args; 360 uint8_t intr, intra, intrb; 361 362 intr = fusbtc_read_reg(sc, FUSB_INTERRUPT); 363 intra = fusbtc_read_reg(sc, FUSB_INTERRUPTA); 364 intrb = fusbtc_read_reg(sc, FUSB_INTERRUPTB); 365 366 if (intr & FUSB_INTERRUPT_VBUSOK) 367 fusbtc_power_change(sc); 368 369 if (intra & FUSB_INTERRUPTA_TOGDONE) 370 fusbtc_toggle_change(sc); 371 372 if (intr & FUSB_INTERRUPT_BC_LVL) 373 timeout_add_msec(&sc->sc_bclvl_tmo, 30); 374 375 if (intr & FUSB_INTERRUPT_COMP_CHNG) 376 fusbtc_comp_change(sc); 377 378 fdt_intr_enable(sc->sc_ih); 379 } 380 381 void 382 fusbtc_toggle(struct fusbtc_softc *sc, int on) 383 { 384 uint8_t reg; 385 386 fusbtc_clr_reg(sc, FUSB_CONTROL2, 387 FUSB_CONTROL2_MODE_MASK | FUSB_CONTROL2_TOGGLE); 388 fusbtc_set_reg(sc, FUSB_MASK, 389 FUSB_MASK_BC_LVL | FUSB_MASK_COMP_CHNG); 390 fusbtc_set_reg(sc, FUSB_MASKA, FUSB_MASKA_TOGDONE); 391 392 if (on) { 393 reg = fusbtc_read_reg(sc, FUSB_CONTROL0); 394 reg |= FUSB_CONTROL0_HOST_CUR0; 395 reg &= ~FUSB_CONTROL0_HOST_CUR1; 396 fusbtc_write_reg(sc, FUSB_CONTROL0, reg); 397 reg = fusbtc_read_reg(sc, FUSB_SWITCHES0); 398 reg &= ~(FUSB_SWITCHES0_VCONN_CC1 | FUSB_SWITCHES0_VCONN_CC2); 399 fusbtc_write_reg(sc, FUSB_SWITCHES0, reg); 400 401 fusbtc_clr_reg(sc, FUSB_MASKA, FUSB_MASKA_TOGDONE); 402 fusbtc_set_reg(sc, FUSB_CONTROL2, 403 sc->sc_drp_mode | FUSB_CONTROL2_TOGGLE); 404 } 405 } 406 407 int 408 fusbtc_bclvl_to_typec(uint8_t bclvl) 409 { 410 if (bclvl == FUSB_STATUS0_BC_LVL_200_600) 411 return TYPEC_CC_RP_DEF; 412 if (bclvl == FUSB_STATUS0_BC_LVL_600_1230) 413 return TYPEC_CC_RP_1_5; 414 if (bclvl == FUSB_STATUS0_BC_LVL_1230_MAX) 415 return TYPEC_CC_RP_3_0; 416 return TYPEC_CC_OPEN; 417 } 418 419 void 420 fusbtc_toggle_change(struct fusbtc_softc *sc) 421 { 422 uint8_t cc, reg; 423 uint8_t status; 424 int pol; 425 426 status = fusbtc_read_reg(sc, FUSB_STATUS1A); 427 status &= FUSB_STATUS1A_TOGSS_MASK; 428 429 if (FUSB_STATUS1A_TOGSS_CC1(status)) 430 pol = TYPEC_POLARITY_CC1; 431 else 432 pol = TYPEC_POLARITY_CC2; 433 434 if (status == FUSB_STATUS1A_TOGSS_SRC1 || 435 status == FUSB_STATUS1A_TOGSS_SRC2) { 436 /* Host */ 437 DPRINTF(("%s: attached (source)\n", sc->sc_dev.dv_xname)); 438 fusbtc_set_cc_pull(sc, pol, 1, 0); 439 fusbtc_set_polarity(sc, pol); 440 fusbtc_write_reg(sc, FUSB_MEASURE, 441 fusbtc_rd_mda[SRC_CURRENT_DEFAULT]); 442 delay(100); 443 reg = fusbtc_read_reg(sc, FUSB_STATUS0); 444 cc = TYPEC_CC_OPEN; 445 if ((reg & FUSB_STATUS0_COMP) == 0) { 446 fusbtc_write_reg(sc, FUSB_MEASURE, 447 fusbtc_ra_mda[SRC_CURRENT_DEFAULT]); 448 delay(100); 449 reg = fusbtc_read_reg(sc, FUSB_STATUS0); 450 cc = TYPEC_CC_RD; 451 if ((reg & FUSB_STATUS0_COMP) == 0) 452 cc = TYPEC_CC_RA; 453 } 454 if (cc == TYPEC_CC_OPEN) { 455 fusbtc_toggle(sc, 1); 456 return; 457 } 458 fusbtc_toggle(sc, 0); 459 fusbtc_write_reg(sc, FUSB_MEASURE, 460 fusbtc_rd_mda[SRC_CURRENT_DEFAULT]); 461 fusbtc_clr_reg(sc, FUSB_MASK, FUSB_MASK_COMP_CHNG); 462 fusbtc_set_roles(sc, TYPEC_HOST, TYPEC_SOURCE); 463 fusbtc_set_vbus(sc, 1, 0); 464 sc->sc_attached = 1; 465 } else if (status == FUSB_STATUS1A_TOGSS_SNK1 || 466 status == FUSB_STATUS1A_TOGSS_SNK2) { 467 /* Device */ 468 DPRINTF(("%s: attached (sink)\n", sc->sc_dev.dv_xname)); 469 fusbtc_set_cc_pull(sc, pol, 0, 1); 470 fusbtc_set_polarity(sc, pol); 471 reg = fusbtc_read_reg(sc, FUSB_STATUS0); 472 reg &= FUSB_STATUS0_BC_LVL_MASK; 473 if (fusbtc_bclvl_to_typec(reg) == TYPEC_CC_OPEN) { 474 fusbtc_toggle(sc, 1); 475 return; 476 } 477 fusbtc_toggle(sc, 0); 478 fusbtc_clr_reg(sc, FUSB_MASK, FUSB_MASK_BC_LVL); 479 fusbtc_set_roles(sc, TYPEC_DEVICE, TYPEC_SINK); 480 fusbtc_set_vbus(sc, 0, 0); 481 sc->sc_attached = 1; 482 } else { 483 panic("%s: unknown combination %x", sc->sc_dev.dv_xname, 484 status); 485 } 486 } 487 488 void 489 fusbtc_power_change(struct fusbtc_softc *sc) 490 { 491 uint8_t power; 492 493 power = fusbtc_read_reg(sc, FUSB_STATUS0); 494 power &= FUSB_STATUS0_VBUSOK; 495 if (sc->sc_vbus_det == power) 496 return; 497 498 sc->sc_vbus_det = power; 499 500 if (!sc->sc_vbus_det) { 501 DPRINTF(("%s: detached (vbus)\n", sc->sc_dev.dv_xname)); 502 sc->sc_attached = 0; 503 fusbtc_toggle(sc, 1); 504 } 505 } 506 507 void 508 fusbtc_bclvl_change(void *args) 509 { 510 struct fusbtc_softc *sc = args; 511 uint8_t bc; 512 513 if (!sc->sc_attached || sc->sc_power_role == TYPEC_SOURCE) 514 return; 515 516 bc = fusbtc_read_reg(sc, FUSB_STATUS0); 517 if (bc & FUSB_STATUS0_ACTIVITY) { 518 timeout_add_msec(&sc->sc_bclvl_tmo, 30); 519 return; 520 } 521 522 bc &= FUSB_STATUS0_BC_LVL_MASK; 523 bc = fusbtc_bclvl_to_typec(bc); 524 525 switch (bc) { 526 case TYPEC_CC_OPEN: 527 printf("%s: can draw 0 mA\n", sc->sc_dev.dv_xname); 528 break; 529 case TYPEC_CC_RP_DEF: 530 printf("%s: can draw 500 mA\n", sc->sc_dev.dv_xname); 531 break; 532 case TYPEC_CC_RP_1_5: 533 printf("%s: can draw 1500 mA\n", sc->sc_dev.dv_xname); 534 break; 535 case TYPEC_CC_RP_3_0: 536 printf("%s: can draw 3000 mA\n", sc->sc_dev.dv_xname); 537 break; 538 } 539 } 540 541 void 542 fusbtc_comp_change(struct fusbtc_softc *sc) 543 { 544 uint8_t reg; 545 546 if (!sc->sc_attached || sc->sc_power_role == TYPEC_SINK) 547 return; 548 549 reg = fusbtc_read_reg(sc, FUSB_STATUS0); 550 if ((reg & FUSB_STATUS0_COMP) == 0) 551 return; 552 553 DPRINTF(("%s: detached (comp)\n", sc->sc_dev.dv_xname)); 554 fusbtc_set_vbus(sc, 0, 0); 555 sc->sc_attached = 0; 556 fusbtc_toggle(sc, 1); 557 } 558 559 void 560 fusbtc_set_roles(struct fusbtc_softc *sc, enum typec_data_role data, 561 enum typec_power_role power) 562 { 563 uint8_t reg; 564 565 reg = fusbtc_read_reg(sc, FUSB_SWITCHES1); 566 reg &= ~(FUSB_SWITCHES1_POWERROLE | FUSB_SWITCHES1_DATAROLE); 567 if (power == TYPEC_SOURCE) 568 reg |= FUSB_SWITCHES1_POWERROLE; 569 if (data == TYPEC_HOST) 570 reg |= FUSB_SWITCHES1_DATAROLE; 571 fusbtc_write_reg(sc, FUSB_SWITCHES1, reg); 572 573 if (data == TYPEC_HOST) 574 printf("%s: connected in host mode\n", 575 sc->sc_dev.dv_xname); 576 else 577 printf("%s: connected in device mode\n", 578 sc->sc_dev.dv_xname); 579 580 sc->sc_data_role = data; 581 sc->sc_power_role = power; 582 } 583 584 void 585 fusbtc_set_cc_pull(struct fusbtc_softc *sc, int pol, int up, int down) 586 { 587 uint8_t reg; 588 589 reg = fusbtc_read_reg(sc, FUSB_SWITCHES0); 590 reg &= ~(FUSB_SWITCHES0_PU_EN1 | FUSB_SWITCHES0_PU_EN2); 591 reg &= ~(FUSB_SWITCHES0_PD_EN1 | FUSB_SWITCHES0_PD_EN2); 592 if (up) { /* host mode */ 593 if (pol == TYPEC_POLARITY_CC1) 594 reg |= FUSB_SWITCHES0_PU_EN1; 595 else 596 reg |= FUSB_SWITCHES0_PU_EN2; 597 } 598 if (down) { /* device mode */ 599 if (pol == TYPEC_POLARITY_CC1) 600 reg |= FUSB_SWITCHES0_PD_EN1; 601 else 602 reg |= FUSB_SWITCHES0_PD_EN2; 603 } 604 fusbtc_write_reg(sc, FUSB_SWITCHES0, reg); 605 } 606 607 void 608 fusbtc_set_polarity(struct fusbtc_softc *sc, int pol) 609 { 610 uint8_t reg; 611 612 reg = fusbtc_read_reg(sc, FUSB_SWITCHES0); 613 reg &= ~(FUSB_SWITCHES0_MEAS_CC1 | FUSB_SWITCHES0_MEAS_CC2); 614 reg &= ~(FUSB_SWITCHES0_VCONN_CC1 | FUSB_SWITCHES0_VCONN_CC2); 615 if (pol == TYPEC_POLARITY_CC1) 616 reg |= FUSB_SWITCHES0_MEAS_CC1; 617 else 618 reg |= FUSB_SWITCHES0_MEAS_CC2; 619 fusbtc_write_reg(sc, FUSB_SWITCHES0, reg); 620 621 reg = fusbtc_read_reg(sc, FUSB_SWITCHES1); 622 reg &= ~(FUSB_SWITCHES1_TXCC1 | FUSB_SWITCHES1_TXCC2); 623 if (pol == TYPEC_POLARITY_CC1) 624 reg |= FUSB_SWITCHES1_TXCC1; 625 else 626 reg |= FUSB_SWITCHES1_TXCC2; 627 fusbtc_write_reg(sc, FUSB_SWITCHES1, reg); 628 629 if (sc->sc_ss_sel) { 630 if (pol == TYPEC_POLARITY_CC1) 631 gpio_controller_set_pin(sc->sc_ss_sel, 1); 632 else 633 gpio_controller_set_pin(sc->sc_ss_sel, 0); 634 } 635 } 636 637 void 638 fusbtc_set_vbus(struct fusbtc_softc *sc, int source, int sink) 639 { 640 if (source) 641 regulator_enable(sc->sc_vbus); 642 else 643 regulator_disable(sc->sc_vbus); 644 } 645 646 void 647 fusbtc_set_reg(struct fusbtc_softc *sc, uint8_t off, uint8_t val) 648 { 649 uint8_t reg; 650 reg = fusbtc_read_reg(sc, off); 651 reg |= val; 652 fusbtc_write_reg(sc, off, reg); 653 } 654 655 void 656 fusbtc_clr_reg(struct fusbtc_softc *sc, uint8_t off, uint8_t val) 657 { 658 uint8_t reg; 659 reg = fusbtc_read_reg(sc, off); 660 reg &= ~val; 661 fusbtc_write_reg(sc, off, reg); 662 } 663 664 uint8_t 665 fusbtc_read_reg(struct fusbtc_softc *sc, uint8_t reg) 666 { 667 uint8_t val = 0; 668 669 iic_acquire_bus(sc->sc_tag, 0); 670 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 671 sc->sc_addr, ®, sizeof(reg), &val, sizeof(val), 0)) { 672 printf("%s: cannot read register 0x%x\n", 673 sc->sc_dev.dv_xname, reg); 674 } 675 iic_release_bus(sc->sc_tag, 0); 676 677 return val; 678 } 679 680 void 681 fusbtc_write_reg(struct fusbtc_softc *sc, uint8_t reg, uint8_t val) 682 { 683 iic_acquire_bus(sc->sc_tag, 0); 684 if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, 685 sc->sc_addr, ®, sizeof(reg), &val, sizeof(val), 0)) { 686 printf("%s: cannot write register 0x%x\n", 687 sc->sc_dev.dv_xname, reg); 688 } 689 iic_release_bus(sc->sc_tag, 0); 690 } 691