fusbtc.c revision 1.1.4.2 1 /* $NetBSD: fusbtc.c,v 1.1.4.2 2025/08/02 05:56:39 perseant 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.1.4.2 2025/08/02 05:56:39 perseant 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 = ia->ia_cookie;
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, ®, 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, ®, 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