Home | History | Annotate | Line # | Download | only in i2c
      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, &reg, 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, &reg, 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