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, ®, 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, ®, 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