xref: /openbsd/sys/dev/fdt/fusbtc.c (revision 9fdf0c62)
1 /* $OpenBSD: fusbtc.c,v 1.2 2021/10/24 17:52:26 mpi 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 const 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
fusbtc_match(struct device * parent,void * match,void * aux)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
fusbtc_attach(struct device * parent,struct device * self,void * aux)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
fusbtc_detach(struct device * self,int flags)342 fusbtc_detach(struct device *self, int flags)
343 {
344 	return 0;
345 }
346 
347 int
fusbtc_intr(void * args)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
fusbtc_task(void * args)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
fusbtc_toggle(struct fusbtc_softc * sc,int on)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
fusbtc_bclvl_to_typec(uint8_t bclvl)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
fusbtc_toggle_change(struct fusbtc_softc * sc)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
fusbtc_power_change(struct fusbtc_softc * sc)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
fusbtc_bclvl_change(void * args)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
fusbtc_comp_change(struct fusbtc_softc * sc)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
fusbtc_set_roles(struct fusbtc_softc * sc,enum typec_data_role data,enum typec_power_role power)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
fusbtc_set_cc_pull(struct fusbtc_softc * sc,int pol,int up,int down)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
fusbtc_set_polarity(struct fusbtc_softc * sc,int pol)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
fusbtc_set_vbus(struct fusbtc_softc * sc,int source,int sink)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
fusbtc_set_reg(struct fusbtc_softc * sc,uint8_t off,uint8_t val)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
fusbtc_clr_reg(struct fusbtc_softc * sc,uint8_t off,uint8_t val)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
fusbtc_read_reg(struct fusbtc_softc * sc,uint8_t reg)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, &reg, 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
fusbtc_write_reg(struct fusbtc_softc * sc,uint8_t reg,uint8_t val)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, &reg, 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