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