1 /* $OpenBSD: tcpci.c,v 1.3 2022/04/06 18:59:28 naddy 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 const 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
tcpci_match(struct device * parent,void * match,void * aux)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
tcpci_attach(struct device * parent,struct device * self,void * aux)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 = fdt_intr_establish(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
tcpci_detach(struct device * self,int flags)275 tcpci_detach(struct device *self, int flags)
276 {
277 return 0;
278 }
279
280 int
tcpci_intr(void * args)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
tcpci_task(void * args)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
tcpci_typec_to_rp(int typec)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
tcpci_cc_to_typec(int cc,int sink)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
tcpci_cc_is_sink(int cc1,int cc2)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
tcpci_cc_is_source(int cc1,int cc2)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
tcpci_cc_is_audio(int cc1,int cc2)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
tcpci_cc_is_audio_detached(int cc1,int cc2)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
tcpci_cc_change(struct tcpci_softc * sc)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
tcpci_power_change(struct tcpci_softc * sc)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
tcpci_set_roles(struct tcpci_softc * sc,enum typec_data_role data,enum typec_power_role power)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
tcpci_set_polarity(struct tcpci_softc * sc,int cc)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
tcpci_set_vbus(struct tcpci_softc * sc,int source,int sink)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
tcpci_read_reg8(struct tcpci_softc * sc,uint8_t reg)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, ®, 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
tcpci_write_reg8(struct tcpci_softc * sc,uint8_t reg,uint8_t val)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, ®, 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
tcpci_read_reg16(struct tcpci_softc * sc,uint8_t reg)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, ®, 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
tcpci_write_reg16(struct tcpci_softc * sc,uint8_t reg,uint16_t val)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, ®, 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