xref: /openbsd/sys/dev/fdt/tcpci.c (revision 905646f0)
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, &reg, 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, &reg, 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, &reg, 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, &reg, 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