1 /*
2 * Copyright (c) 2024 Nuvoton Technology Corporation.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT nuvoton_numaker_tcpc
8
9 #include <zephyr/kernel.h>
10 #include <zephyr/drivers/usb_c/usbc_tcpc.h>
11 #include <zephyr/drivers/usb_c/usbc_ppc.h>
12 #include <zephyr/drivers/clock_control.h>
13 #include <zephyr/drivers/clock_control/clock_control_numaker.h>
14 #include <zephyr/drivers/reset.h>
15 #include <zephyr/drivers/pinctrl.h>
16 #include <zephyr/drivers/gpio.h>
17 #include <zephyr/drivers/adc.h>
18 #include <zephyr/sys/byteorder.h>
19
20 #include <zephyr/logging/log.h>
21 LOG_MODULE_REGISTER(tcpc_numaker, CONFIG_USBC_LOG_LEVEL);
22
23 #include <soc.h>
24 #include <NuMicro.h>
25
26 #include "ucpd_numaker.h"
27
28 /* Implementation notes on NuMaker TCPC/PPC/VBUS
29 *
30 * 1. UTCPD, interfacing to external circuit on VBUS/VCONN voltage measurement,
31 * VBUS/VCONN overcurrent protection, VBUS overvoltage protection, etc.,
32 * can implement all functions defined in TCPC, PPC, and VBUS. For this,
33 * TCPC is implemented in UTCPD majorly; PPC and VBUS rely on TCPC for
34 * their implementation.
35 * 2. For VBUS/VCONN voltage measurement, UTCPD is updated periodically
36 * by Timer-trigger EADC. To implement this interconnection, TCPC node_id
37 * will cover UTCPD, EADC, and Timer H/W characteristics of registers,
38 * interrupts, resets, and clocks.
39 * NOTE: EADC and Timer interrupts needn't enable for Timer-triggered EADC.
40 * In BSP sample, they are enabled just for development/debug purpose.
41 * 3. About VCONN per PCB
42 * (1) Support only VCONN source, no VCONN sink (like Plug Cable)
43 * (2) Separate pins for VCONN enable on CC1/CC2 (VCNEN1/VCNEN2)
44 * (3) Single pin for VCONN discharge (DISCHG)
45 * 4. VBUS discharge precedence
46 * (1) GPIO
47 * (2) UTCPD
48 * 5. VCONN discharge precedence
49 * (1) DPM-supplied callback
50 * (2) GPIO
51 * (3) UTCPD
52 */
53
54 /**
55 * @brief Invalid or missing value
56 */
57 #define NUMAKER_INVALID_VALUE UINT32_MAX
58
59 /**
60 * @brief UTCPD VBUS threshold default in mV
61 *
62 * These are default values of UTCPD VBUS threshold registers. They need
63 * to be reconfigured by taking the following factors into consideration:
64 * 1. Analog Vref
65 * 2. UTCPD VBVOL.VBSCALE
66 */
67 #define NUMAKER_UTCPD_VBUS_THRESHOLD_OVERVOLTAGE_MV 25000
68 #define NUMAKER_UTCPD_VBUS_THRESHOLD_VSAFE5V_MV 5000
69 #define NUMAKER_UTCPD_VBUS_THRESHOLD_VSAFE0V_MV 0
70 #define NUMAKER_UTCPD_VBUS_THRESHOLD_STOP_FORCE_DISCHARGE_MV 800
71 #define NUMAKER_UTCPD_VBUS_THRESHOLD_SINK_DISCONNECT_MV 3500
72
73 /**
74 * @brief SYS register dump
75 */
76 #define NUMAKER_SYS_REG_DUMP(dev, reg_name) LOG_INF("SYS: %8s: 0x%08x", #reg_name, SYS->reg_name);
77
78 /**
79 * @brief GPIO register dump
80 */
81 #define NUMAKER_GPIO_REG_DUMP(dev, port, reg_name) \
82 LOG_INF("%s: %8s: 0x%08x", #port, #reg_name, port->reg_name);
83
84 /**
85 * @brief UTCPD register write timeout in microseconds
86 */
87 #define NUMAKER_UTCPD_REG_WRITE_BY_NAME_TIMEOUT_US 20000
88
89 /**
90 * @brief UTCPD register write by name
91 */
92 #define NUMAKER_UTCPD_REG_WRITE_BY_NAME(dev, reg_name, val) \
93 ({ \
94 int rc_intern = numaker_utcpd_reg_write_wait_ready(dev); \
95 if (rc_intern < 0) { \
96 LOG_ERR("UTCPD register (%s) write timeout", #reg_name); \
97 } else { \
98 utcpd_base->reg_name = (val); \
99 } \
100 rc_intern; \
101 })
102
103 /**
104 * @brief UTCPD register force write by name
105 */
106 #define NUMAKER_UTCPD_REG_FORCE_WRITE_BY_NAME(dev, reg_name, val) \
107 ({ \
108 int rc_intern = numaker_utcpd_reg_write_wait_ready(dev); \
109 if (rc_intern < 0) { \
110 LOG_ERR("UTCPD register (%s) write timeout, force-write", #reg_name); \
111 } \
112 utcpd_base->reg_name = (val); \
113 rc_intern; \
114 })
115
116 /**
117 * @brief UTCPD register write by offset
118 */
119 #define NUMAKER_UTCPD_REG_WRITE_BY_OFFSET(dev, reg_offset, val) \
120 ({ \
121 int rc_intern = numaker_utcpd_reg_write_wait_ready(dev); \
122 if (rc_intern < 0) { \
123 LOG_ERR("UTCPD register (0x%04x) write timeout", reg_offset); \
124 } else { \
125 sys_write32((val), ((uintptr_t)utcpd_base) + reg_offset); \
126 } \
127 rc_intern; \
128 })
129
130 /**
131 * @brief UTCPD register force write by offset
132 */
133 #define NUMAKER_UTCPD_REG_FORCE_WRITE_BY_OFFSET(dev, reg_offset, val) \
134 ({ \
135 int rc_intern = numaker_utcpd_reg_write_wait_ready(dev); \
136 if (rc_intern < 0) { \
137 LOG_ERR("UTCPD register (0x%04x) write timeout, force-write", reg_offset); \
138 } \
139 sys_write32((val), ((uintptr_t)utcpd_base) + reg_offset); \
140 rc_intern; \
141 })
142
143 /**
144 * @brief UTCPD register read by name
145 */
146 #define NUMAKER_UTCPD_REG_READ_BY_NAME(dev, reg_name) ({ utcpd_base->reg_name; })
147
148 /**
149 * @brief UTCPD register read by offset
150 */
151 #define NUMAKER_UTCPD_REG_READ_BY_OFFSET(dev, reg_offset) \
152 ({ sys_read32(((uintptr_t)utcpd_base) + reg_offset); })
153
154 /**
155 * @brief UTCPD register dump
156 */
157 #define NUMAKER_UTCPD_REG_DUMP(dev, reg_name) \
158 LOG_INF("UTCPD: %8s: 0x%08x", #reg_name, NUMAKER_UTCPD_REG_READ_BY_NAME(dev, reg_name));
159
160 /**
161 * @brief Helper to write UTCPD VBUS threshold
162 */
163 #define NUMAKER_UTCPD_VBUS_THRESHOLD_WRITE(dev, reg_name, mv_norm) \
164 ({ \
165 uint32_t mv_bit; \
166 mv_bit = numaker_utcpd_vbus_volt_mv2bit(dev, mv_norm); \
167 mv_bit <<= UTCPD_##reg_name##_##reg_name##_Pos; \
168 mv_bit &= UTCPD_##reg_name##_##reg_name##_Msk; \
169 NUMAKER_UTCPD_REG_WRITE_BY_NAME(dev, reg_name, mv_bit); \
170 })
171
172 /**
173 * @brief Helper to read UTCPD VBUS threshold
174 */
175 #define NUMAKER_UTCPD_VBUS_THRESHOLD_READ(dev, reg_name) \
176 ({ \
177 uint32_t mv_bit; \
178 mv_bit = NUMAKER_UTCPD_REG_READ_BY_NAME(dev, reg_name); \
179 mv_bit &= UTCPD_##reg_name##_##reg_name##_Msk; \
180 mv_bit >>= UTCPD_##reg_name##_##reg_name##_Pos; \
181 numaker_utcpd_vbus_volt_bit2mv(dev, mv_bit); \
182 })
183
184 /**
185 * @brief Immutable device context
186 */
187 struct numaker_tcpc_config {
188 UTCPD_T *utcpd_base;
189 EADC_T *eadc_base;
190 TIMER_T *timer_base;
191 const struct device *clkctrl_dev;
192 struct numaker_scc_subsys pcc_utcpd;
193 struct numaker_scc_subsys pcc_timer;
194 struct reset_dt_spec reset_utcpd;
195 struct reset_dt_spec reset_timer;
196 void (*irq_config_func_utcpd)(const struct device *dev);
197 void (*irq_unconfig_func_utcpd)(const struct device *dev);
198 const struct pinctrl_dev_config *pincfg;
199 struct {
200 struct {
201 struct gpio_dt_spec vbus_detect;
202 struct gpio_dt_spec vbus_discharge;
203 struct gpio_dt_spec vconn_discharge;
204 } gpios;
205
206 bool dead_battery;
207 struct {
208 uint32_t bit;
209 } pinpl;
210 struct {
211 struct {
212 uint32_t bit;
213 uint32_t value;
214 } vbscale;
215 } vbvol;
216 } utcpd;
217 struct {
218 const struct adc_dt_spec *spec_vbus;
219 const struct adc_dt_spec *spec_vconn;
220 /* Rate of timer-triggered voltage measurement (Hz) */
221 uint32_t timer_trigger_rate;
222 /* Trigger source for measuring VBUS/VCONN voltage */
223 uint32_t trgsel_vbus;
224 uint32_t trgsel_vconn;
225 } eadc;
226 };
227
228 /**
229 * @brief Mutable device context
230 */
231 struct numaker_tcpc_data {
232 enum tc_rp_value rp;
233 bool rx_sop_prime_enabled;
234
235 /* One-slot Rx FIFO */
236 bool rx_msg_ready;
237 struct pd_msg rx_msg;
238
239 /* The fields below must persist across tcpc_init(). */
240
241 uint32_t vref_mv;
242
243 /* TCPC alert */
244 struct {
245 tcpc_alert_handler_cb_t handler;
246 void *data;
247 } tcpc_alert;
248
249 /* PPC event */
250 struct {
251 usbc_ppc_event_cb_t handler;
252 void *data;
253 } ppc_event;
254
255 /* DPM supplied */
256 struct {
257 /* VCONN callback function */
258 tcpc_vconn_control_cb_t vconn_cb;
259 /* VCONN discharge callback function */
260 tcpc_vconn_discharge_cb_t vconn_discharge_cb;
261 } dpm;
262 };
263
264 /**
265 * @brief Wait ready for next write access to UTCPD register
266 *
267 * @retval 0 on success
268 * @retval -EIO on failure
269 */
numaker_utcpd_reg_write_wait_ready(const struct device * dev)270 static int numaker_utcpd_reg_write_wait_ready(const struct device *dev)
271 {
272 const struct numaker_tcpc_config *const config = dev->config;
273 UTCPD_T *utcpd_base = config->utcpd_base;
274
275 if (!WAIT_FOR((utcpd_base->CLKINFO & UTCPD_CLKINFO_ReadyFlag_Msk),
276 NUMAKER_UTCPD_REG_WRITE_BY_NAME_TIMEOUT_US, NULL)) {
277 return -EIO;
278 }
279
280 return 0;
281 }
282
283 /**
284 * @brief Convert VBUS voltage format from H/W bit to mV
285 *
286 * The following factors are taken into consideration:
287 * 1. Analog Vref
288 * 2. UTCPD VBVOL.VBSCALE
289 *
290 * @note UTCPD VBVOL.VBVOL = MSB 10-bit of EADC DAT.RESULT[11:0],
291 * that is, discarding LSB 2-bit.
292 */
numaker_utcpd_vbus_volt_bit2mv(const struct device * dev,uint32_t bit)293 static uint32_t numaker_utcpd_vbus_volt_bit2mv(const struct device *dev, uint32_t bit)
294 {
295 const struct numaker_tcpc_config *const config = dev->config;
296 struct numaker_tcpc_data *data = dev->data;
297
298 __ASSERT_NO_MSG(data->vref_mv);
299 return (uint32_t)(((uint64_t)bit) * data->vref_mv * config->utcpd.vbvol.vbscale.value /
300 BIT_MASK(10));
301 }
302
303 /**
304 * @brief Convert VBUS voltage format from mV to H/W bit
305 *
306 * The following factors are taken into consideration:
307 * 1. Analog Vref
308 * 2. UTCPD VBVOL.VBSCALE
309 *
310 * @note UTCPD VBVOL.VBVOL = MSB 10-bit of EADC DAT.RESULT[11:0],
311 * that is, discarding LSB 2-bit.
312 */
numaker_utcpd_vbus_volt_mv2bit(const struct device * dev,uint32_t mv)313 static uint32_t numaker_utcpd_vbus_volt_mv2bit(const struct device *dev, uint32_t mv)
314 {
315 const struct numaker_tcpc_config *const config = dev->config;
316 struct numaker_tcpc_data *data = dev->data;
317
318 __ASSERT_NO_MSG(data->vref_mv);
319 return mv * BIT_MASK(10) / data->vref_mv / config->utcpd.vbvol.vbscale.value;
320 }
321
322 /**
323 * @brief UTCPD register dump
324 *
325 * @retval 0 on success
326 */
numaker_utcpd_dump_regs(const struct device * dev)327 static int numaker_utcpd_dump_regs(const struct device *dev)
328 {
329 const struct numaker_tcpc_config *const config = dev->config;
330 UTCPD_T *utcpd_base = config->utcpd_base;
331
332 /* SYS register */
333 NUMAKER_SYS_REG_DUMP(dev, VREFCTL);
334 NUMAKER_SYS_REG_DUMP(dev, UTCPDCTL);
335
336 /* UTCPD register */
337 NUMAKER_UTCPD_REG_DUMP(dev, IS);
338 NUMAKER_UTCPD_REG_DUMP(dev, IE);
339 NUMAKER_UTCPD_REG_DUMP(dev, PWRSTSIE);
340 NUMAKER_UTCPD_REG_DUMP(dev, FUTSTSIE);
341 NUMAKER_UTCPD_REG_DUMP(dev, CTL);
342 NUMAKER_UTCPD_REG_DUMP(dev, PINPL);
343 NUMAKER_UTCPD_REG_DUMP(dev, ROLCTL);
344 NUMAKER_UTCPD_REG_DUMP(dev, FUTCTL);
345 NUMAKER_UTCPD_REG_DUMP(dev, PWRCTL);
346 NUMAKER_UTCPD_REG_DUMP(dev, CCSTS);
347 NUMAKER_UTCPD_REG_DUMP(dev, PWRSTS);
348 NUMAKER_UTCPD_REG_DUMP(dev, FUTSTS);
349 NUMAKER_UTCPD_REG_DUMP(dev, DVCAP1);
350 NUMAKER_UTCPD_REG_DUMP(dev, DVCAP2);
351 NUMAKER_UTCPD_REG_DUMP(dev, MSHEAD);
352 NUMAKER_UTCPD_REG_DUMP(dev, DTRXEVNT);
353 NUMAKER_UTCPD_REG_DUMP(dev, VBVOL);
354 NUMAKER_UTCPD_REG_DUMP(dev, SKVBDCTH);
355 NUMAKER_UTCPD_REG_DUMP(dev, SPDGTH);
356 NUMAKER_UTCPD_REG_DUMP(dev, VBAMH);
357 NUMAKER_UTCPD_REG_DUMP(dev, VBAML);
358 NUMAKER_UTCPD_REG_DUMP(dev, VNDIS);
359 NUMAKER_UTCPD_REG_DUMP(dev, VNDIE);
360 NUMAKER_UTCPD_REG_DUMP(dev, MUXSEL);
361 NUMAKER_UTCPD_REG_DUMP(dev, VCDGCTL);
362 NUMAKER_UTCPD_REG_DUMP(dev, ADGTM);
363 NUMAKER_UTCPD_REG_DUMP(dev, VSAFE0V);
364 NUMAKER_UTCPD_REG_DUMP(dev, VSAFE5V);
365 NUMAKER_UTCPD_REG_DUMP(dev, VBOVTH);
366 NUMAKER_UTCPD_REG_DUMP(dev, VCPSVOL);
367 NUMAKER_UTCPD_REG_DUMP(dev, VCUV);
368 NUMAKER_UTCPD_REG_DUMP(dev, PHYCTL);
369 NUMAKER_UTCPD_REG_DUMP(dev, FRSRXCTL);
370 NUMAKER_UTCPD_REG_DUMP(dev, VCVOL);
371 NUMAKER_UTCPD_REG_DUMP(dev, CLKINFO);
372
373 return 0;
374 }
375
376 /**
377 * @brief Initializes EADC Vref
378 *
379 * @retval 0 on success
380 */
numaker_eadc_vref_init(const struct device * dev)381 static int numaker_eadc_vref_init(const struct device *dev)
382 {
383 const struct numaker_tcpc_config *const config = dev->config;
384 struct numaker_tcpc_data *data = dev->data;
385 const struct adc_dt_spec *spec;
386 enum adc_reference reference;
387
388 if (data->vref_mv) {
389 return 0;
390 }
391
392 /* NOTE: Register protection lock will restore automatically. Unlock it again. */
393 SYS_UnlockReg();
394
395 /* Analog reference voltage
396 *
397 * NOTE: For Vref being internal, external Vref pin must be floating,
398 * or it can disturb.
399 */
400 spec = config->eadc.spec_vbus ? config->eadc.spec_vbus : config->eadc.spec_vconn;
401 if (spec == NULL) {
402 return 0;
403 }
404 /* ADC device ready */
405 if (!adc_is_ready_dt(spec)) {
406 LOG_ERR("ADC device for VBUS/VCONN not ready");
407 return -ENODEV;
408 }
409
410 /* ADC channel configuration ready */
411 if (!spec->channel_cfg_dt_node_exists) {
412 LOG_ERR("ADC channel configuration for VBUS/VCONN not specified");
413 return -ENODEV;
414 }
415
416 reference = spec->channel_cfg.reference;
417
418 SYS->VREFCTL &= ~SYS_VREFCTL_VREFCTL_Msk;
419 if (reference == ADC_REF_EXTERNAL0 || reference == ADC_REF_EXTERNAL1) {
420 SYS->VREFCTL |= SYS_VREFCTL_VREF_PIN;
421 } else if (reference == ADC_REF_INTERNAL) {
422 switch (spec->vref_mv) {
423 case 1600:
424 SYS->VREFCTL |= SYS_VREFCTL_VREF_1_6V;
425 break;
426 case 2000:
427 SYS->VREFCTL |= SYS_VREFCTL_VREF_2_0V;
428 break;
429 case 2500:
430 SYS->VREFCTL |= SYS_VREFCTL_VREF_2_5V;
431 break;
432 case 3000:
433 SYS->VREFCTL |= SYS_VREFCTL_VREF_3_0V;
434 break;
435 default:
436 LOG_ERR("Invalid Vref voltage");
437 return -ENOTSUP;
438 }
439 } else {
440 LOG_ERR("Invalid Vref source");
441 return -ENOTSUP;
442 }
443
444 data->vref_mv = spec->vref_mv;
445
446 return 0;
447 }
448
449 /**
450 * @brief Reads and returns UTCPD VBUS measured in mV
451 *
452 * @retval 0 on success
453 * @retval -EIO on failure
454 */
numaker_utcpd_vbus_measure(const struct device * dev,uint32_t * mv)455 int numaker_utcpd_vbus_measure(const struct device *dev, uint32_t *mv)
456 {
457 const struct numaker_tcpc_config *const config = dev->config;
458 UTCPD_T *utcpd_base = config->utcpd_base;
459 int rc;
460
461 if (mv == NULL) {
462 return -EINVAL;
463 }
464 *mv = 0;
465
466 if (config->eadc.spec_vbus == NULL) {
467 return -ENOTSUP;
468 }
469
470 /* Vref */
471 rc = numaker_eadc_vref_init(dev);
472 if (rc < 0) {
473 return rc;
474 }
475
476 *mv = NUMAKER_UTCPD_VBUS_THRESHOLD_READ(dev, VBVOL);
477
478 return 0;
479 }
480
481 /**
482 * @brief Check if the UTCPD VBUS is present
483 *
484 * @retval 1 if UTCPD VBUS is present
485 * @retval 0 if UTCPD VBUS is not present
486 */
numaker_utcpd_vbus_is_present(const struct device * dev)487 int numaker_utcpd_vbus_is_present(const struct device *dev)
488 {
489 const struct numaker_tcpc_config *const config = dev->config;
490 UTCPD_T *utcpd_base = config->utcpd_base;
491 uint32_t pwrsts = NUMAKER_UTCPD_REG_READ_BY_NAME(dev, PWRSTS);
492
493 if (pwrsts & UTCPD_PWRSTS_VBPS_Msk) {
494 return 1;
495 } else {
496 return 0;
497 }
498 }
499
500 /**
501 * @brief Check if the UTCPD VBUS is sourcing
502 *
503 * @retval 1 if UTCPD VBUS is sourcing
504 * @retval 0 if UTCPD VBUS is not sourcing
505 */
numaker_utcpd_vbus_is_source(const struct device * dev)506 int numaker_utcpd_vbus_is_source(const struct device *dev)
507 {
508 const struct numaker_tcpc_config *const config = dev->config;
509 UTCPD_T *utcpd_base = config->utcpd_base;
510 uint32_t pwrsts = NUMAKER_UTCPD_REG_READ_BY_NAME(dev, PWRSTS);
511
512 if (pwrsts & (UTCPD_PWRSTS_SRHV_Msk | UTCPD_PWRSTS_SRVB_Msk)) {
513 return 1;
514 } else {
515 return 0;
516 }
517 }
518
519 /**
520 * @brief Check if the UTCPD VBUS is sinking
521 *
522 * @retval 1 if UTCPD VBUS is sinking
523 * @retval 0 if UTCPD VBUS is not sinking
524 */
numaker_utcpd_vbus_is_sink(const struct device * dev)525 int numaker_utcpd_vbus_is_sink(const struct device *dev)
526 {
527 const struct numaker_tcpc_config *const config = dev->config;
528 UTCPD_T *utcpd_base = config->utcpd_base;
529 uint32_t pwrsts = NUMAKER_UTCPD_REG_READ_BY_NAME(dev, PWRSTS);
530
531 if (pwrsts & UTCPD_PWRSTS_SKVB_Msk) {
532 return 1;
533 } else {
534 return 0;
535 }
536 }
537
538 /**
539 * @brief Enable or disable discharge on UTCPD VBUS
540 *
541 * @retval 0 on success
542 * @retval -EIO on failure
543 */
numaker_utcpd_vbus_set_discharge(const struct device * dev,bool enable)544 int numaker_utcpd_vbus_set_discharge(const struct device *dev, bool enable)
545 {
546 const struct numaker_tcpc_config *const config = dev->config;
547 UTCPD_T *utcpd_base = config->utcpd_base;
548 int rc;
549 const struct gpio_dt_spec *vbus_discharge_spec = &config->utcpd.gpios.vbus_discharge;
550 uint32_t pwrctl = NUMAKER_UTCPD_REG_READ_BY_NAME(dev, PWRCTL);
551
552 /* Use GPIO VBUS discharge */
553 if (vbus_discharge_spec->port != NULL) {
554 return gpio_pin_set_dt(vbus_discharge_spec, enable);
555 }
556
557 /* Use UTCPD VBUS discharge */
558 if (enable) {
559 pwrctl |= UTCPD_PWRCTL_FDGEN_Msk;
560 } else {
561 pwrctl &= ~UTCPD_PWRCTL_FDGEN_Msk;
562 }
563 rc = NUMAKER_UTCPD_REG_WRITE_BY_NAME(dev, PWRCTL, pwrctl);
564 if (rc < 0) {
565 return rc;
566 }
567
568 return 0;
569 }
570
571 /**
572 * @brief Enable or disable UTCPD BIST test mode
573 *
574 * @retval 0 on success
575 * @retval -EIO on failure
576 */
numaker_utcpd_bist_test_mode_set_enable(const struct device * dev,bool enable)577 static int numaker_utcpd_bist_test_mode_set_enable(const struct device *dev, bool enable)
578 {
579 const struct numaker_tcpc_config *const config = dev->config;
580 UTCPD_T *utcpd_base = config->utcpd_base;
581 int rc;
582 uint32_t ctl = NUMAKER_UTCPD_REG_READ_BY_NAME(dev, CTL);
583
584 /* Enable or not BIST test mode */
585 if (enable) {
586 ctl |= UTCPD_CTL_BISTEN_Msk;
587 } else {
588 ctl &= ~UTCPD_CTL_BISTEN_Msk;
589 }
590 rc = NUMAKER_UTCPD_REG_WRITE_BY_NAME(dev, CTL, ctl);
591 if (rc < 0) {
592 return rc;
593 }
594
595 return 0;
596 }
597
598 /**
599 * @brief Check if UTCPD BIST test mode is enabled
600 *
601 * @retval 1 if UTCPD BIST test mode is enabled
602 * @retval 0 if UTCPD BIST test mode is not enabled
603 */
numaker_utcpd_bist_test_mode_is_enabled(const struct device * dev)604 static int numaker_utcpd_bist_test_mode_is_enabled(const struct device *dev)
605 {
606 const struct numaker_tcpc_config *const config = dev->config;
607 UTCPD_T *utcpd_base = config->utcpd_base;
608 uint32_t ctl = NUMAKER_UTCPD_REG_READ_BY_NAME(dev, CTL);
609
610 if (ctl & UTCPD_CTL_BISTEN_Msk) {
611 return 1;
612 } else {
613 return 0;
614 }
615 }
616
617 /**
618 * @brief Clears UTCPD Rx message FIFO
619 *
620 * @retval 0 on success
621 */
numaker_utcpd_rx_fifo_clear(const struct device * dev)622 static int numaker_utcpd_rx_fifo_clear(const struct device *dev)
623 {
624 struct numaker_tcpc_data *data = dev->data;
625
626 data->rx_msg_ready = false;
627
628 return 0;
629 }
630
631 /**
632 * @brief Reads Rx message data from UTCPD
633 *
634 * @retval 0 on success
635 * @retval -EIO on failure
636 */
numaker_utcpd_rx_read_data(const struct device * dev,uint8_t * rx_data,uint32_t rx_data_size)637 static int numaker_utcpd_rx_read_data(const struct device *dev, uint8_t *rx_data,
638 uint32_t rx_data_size)
639 {
640 const struct numaker_tcpc_config *const config = dev->config;
641 UTCPD_T *utcpd_base = config->utcpd_base;
642 uint32_t data_rmn = rx_data_size;
643 uint8_t *data_pos = rx_data;
644 uintptr_t data_reg_offset = offsetof(UTCPD_T, RXDA0);
645 uint32_t data_value;
646
647 /* 32-bit aligned */
648 while (data_rmn >= 4) {
649 data_value = NUMAKER_UTCPD_REG_READ_BY_OFFSET(dev, data_reg_offset);
650 sys_put_le32(data_value, data_pos);
651
652 /* Next data */
653 data_reg_offset += 4;
654 data_pos += 4;
655 data_rmn -= 4;
656 }
657
658 /* Remaining non-32-bit aligned */
659 __ASSERT_NO_MSG(data_rmn < 4);
660 if (data_rmn) {
661 data_value = NUMAKER_UTCPD_REG_READ_BY_OFFSET(dev, data_reg_offset);
662 data_reg_offset += 4;
663
664 switch (data_rmn) {
665 case 3:
666 sys_put_le24(data_value, data_pos);
667 data_pos += 3;
668 data_rmn -= 3;
669 break;
670
671 case 2:
672 sys_put_le16(data_value, data_pos);
673 data_pos += 2;
674 data_rmn -= 2;
675 break;
676
677 case 1:
678 *data_pos = data_value;
679 data_pos += 1;
680 data_rmn -= 1;
681 break;
682 }
683 }
684
685 __ASSERT_NO_MSG(data_rmn == 0);
686
687 return 0;
688 }
689
690 /**
691 * @brief Writes Tx message data to UTCPD
692 *
693 * @retval 0 on success
694 * @retval -EIO on failure
695 */
numaker_utcpd_tx_write_data(const struct device * dev,const uint8_t * tx_data,uint32_t tx_data_size)696 static int numaker_utcpd_tx_write_data(const struct device *dev, const uint8_t *tx_data,
697 uint32_t tx_data_size)
698 {
699 const struct numaker_tcpc_config *const config = dev->config;
700 UTCPD_T *utcpd_base = config->utcpd_base;
701 int rc;
702 uint32_t data_rmn = tx_data_size;
703 const uint8_t *data_pos = tx_data;
704 uint32_t data_reg_offset = offsetof(UTCPD_T, TXDA0);
705 uint32_t data_value;
706
707 /* 32-bit aligned */
708 while (data_rmn >= 4) {
709 data_value = sys_get_le32(data_pos);
710 rc = NUMAKER_UTCPD_REG_WRITE_BY_OFFSET(dev, data_reg_offset, data_value);
711 if (rc < 0) {
712 return rc;
713 }
714
715 /* Next data */
716 data_pos += 4;
717 data_reg_offset += 4;
718 data_rmn -= 4;
719 }
720
721 /* Remaining non-32-bit aligned */
722 __ASSERT_NO_MSG(data_rmn < 4);
723 if (data_rmn) {
724 switch (data_rmn) {
725 case 3:
726 data_value = sys_get_le24(data_pos);
727 data_pos += 3;
728 data_rmn -= 3;
729 break;
730
731 case 2:
732 data_value = sys_get_le16(data_pos);
733 data_pos += 2;
734 data_rmn -= 2;
735 break;
736
737 case 1:
738 data_value = *data_pos;
739 data_pos += 1;
740 data_rmn -= 1;
741 break;
742 }
743 rc = NUMAKER_UTCPD_REG_WRITE_BY_OFFSET(dev, data_reg_offset, data_value);
744 if (rc < 0) {
745 return rc;
746 }
747 data_reg_offset += 4;
748 }
749
750 __ASSERT_NO_MSG(data_rmn == 0);
751
752 return 0;
753 }
754
755 /**
756 * @brief Enqueues UTCPD Rx message
757 *
758 * @retval 0 on success
759 * @retval -EIO on failure
760 */
numaker_utcpd_rx_fifo_enqueue(const struct device * dev)761 static int numaker_utcpd_rx_fifo_enqueue(const struct device *dev)
762 {
763 const struct numaker_tcpc_config *const config = dev->config;
764 struct numaker_tcpc_data *data = dev->data;
765 UTCPD_T *utcpd_base = config->utcpd_base;
766 int rc = 0;
767 uint32_t rxbcnt = NUMAKER_UTCPD_REG_READ_BY_NAME(dev, RXBCNT);
768 uint32_t rxftype = NUMAKER_UTCPD_REG_READ_BY_NAME(dev, RXFTYPE);
769 uint32_t rxhead = NUMAKER_UTCPD_REG_READ_BY_NAME(dev, RXHEAD);
770 uint32_t is = NUMAKER_UTCPD_REG_READ_BY_NAME(dev, IS);
771 uint32_t rx_data_size;
772 struct pd_msg *msg = &data->rx_msg;
773
774 /* Rx message pending? */
775 if (!(is & UTCPD_IS_RXSOPIS_Msk)) {
776 goto cleanup;
777 }
778
779 /* rxbcnt = 1 (frame type) + 2 (Message Header) + Rx data byte count */
780 if (rxbcnt < 3) {
781 LOG_ERR("Invalid UTCPD.RXBCNT: %d", rxbcnt);
782 rc = -EIO;
783 goto cleanup;
784 }
785 rx_data_size = rxbcnt - 3;
786
787 /* Not support Unchunked Extended Message exceeding PD_CONVERT_PD_HEADER_COUNT_TO_BYTES */
788 if (rx_data_size > (PD_MAX_EXTENDED_MSG_LEGACY_LEN + 2)) {
789 LOG_ERR("Not support Unchunked Extended Message exceeding "
790 "PD_CONVERT_PD_HEADER_COUNT_TO_BYTES: %d",
791 rx_data_size);
792 rc = -EIO;
793 goto cleanup;
794 }
795
796 /* Rx FIFO has room? */
797 if (data->rx_msg_ready) {
798 LOG_WRN("Rx FIFO overflow");
799 }
800
801 /* Rx frame type */
802 /* NOTE: Needn't extra cast for UTCPD_RXFTYPE.RXFTYPE aligning with pd_packet_type */
803 msg->type = (rxftype & UTCPD_RXFTYPE_RXFTYPE_Msk) >> UTCPD_RXFTYPE_RXFTYPE_Pos;
804
805 /* Rx header */
806 msg->header.raw_value = (uint16_t)rxhead;
807
808 /* Rx data size */
809 msg->len = rx_data_size;
810
811 /* Rx data */
812 rc = numaker_utcpd_rx_read_data(dev, msg->data, rx_data_size);
813 if (rc < 0) {
814 goto cleanup;
815 }
816
817 /* Finish enqueue of this Rx message */
818 data->rx_msg_ready = true;
819
820 cleanup:
821
822 /* This has side effect of clearing UTCPD_RXBCNT and friends. */
823 NUMAKER_UTCPD_REG_FORCE_WRITE_BY_NAME(dev, IS, UTCPD_IS_RXSOPIS_Msk);
824
825 return rc;
826 }
827
828 /**
829 * @brief Notify TCPC alert
830 */
numaker_utcpd_notify_tcpc_alert(const struct device * dev,enum tcpc_alert alert)831 static void numaker_utcpd_notify_tcpc_alert(const struct device *dev, enum tcpc_alert alert)
832 {
833 struct numaker_tcpc_data *data = dev->data;
834 tcpc_alert_handler_cb_t alert_handler = data->tcpc_alert.handler;
835 void *alert_data = data->tcpc_alert.data;
836
837 if (alert_handler) {
838 alert_handler(dev, alert_data, alert);
839 }
840 }
841
842 /**
843 * @brief Notify PPC event
844 */
numaker_utcpd_notify_ppc_event(const struct device * dev,enum usbc_ppc_event event)845 static void numaker_utcpd_notify_ppc_event(const struct device *dev, enum usbc_ppc_event event)
846 {
847 struct numaker_tcpc_data *data = dev->data;
848 usbc_ppc_event_cb_t event_handler = data->ppc_event.handler;
849 void *event_data = data->ppc_event.data;
850
851 if (event_handler) {
852 event_handler(dev, event_data, event);
853 }
854 }
855
856 /**
857 * @brief UTCPD ISR
858 *
859 * @note UTCPD register write cannot be failed, or we may trap in ISR for
860 * interrupt bits not cleared. To avoid that, we use "force-write"
861 * version clear interrupt bits for sure.
862 */
numaker_utcpd_isr(const struct device * dev)863 static void numaker_utcpd_isr(const struct device *dev)
864 {
865 const struct numaker_tcpc_config *const config = dev->config;
866 UTCPD_T *utcpd_base = config->utcpd_base;
867 uint32_t is = NUMAKER_UTCPD_REG_READ_BY_NAME(dev, IS);
868 uint32_t futsts = NUMAKER_UTCPD_REG_READ_BY_NAME(dev, FUTSTS);
869 uint32_t vndis = NUMAKER_UTCPD_REG_READ_BY_NAME(dev, VNDIS);
870 uint32_t ie = NUMAKER_UTCPD_REG_READ_BY_NAME(dev, IE);
871 uint32_t futstsie = NUMAKER_UTCPD_REG_READ_BY_NAME(dev, FUTSTSIE);
872
873 /* CC status changed */
874 if (is & UTCPD_IS_CCSCHIS_Msk) {
875 numaker_utcpd_notify_tcpc_alert(dev, TCPC_ALERT_CC_STATUS);
876 }
877
878 /* Power status changed */
879 if (is & UTCPD_IS_PWRSCHIS_Msk) {
880 numaker_utcpd_notify_tcpc_alert(dev, TCPC_ALERT_POWER_STATUS);
881 }
882
883 /* Received SOP Message */
884 if (is & UTCPD_IS_RXSOPIS_Msk) {
885 numaker_utcpd_rx_fifo_enqueue(dev);
886
887 /* Per TCPCI 4.4.5.1 TCPC_CONTROL, BIST Test Mode
888 * Incoming messages enabled by RECEIVE_DETECT result
889 * in GoodCRC response but may not be passed to the TCPM
890 * via Alert. TCPC may temporarily store incoming messages
891 * in the Receive Message Buffer, but this may or may not
892 * result in a Receive SOP* Message Status or a Rx Buffer
893 * Overflow alert.
894 */
895 if (numaker_utcpd_bist_test_mode_is_enabled(dev) == 1) {
896 numaker_utcpd_rx_fifo_clear(dev);
897 } else {
898 numaker_utcpd_notify_tcpc_alert(dev, TCPC_ALERT_MSG_STATUS);
899 }
900 }
901
902 /* Rx buffer overflow */
903 if (is & UTCPD_IS_RXOFIS_Msk) {
904 LOG_WRN("Rx buffer overflow");
905 numaker_utcpd_notify_tcpc_alert(dev, TCPC_ALERT_RX_BUFFER_OVERFLOW);
906 }
907
908 /* Received Hard Reset */
909 if (is & UTCPD_IS_RXHRSTIS_Msk) {
910 numaker_utcpd_notify_tcpc_alert(dev, TCPC_ALERT_HARD_RESET_RECEIVED);
911 }
912
913 /* SOP* message transmission not successful, no GoodCRC response received on SOP* message
914 * transmission
915 */
916 if (is & UTCPD_IS_TXFALIS_Msk) {
917 numaker_utcpd_notify_tcpc_alert(dev, TCPC_ALERT_TRANSMIT_MSG_FAILED);
918 }
919
920 /* Reset or SOP* message transmission not sent due to incoming receive message */
921 if (is & UTCPD_IS_TXDCUDIS_Msk) {
922 numaker_utcpd_notify_tcpc_alert(dev, TCPC_ALERT_TRANSMIT_MSG_DISCARDED);
923 }
924
925 /* Reset or SOP* message transmission successful, GoodCRC response received on SOP* message
926 * transmission
927 */
928 if (is & UTCPD_IS_TXOKIS_Msk) {
929 numaker_utcpd_notify_tcpc_alert(dev, TCPC_ALERT_TRANSMIT_MSG_SUCCESS);
930 }
931
932 /* VBUS voltage alarm high */
933 if ((is & UTCPD_IS_VBAMHIS_Msk) && (ie & UTCPD_IS_VBAMHIS_Msk)) {
934 LOG_WRN("UTCPD VBUS voltage alarm high not addressed, disable the alert");
935 ie &= ~UTCPD_IS_VBAMHIS_Msk;
936 NUMAKER_UTCPD_REG_FORCE_WRITE_BY_NAME(dev, IE, ie);
937 numaker_utcpd_notify_tcpc_alert(dev, TCPC_ALERT_VBUS_ALARM_HI);
938 }
939
940 /* VBUS voltage alarm low */
941 if ((is & UTCPD_IS_VBAMLIS_Msk) && (ie & UTCPD_IS_VBAMLIS_Msk)) {
942 LOG_WRN("UTCPD VBUS voltage alarm low not addressed, disable the alert");
943 ie &= ~UTCPD_IS_VBAMLIS_Msk;
944 NUMAKER_UTCPD_REG_FORCE_WRITE_BY_NAME(dev, IE, ie);
945 numaker_utcpd_notify_tcpc_alert(dev, TCPC_ALERT_VBUS_ALARM_LO);
946 }
947
948 /* Fault */
949 if ((is & UTCPD_IS_FUTIS_Msk) && (futstsie & futsts)) {
950 LOG_ERR("UTCPD fault (FUTSTS=0x%08x)", futsts);
951 NUMAKER_UTCPD_REG_FORCE_WRITE_BY_OFFSET(dev, offsetof(UTCPD_T, FUTSTS), futsts);
952 /* NOTE: FUTSTSIE will restore to default on Hard Reset. We may re-enter
953 * here and redo mask.
954 */
955 LOG_WRN("UTCPD fault (FUTSTS=0x%08x) not addressed, disable fault alert (FUTSTSIE)",
956 futsts);
957 futstsie &= ~futsts;
958 NUMAKER_UTCPD_REG_FORCE_WRITE_BY_NAME(dev, FUTSTSIE, futstsie);
959 numaker_utcpd_notify_tcpc_alert(dev, TCPC_ALERT_FAULT_STATUS);
960
961 /* VBUS overvoltage */
962 if (futsts & UTCPD_FUTSTS_VBOVFUT_Msk) {
963 if (numaker_utcpd_vbus_is_source(dev)) {
964 numaker_utcpd_notify_ppc_event(dev, USBC_PPC_EVENT_SRC_OVERVOLTAGE);
965 }
966
967 if (numaker_utcpd_vbus_is_sink(dev)) {
968 numaker_utcpd_notify_ppc_event(dev, USBC_PPC_EVENT_SNK_OVERVOLTAGE);
969 }
970 }
971
972 /* VBUS overcurrent */
973 if (futsts & UTCPD_FUTSTS_VBOCFUT_Msk) {
974 if (numaker_utcpd_vbus_is_source(dev)) {
975 numaker_utcpd_notify_ppc_event(dev, USBC_PPC_EVENT_SRC_OVERCURRENT);
976 }
977 }
978 }
979
980 /* VBUS Sink disconnect threshold crossing has been detected */
981 if (is & UTCPD_IS_SKDCDTIS_Msk) {
982 numaker_utcpd_notify_tcpc_alert(dev, TCPC_ALERT_VBUS_SNK_DISCONNECT);
983 }
984
985 /* Vendor defined event detected */
986 if (is & UTCPD_IS_VNDIS_Msk) {
987 NUMAKER_UTCPD_REG_FORCE_WRITE_BY_NAME(dev, VNDIS, vndis);
988
989 numaker_utcpd_notify_tcpc_alert(dev, TCPC_ALERT_VENDOR_DEFINED);
990 }
991
992 NUMAKER_UTCPD_REG_FORCE_WRITE_BY_NAME(dev, IS, is);
993 }
994
995 /**
996 * @brief Configures EADC sample module with trigger source, channel, etc.
997 */
numaker_eadc_smplmod_init(const struct device * dev,const struct adc_dt_spec * spec,uint32_t trgsel)998 static int numaker_eadc_smplmod_init(const struct device *dev, const struct adc_dt_spec *spec,
999 uint32_t trgsel)
1000 {
1001 const struct numaker_tcpc_config *const config = dev->config;
1002 EADC_T *eadc_base = config->eadc_base;
1003 uint16_t acquisition_time;
1004 uint16_t acq_time_unit;
1005 uint16_t acq_time_value;
1006
1007 __ASSERT_NO_MSG(spec);
1008
1009 /* ADC device ready */
1010 if (!adc_is_ready_dt(spec)) {
1011 LOG_ERR("ADC device for VBUS/VCONN not ready");
1012 return -ENODEV;
1013 }
1014
1015 /* ADC channel configuration ready */
1016 if (!spec->channel_cfg_dt_node_exists) {
1017 LOG_ERR("ADC channel configuration for VBUS/VCONN not specified");
1018 return -ENODEV;
1019 }
1020
1021 acquisition_time = spec->channel_cfg.acquisition_time;
1022 acq_time_unit = ADC_ACQ_TIME_UNIT(acquisition_time);
1023 acq_time_value = ADC_ACQ_TIME_VALUE(acquisition_time);
1024 if (acq_time_unit != ADC_ACQ_TIME_TICKS) {
1025 LOG_ERR("Invalid acquisition time unit for VBUS/VCONN");
1026 return -ENOTSUP;
1027 }
1028
1029 /* Bind sample module with trigger source and channel */
1030 EADC_ConfigSampleModule(eadc_base, spec->channel_id, trgsel, spec->channel_id);
1031 /* Extend sampling time */
1032 EADC_SetExtendSampleTime(eadc_base, spec->channel_id, acq_time_value);
1033
1034 return 0;
1035 }
1036
1037 /**
1038 * @brief Initializes VBUS threshold and monitor
1039 *
1040 * @retval 0 on success
1041 * @retval -EIO on failure
1042 */
numaker_utcpd_vbus_init(const struct device * dev)1043 static int numaker_utcpd_vbus_init(const struct device *dev)
1044 {
1045 const struct numaker_tcpc_config *const config = dev->config;
1046 UTCPD_T *utcpd_base = config->utcpd_base;
1047 int rc;
1048 uint32_t vbvol = NUMAKER_UTCPD_REG_READ_BY_NAME(dev, VBVOL);
1049 uint32_t pwrctl = 0;
1050
1051 /* UTCPD VBUS scale factor */
1052 vbvol &= ~UTCPD_VBVOL_VBSCALE_Msk;
1053 vbvol |= config->utcpd.vbvol.vbscale.bit;
1054 rc = NUMAKER_UTCPD_REG_WRITE_BY_NAME(dev, VBVOL, vbvol);
1055 if (rc < 0) {
1056 return rc;
1057 }
1058
1059 if (config->eadc.spec_vbus != NULL) {
1060 /* Vref */
1061 rc = numaker_eadc_vref_init(dev);
1062 if (rc < 0) {
1063 return rc;
1064 }
1065
1066 /* UTCPD VBUS overvoltage threshold */
1067 rc = NUMAKER_UTCPD_VBUS_THRESHOLD_WRITE(
1068 dev, VBOVTH, NUMAKER_UTCPD_VBUS_THRESHOLD_OVERVOLTAGE_MV);
1069 if (rc < 0) {
1070 return rc;
1071 }
1072
1073 /* UTCPD VBUS vSafe5V threshold */
1074 rc = NUMAKER_UTCPD_VBUS_THRESHOLD_WRITE(dev, VSAFE5V,
1075 NUMAKER_UTCPD_VBUS_THRESHOLD_VSAFE5V_MV);
1076 if (rc < 0) {
1077 return rc;
1078 }
1079
1080 /* UTCPD VBUS vSafe0V threshold */
1081 rc = NUMAKER_UTCPD_VBUS_THRESHOLD_WRITE(dev, VSAFE0V,
1082 NUMAKER_UTCPD_VBUS_THRESHOLD_VSAFE0V_MV);
1083 if (rc < 0) {
1084 return rc;
1085 }
1086
1087 /* UTCPD VBUS stop force discharge threshold */
1088 rc = NUMAKER_UTCPD_VBUS_THRESHOLD_WRITE(
1089 dev, SPDGTH, NUMAKER_UTCPD_VBUS_THRESHOLD_STOP_FORCE_DISCHARGE_MV);
1090 if (rc < 0) {
1091 return rc;
1092 }
1093
1094 /* UTCPD VBUS sink disconnect threshold */
1095 rc = NUMAKER_UTCPD_VBUS_THRESHOLD_WRITE(
1096 dev, SKVBDCTH, NUMAKER_UTCPD_VBUS_THRESHOLD_SINK_DISCONNECT_MV);
1097 if (rc < 0) {
1098 return rc;
1099 }
1100 }
1101
1102 /* Enable UTCPD VBUS voltage monitor so that UTCPD.VBVOL is available */
1103 if (config->eadc.spec_vbus != NULL) {
1104 pwrctl &= ~UTCPD_PWRCTL_VBMONI_DIS;
1105 } else {
1106 pwrctl |= UTCPD_PWRCTL_VBMONI_DIS;
1107 }
1108 /* Disable UTCPD VBUS voltage alarms */
1109 pwrctl |= UTCPD_PWRCTL_DSVBAM_DIS;
1110 /* Disable UTCPD VBUS auto-discharge on disconnect
1111 * NOTE: UTCPD may not integrate with discharge, so this feature is
1112 * disabled and discharge is handled separately.
1113 */
1114 pwrctl &= ~UTCPD_PWRCTL_ADGDC;
1115 return NUMAKER_UTCPD_REG_WRITE_BY_NAME(dev, PWRCTL, pwrctl);
1116 }
1117
1118 /**
1119 * @brief Initializes UTCPD GPIO pins
1120 *
1121 * @retval 0 on success
1122 * @retval -EIO on failure
1123 */
numaker_utcpd_gpios_init(const struct device * dev)1124 static int numaker_utcpd_gpios_init(const struct device *dev)
1125 {
1126 const struct numaker_tcpc_config *const config = dev->config;
1127 int rc;
1128 const struct gpio_dt_spec *spec;
1129
1130 /* Configure VBUS detect pin to INPUT to avoid intervening its power measurement */
1131 spec = &config->utcpd.gpios.vbus_detect;
1132 if (spec->port == NULL) {
1133 LOG_ERR("VBUS detect pin not specified");
1134 return -ENODEV;
1135 }
1136 if (!gpio_is_ready_dt(spec)) {
1137 LOG_ERR("VBUS detect pin port device not ready");
1138 return -ENODEV;
1139 }
1140 rc = gpio_pin_configure_dt(spec, GPIO_INPUT);
1141 if (rc < 0) {
1142 LOG_ERR("VBUS detect pin configured to INPUT failed: %d", rc);
1143 return rc;
1144 }
1145
1146 /* Configure VBUS discharge pin to OUTPUT INACTIVE */
1147 spec = &config->utcpd.gpios.vbus_discharge;
1148 if (spec->port != NULL) {
1149 if (!gpio_is_ready_dt(spec)) {
1150 LOG_ERR("VBUS discharge pin port device not ready");
1151 return -ENODEV;
1152 }
1153 rc = gpio_pin_configure_dt(spec, GPIO_OUTPUT_INACTIVE);
1154 if (rc < 0) {
1155 LOG_ERR("VBUS discharge pin configured to OUTPUT INACTIVE failed: %d", rc);
1156 return rc;
1157 }
1158 }
1159
1160 /* Configure VCONN discharge pin to OUTPUT INACTIVE */
1161 spec = &config->utcpd.gpios.vconn_discharge;
1162 if (spec->port != NULL) {
1163 if (!gpio_is_ready_dt(spec)) {
1164 LOG_ERR("VCONN discharge pin port device not ready");
1165 return -ENODEV;
1166 }
1167 rc = gpio_pin_configure_dt(spec, GPIO_OUTPUT_INACTIVE);
1168 if (rc < 0) {
1169 LOG_ERR("VCONN discharge pin configured to OUTPUT INACTIVE failed: %d", rc);
1170 return rc;
1171 }
1172 }
1173
1174 return 0;
1175 }
1176
1177 /**
1178 * @brief Initializes UTCPD PHY
1179 *
1180 * @retval 0 on success
1181 * @retval -EIO on failure
1182 */
numaker_utcpd_phy_init(const struct device * dev)1183 static int numaker_utcpd_phy_init(const struct device *dev)
1184 {
1185 const struct numaker_tcpc_config *const config = dev->config;
1186 UTCPD_T *utcpd_base = config->utcpd_base;
1187 uint32_t phyctl = NUMAKER_UTCPD_REG_READ_BY_NAME(dev, PHYCTL);
1188
1189 /* Enable PHY
1190 *
1191 * NOTE: Only UTCPD0 is supported.
1192 */
1193 SYS->UTCPDCTL |= SYS_UTCPDCTL_POREN0_Msk;
1194 phyctl |= UTCPD_PHYCTL_PHYPWR_Msk;
1195 return NUMAKER_UTCPD_REG_WRITE_BY_NAME(dev, PHYCTL, phyctl);
1196 }
1197
1198 /**
1199 * @brief Checks if UTCPD Dead Battery mode is enabled
1200 *
1201 * @retval true Dead Battery mode is enabled
1202 * @retval false Dead Battery mode is not enabled
1203 */
numaker_utcpd_deadbattery_query_enable(const struct device * dev)1204 static bool numaker_utcpd_deadbattery_query_enable(const struct device *dev)
1205 {
1206 const struct numaker_tcpc_config *const config = dev->config;
1207 UTCPD_T *utcpd_base = config->utcpd_base;
1208 uint32_t phyctl = NUMAKER_UTCPD_REG_READ_BY_NAME(dev, PHYCTL);
1209
1210 /* 0 = Dead Battery circuit controls internal Rd/Rp.
1211 * 1 = Role Control Register controls internal Rd/
1212 */
1213 return !(phyctl & UTCPD_PHYCTL_DBCTL_Msk);
1214 }
1215
1216 /**
1217 * @brief Enables or disables UTCPD Dead Battery mode
1218 *
1219 * @retval 0 on success
1220 * @retval -EIO on failure
1221 */
numaker_utcpd_deadbattery_set_enable(const struct device * dev,bool enable)1222 static int numaker_utcpd_deadbattery_set_enable(const struct device *dev, bool enable)
1223 {
1224 const struct numaker_tcpc_config *const config = dev->config;
1225 UTCPD_T *utcpd_base = config->utcpd_base;
1226 uint32_t phyctl = NUMAKER_UTCPD_REG_READ_BY_NAME(dev, PHYCTL);
1227
1228 if (enable) {
1229 /* Dead Battery circuit controls internal Rd/Rp */
1230 phyctl &= ~UTCPD_PHYCTL_DBCTL_Msk;
1231 } else {
1232 /* UTCPD.ROLCTL controls internal Rd/Rp */
1233 phyctl |= UTCPD_PHYCTL_DBCTL_Msk;
1234 }
1235 return NUMAKER_UTCPD_REG_WRITE_BY_NAME(dev, PHYCTL, phyctl);
1236 }
1237
1238 /**
1239 * @brief Initializes UTCPD Dead Battery mode
1240 *
1241 * @retval 0 on success
1242 * @retval -EIO on failure
1243 */
numaker_utcpd_deadbattery_init(const struct device * dev)1244 static int numaker_utcpd_deadbattery_init(const struct device *dev)
1245 {
1246 const struct numaker_tcpc_config *const config = dev->config;
1247
1248 return numaker_utcpd_deadbattery_set_enable(dev, config->utcpd.dead_battery);
1249 }
1250
1251 /**
1252 * @brief Initializes UTCPD interrupts
1253 *
1254 * @retval 0 on success
1255 * @retval -EIO on failure
1256 */
numaker_utcpd_interrupts_init(const struct device * dev)1257 static int numaker_utcpd_interrupts_init(const struct device *dev)
1258 {
1259 const struct numaker_tcpc_config *const config = dev->config;
1260 UTCPD_T *utcpd_base = config->utcpd_base;
1261 int rc;
1262 uint32_t ie;
1263 uint32_t pwrstsie;
1264 uint32_t futstsie;
1265 uint32_t vndie;
1266
1267 ie = UTCPD_IE_VNDIE_Msk | UTCPD_IE_SKDCDTIE_Msk | UTCPD_IE_RXOFIE_Msk | UTCPD_IE_FUTIE_Msk |
1268 UTCPD_IE_VBAMLIE_Msk | UTCPD_IE_VBAMHIE_Msk | UTCPD_IE_TXOKIE_Msk |
1269 UTCPD_IE_TXDCUDIE_Msk | UTCPD_IE_TXFAILIE_Msk | UTCPD_IE_RXHRSTIE_Msk |
1270 UTCPD_IE_RXSOPIE_Msk | UTCPD_IE_PWRSCHIE_Msk | UTCPD_IE_CCSCHIE_Msk;
1271 rc = NUMAKER_UTCPD_REG_WRITE_BY_NAME(dev, IE, ie);
1272 if (rc < 0) {
1273 return rc;
1274 }
1275
1276 pwrstsie = UTCPD_PWRSTSIE_DACONIE_Msk | UTCPD_PWRSTSIE_SRHVIE_Msk |
1277 UTCPD_PWRSTSIE_SRVBIE_Msk | UTCPD_PWRSTSIE_VBDTDGIE_Msk |
1278 UTCPD_PWRSTSIE_VBPSIE_Msk | UTCPD_PWRSTSIE_VCPSIE_Msk |
1279 UTCPD_PWRSTSIE_SKVBIE_Msk;
1280 rc = NUMAKER_UTCPD_REG_WRITE_BY_NAME(dev, PWRSTSIE, pwrstsie);
1281 if (rc < 0) {
1282 return rc;
1283 }
1284
1285 futstsie = UTCPD_FUTSTSIE_FOFFVBIE_Msk | UTCPD_FUTSTSIE_ADGFALIE_Msk |
1286 UTCPD_FUTSTSIE_FDGFALIE_Msk | UTCPD_FUTSTSIE_VBOCIE_Msk |
1287 UTCPD_FUTSTSIE_VBOVIE_Msk | UTCPD_FUTSTSIE_VCOCIE_Msk;
1288 rc = NUMAKER_UTCPD_REG_WRITE_BY_NAME(dev, FUTSTSIE, futstsie);
1289 if (rc < 0) {
1290 return rc;
1291 }
1292
1293 vndie = UTCPD_VNDIE_VCDGIE_Msk | UTCPD_VNDIE_CRCERRIE_Msk | UTCPD_VNDIE_TXFRSIE_Msk |
1294 UTCPD_VNDIE_RXFRSIE_Msk;
1295 rc = NUMAKER_UTCPD_REG_WRITE_BY_NAME(dev, VNDIE, vndie);
1296 if (rc < 0) {
1297 return rc;
1298 }
1299
1300 return 0;
1301 }
1302
1303 /**
1304 * @brief Initializes UTCPD at stack recycle
1305 *
1306 * @retval 0 on success
1307 * @retval -EIO on failure
1308 */
numaker_utcpd_init_recycle(const struct device * dev)1309 static int numaker_utcpd_init_recycle(const struct device *dev)
1310 {
1311 const struct numaker_tcpc_config *const config = dev->config;
1312 UTCPD_T *utcpd_base = config->utcpd_base;
1313 int rc;
1314 uint32_t value;
1315
1316 /* Disable BIST, CC1/CC2 for CC/VCOON */
1317 value = 0;
1318 rc = NUMAKER_UTCPD_REG_WRITE_BY_NAME(dev, CTL, value);
1319 if (rc < 0) {
1320 return rc;
1321 }
1322
1323 /* Rp default, CC1/CC2 Rd */
1324 value = UTCPD_ROLECTL_RPVALUE_DEF | UTCPD_ROLECTL_CC1_RD | UTCPD_ROLECTL_CC2_RD;
1325 rc = NUMAKER_UTCPD_REG_WRITE_BY_NAME(dev, ROLCTL, value);
1326 if (rc < 0) {
1327 return rc;
1328 }
1329
1330 /* Disable VCONN source */
1331 value = NUMAKER_UTCPD_REG_READ_BY_NAME(dev, PWRCTL);
1332 value &= ~UTCPD_PWRCTL_VCEN_Msk;
1333 rc = NUMAKER_UTCPD_REG_WRITE_BY_NAME(dev, PWRCTL, value);
1334 if (rc < 0) {
1335 return rc;
1336 }
1337
1338 /* Disable detecting Rx events */
1339 value = 0;
1340 rc = NUMAKER_UTCPD_REG_WRITE_BY_NAME(dev, DTRXEVNT, value);
1341 if (rc < 0) {
1342 return rc;
1343 }
1344
1345 return 0;
1346 }
1347
1348 /**
1349 * @brief Initializes UTCPD at device startup
1350 *
1351 * @retval 0 on success
1352 * @retval -EIO on failure
1353 */
numaker_utcpd_init_startup(const struct device * dev)1354 static int numaker_utcpd_init_startup(const struct device *dev)
1355 {
1356 const struct numaker_tcpc_config *const config = dev->config;
1357 UTCPD_T *utcpd_base = config->utcpd_base;
1358 int rc;
1359 uint32_t pinpl;
1360 uint32_t futctl;
1361 uint32_t muxsel;
1362
1363 /* UTCPD GPIO */
1364 rc = numaker_utcpd_gpios_init(dev);
1365 if (rc < 0) {
1366 return rc;
1367 }
1368
1369 /* UTCPD PHY */
1370 rc = numaker_utcpd_phy_init(dev);
1371 if (rc < 0) {
1372 return rc;
1373 }
1374
1375 /* UTCPD Dead Battery */
1376 rc = numaker_utcpd_deadbattery_init(dev);
1377 if (rc < 0) {
1378 return rc;
1379 }
1380
1381 /* UTCPD pin polarity */
1382 pinpl = config->utcpd.pinpl.bit;
1383 rc = NUMAKER_UTCPD_REG_WRITE_BY_NAME(dev, PINPL, pinpl);
1384 if (rc < 0) {
1385 return rc;
1386 }
1387
1388 /* VBUS voltage and monitor */
1389 rc = numaker_utcpd_vbus_init(dev);
1390 if (rc < 0) {
1391 return rc;
1392 }
1393
1394 /* UTCPD fault
1395 *
1396 * Disable the following fault detects which rely on external circuit:
1397 * 1. VBUS force-off
1398 * 2. VBUS overcurrent protection
1399 * 3. VCONN overcurrent protection
1400 */
1401 futctl = UTCPD_FUTCTL_FOFFVBDS_Msk | UTCPD_FUTCTL_VBOCDTDS_Msk | UTCPD_FUTCTL_VCOCDTDS_Msk;
1402 rc = NUMAKER_UTCPD_REG_WRITE_BY_NAME(dev, FUTCTL, futctl);
1403 if (rc < 0) {
1404 return rc;
1405 }
1406
1407 /* UTCPD interconnection select
1408 *
1409 * NOTE: Just configure CC2FRSS/CC2VCENS/CC1FRSS/CC1VCENS to non-merged
1410 * to follow TCPCI
1411 */
1412 muxsel = UTCPD_MUXSEL_CC2FRSS_Msk | UTCPD_MUXSEL_CC2VCENS_Msk | UTCPD_MUXSEL_CC1FRSS_Msk |
1413 UTCPD_MUXSEL_CC1VCENS_Msk;
1414 /* NOTE: For absence of EADC channel measurement for VCONN, we configure with all-one which
1415 * is supposed to be invalid EADC channel number so that UTCPD won't get updated
1416 * on VCONN by accident.
1417 */
1418 if (config->eadc.spec_vbus != NULL) {
1419 muxsel |= (config->eadc.spec_vbus->channel_id << UTCPD_MUXSEL_ADCSELVB_Pos);
1420 } else {
1421 muxsel |= UTCPD_MUXSEL_ADCSELVB_Msk;
1422 }
1423 if (config->eadc.spec_vconn != NULL) {
1424 muxsel |= (config->eadc.spec_vconn->channel_id << UTCPD_MUXSEL_ADCSELVC_Pos);
1425 } else {
1426 muxsel |= UTCPD_MUXSEL_ADCSELVC_Msk;
1427 }
1428 rc = NUMAKER_UTCPD_REG_WRITE_BY_NAME(dev, MUXSEL, muxsel);
1429 if (rc < 0) {
1430 return rc;
1431 }
1432
1433 /* Interrupts */
1434 rc = numaker_utcpd_interrupts_init(dev);
1435 if (rc < 0) {
1436 return rc;
1437 }
1438
1439 /* IRQ */
1440 config->irq_config_func_utcpd(dev);
1441
1442 return 0;
1443 }
1444
1445 /**
1446 * @brief Initializes EADC to be timer-triggered for measuring
1447 * VBUS/VCONN voltage at device startup
1448 *
1449 * @retval 0 on success
1450 * @retval -EIO on failure
1451 */
numaker_eadc_init_startup(const struct device * dev)1452 static int numaker_eadc_init_startup(const struct device *dev)
1453 {
1454 const struct numaker_tcpc_config *const config = dev->config;
1455 EADC_T *eadc_base = config->eadc_base;
1456 int rc;
1457 const struct adc_dt_spec *spec;
1458
1459 /* Vref */
1460 rc = numaker_eadc_vref_init(dev);
1461 if (rc < 0) {
1462 return rc;
1463 }
1464
1465 /* Set input mode as single-end and enable the A/D converter */
1466 EADC_Open(eadc_base, EADC_CTL_DIFFEN_SINGLE_END);
1467
1468 /* Configure sample module for measuring VBUS voltage
1469 *
1470 * NOTE: Make sample module number the same as channel number for
1471 * easy implementation.
1472 * NOTE: EADC measurement channel for VBUS can be absent with PWRSTS.VBPS as fallback
1473 */
1474 spec = config->eadc.spec_vbus;
1475 if (spec) {
1476 rc = numaker_eadc_smplmod_init(dev, spec, config->eadc.trgsel_vbus);
1477 if (rc < 0) {
1478 return rc;
1479 }
1480 }
1481
1482 /* Configure sample module for measuring VCONN voltage
1483 *
1484 * NOTE: Make sample module number the same as channel number for
1485 * easy implementation.
1486 * NOTE: EADC measurement channel for VCONN can be absent for VCONN unsupported
1487 */
1488 spec = config->eadc.spec_vconn;
1489 if (spec) {
1490 rc = numaker_eadc_smplmod_init(dev, spec, config->eadc.trgsel_vconn);
1491 if (rc < 0) {
1492 return rc;
1493 }
1494 }
1495
1496 return 0;
1497 }
1498
1499 /**
1500 * @brief Initializes Timer to trigger EADC for measuring VBUS/VCONN
1501 * voltage at device startup
1502 *
1503 * @retval 0 on success
1504 */
numaker_timer_init_startup(const struct device * dev)1505 static int numaker_timer_init_startup(const struct device *dev)
1506 {
1507 const struct numaker_tcpc_config *const config = dev->config;
1508 TIMER_T *timer_base = config->timer_base;
1509
1510 /* Configure Timer to trigger EADC periodically */
1511 TIMER_Open(timer_base, TIMER_PERIODIC_MODE, config->eadc.timer_trigger_rate);
1512 TIMER_SetTriggerSource(timer_base, TIMER_TRGSRC_TIMEOUT_EVENT);
1513 TIMER_SetTriggerTarget(timer_base, TIMER_TRG_TO_EADC);
1514 TIMER_Start(timer_base);
1515
1516 return 0;
1517 }
1518
1519 /**
1520 * @brief Initializes TCPC at stack recycle
1521 *
1522 * @retval 0 on success
1523 * @retval -EIO on failure
1524 */
numaker_tcpc_init_recycle(const struct device * dev)1525 static int numaker_tcpc_init_recycle(const struct device *dev)
1526 {
1527 struct numaker_tcpc_data *data = dev->data;
1528 int rc;
1529
1530 /* Initialize UTCPD for attach/detach recycle */
1531 rc = numaker_utcpd_init_recycle(dev);
1532 if (rc < 0) {
1533 return rc;
1534 }
1535
1536 /* The fields below must (re-)initialize for tcpc_init(). */
1537 data->rp = TC_RP_USB;
1538 data->rx_sop_prime_enabled = false;
1539 data->rx_msg_ready = false;
1540 memset(&data->rx_msg, 0x00, sizeof(data->rx_msg));
1541
1542 return 0;
1543 }
1544
1545 /**
1546 * @brief Initializes TCPC at device startup
1547 *
1548 * @retval 0 on success
1549 * @retval -EIO on failure
1550 */
numaker_tcpc_init_startup(const struct device * dev)1551 static int numaker_tcpc_init_startup(const struct device *dev)
1552 {
1553 const struct numaker_tcpc_config *const config = dev->config;
1554 int rc;
1555
1556 SYS_UnlockReg();
1557
1558 /* Configure pinmux (NuMaker's SYS MFP) */
1559 rc = pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT);
1560 if (rc < 0) {
1561 return rc;
1562 }
1563
1564 /* Invoke Clock controller to enable module clock */
1565
1566 /* Equivalent to CLK_EnableModuleClock() */
1567 rc = clock_control_on(config->clkctrl_dev, (clock_control_subsys_t)&config->pcc_utcpd);
1568 if (rc < 0) {
1569 return rc;
1570 }
1571 rc = clock_control_on(config->clkctrl_dev, (clock_control_subsys_t)&config->pcc_timer);
1572 if (rc < 0) {
1573 return rc;
1574 }
1575
1576 /* Equivalent to CLK_SetModuleClock() */
1577 rc = clock_control_configure(config->clkctrl_dev,
1578 (clock_control_subsys_t)&config->pcc_utcpd, NULL);
1579 if (rc < 0) {
1580 return rc;
1581 }
1582 rc = clock_control_configure(config->clkctrl_dev,
1583 (clock_control_subsys_t)&config->pcc_timer, NULL);
1584 if (rc < 0) {
1585 return rc;
1586 }
1587
1588 /* Invoke Reset controller to reset module to default state */
1589 /* Equivalent to SYS_ResetModule() */
1590 rc = reset_line_toggle_dt(&config->reset_utcpd);
1591 if (rc < 0) {
1592 return rc;
1593 }
1594 rc = reset_line_toggle_dt(&config->reset_timer);
1595 if (rc < 0) {
1596 return rc;
1597 }
1598
1599 /* Initialize UTCPD */
1600 rc = numaker_utcpd_init_startup(dev);
1601 if (rc < 0) {
1602 return rc;
1603 }
1604
1605 if (config->eadc.spec_vbus != NULL || config->eadc.spec_vconn != NULL) {
1606 /* Initialize EADC */
1607 rc = numaker_eadc_init_startup(dev);
1608 if (rc < 0) {
1609 return rc;
1610 }
1611
1612 /* Initialize Timer */
1613 rc = numaker_timer_init_startup(dev);
1614 if (rc < 0) {
1615 return rc;
1616 }
1617 }
1618
1619 return numaker_tcpc_init_recycle(dev);
1620 }
1621
1622 /**
1623 * @brief Reads the status of the CC lines
1624 *
1625 * @retval 0 on success
1626 * @retval -EIO on failure
1627 */
numaker_tcpc_get_cc(const struct device * dev,enum tc_cc_voltage_state * cc1,enum tc_cc_voltage_state * cc2)1628 static int numaker_tcpc_get_cc(const struct device *dev, enum tc_cc_voltage_state *cc1,
1629 enum tc_cc_voltage_state *cc2)
1630 {
1631 const struct numaker_tcpc_config *const config = dev->config;
1632 UTCPD_T *utcpd_base = config->utcpd_base;
1633 uint32_t rolctl = NUMAKER_UTCPD_REG_READ_BY_NAME(dev, ROLCTL);
1634 uint32_t rolctl_cc1 = rolctl & UTCPD_ROLCTL_CC1_Msk;
1635 uint32_t rolctl_cc2 = rolctl & UTCPD_ROLCTL_CC2_Msk;
1636 uint32_t ccsts = NUMAKER_UTCPD_REG_READ_BY_NAME(dev, CCSTS);
1637 uint32_t ccsts_cc1state = ccsts & UTCPD_CCSTS_CC1STATE_Msk;
1638 uint32_t ccsts_cc2state = ccsts & UTCPD_CCSTS_CC2STATE_Msk;
1639 uint32_t ccsts_conrlt = ccsts & UTCPD_CCSTS_CONRLT_Msk;
1640
1641 /* CC1 */
1642 if (rolctl_cc1 == UTCPD_ROLECTL_CC1_RP || ccsts_conrlt == UTCPD_CONN_RESULT_RP) {
1643 switch (ccsts_cc1state) {
1644 case UTCPD_CCSTS_CC1STATE_SRC_RA:
1645 *cc1 = TC_CC_VOLT_RA;
1646 break;
1647 case UTCPD_CCSTS_CC1STATE_SRC_RD:
1648 *cc1 = TC_CC_VOLT_RD;
1649 break;
1650 default:
1651 *cc1 = TC_CC_VOLT_OPEN;
1652 }
1653 } else if (rolctl_cc1 == UTCPD_ROLECTL_CC1_RD || ccsts_conrlt == UTCPD_CONN_RESULT_RD) {
1654 switch (ccsts_cc1state) {
1655 case UTCPD_CCSTS_CC1STATE_SNK_DEF:
1656 *cc1 = TC_CC_VOLT_RP_DEF;
1657 break;
1658 case UTCPD_CCSTS_CC1STATE_SNK_1P5A:
1659 *cc1 = TC_CC_VOLT_RP_1A5;
1660 break;
1661 case UTCPD_CCSTS_CC1STATE_SNK_3A:
1662 *cc1 = TC_CC_VOLT_RP_3A0;
1663 break;
1664 default:
1665 *cc1 = TC_CC_VOLT_OPEN;
1666 }
1667 } else {
1668 *cc1 = TC_CC_VOLT_OPEN;
1669 }
1670
1671 /* CC2 */
1672 if (rolctl_cc2 == UTCPD_ROLECTL_CC2_RP || ccsts_conrlt == UTCPD_CONN_RESULT_RP) {
1673 switch (ccsts_cc2state) {
1674 case UTCPD_CCSTS_CC2STATE_SRC_RA:
1675 *cc2 = TC_CC_VOLT_RA;
1676 break;
1677 case UTCPD_CCSTS_CC2STATE_SRC_RD:
1678 *cc2 = TC_CC_VOLT_RD;
1679 break;
1680 default:
1681 *cc2 = TC_CC_VOLT_OPEN;
1682 }
1683 } else if (rolctl_cc2 == UTCPD_ROLECTL_CC2_RD || ccsts_conrlt == UTCPD_CONN_RESULT_RD) {
1684 switch (ccsts_cc2state) {
1685 case UTCPD_CCSTS_CC2STATE_SNK_DEF:
1686 *cc2 = TC_CC_VOLT_RP_DEF;
1687 break;
1688 case UTCPD_CCSTS_CC2STATE_SNK_1P5A:
1689 *cc2 = TC_CC_VOLT_RP_1A5;
1690 break;
1691 case UTCPD_CCSTS_CC2STATE_SNK_3A:
1692 *cc2 = TC_CC_VOLT_RP_3A0;
1693 break;
1694 default:
1695 *cc2 = TC_CC_VOLT_OPEN;
1696 }
1697 } else {
1698 *cc2 = TC_CC_VOLT_OPEN;
1699 }
1700
1701 return 0;
1702 }
1703
1704 /**
1705 * @brief Sets the value of CC pull up resistor used when operating as a Source
1706 *
1707 * @retval 0 on success
1708 * @retval -EIO on failure
1709 */
numaker_tcpc_select_rp_value(const struct device * dev,enum tc_rp_value rp)1710 static int numaker_tcpc_select_rp_value(const struct device *dev, enum tc_rp_value rp)
1711 {
1712 struct numaker_tcpc_data *data = dev->data;
1713
1714 data->rp = rp;
1715
1716 return 0;
1717 }
1718
1719 /**
1720 * @brief Gets the value of the CC pull up resistor used when operating as a Source
1721 *
1722 * @retval 0 on success
1723 * @retval -EIO on failure
1724 */
numaker_tcpc_get_rp_value(const struct device * dev,enum tc_rp_value * rp)1725 static int numaker_tcpc_get_rp_value(const struct device *dev, enum tc_rp_value *rp)
1726 {
1727 struct numaker_tcpc_data *data = dev->data;
1728
1729 *rp = data->rp;
1730
1731 return 0;
1732 }
1733
1734 /**
1735 * @brief Sets the CC pull resistor and sets the role as either Source or Sink
1736 *
1737 * @retval 0 on success
1738 * @retval -EIO on failure
1739 */
numaker_tcpc_set_cc(const struct device * dev,enum tc_cc_pull pull)1740 static int numaker_tcpc_set_cc(const struct device *dev, enum tc_cc_pull pull)
1741 {
1742 const struct numaker_tcpc_config *const config = dev->config;
1743 struct numaker_tcpc_data *data = dev->data;
1744 UTCPD_T *utcpd_base = config->utcpd_base;
1745 int rc;
1746 uint32_t rolctl = 0;
1747
1748 /* Disable Dead Battery mode if it is active, so that
1749 * internal Rd/Rp gets controlled by to UTCPD.ROLCTL
1750 * from Dead Battery circuit.
1751 */
1752 if (numaker_utcpd_deadbattery_query_enable(dev)) {
1753 rc = numaker_utcpd_deadbattery_set_enable(dev, false);
1754 if (rc < 0) {
1755 return rc;
1756 }
1757 }
1758
1759 /* Rp value: default, 1.5A, or 3.0A */
1760 switch (data->rp) {
1761 case TC_RP_USB:
1762 rolctl |= UTCPD_ROLECTL_RPVALUE_DEF;
1763 break;
1764
1765 case TC_RP_1A5:
1766 rolctl |= UTCPD_ROLECTL_RPVALUE_1P5A;
1767 break;
1768
1769 case TC_RP_3A0:
1770 rolctl |= UTCPD_ROLECTL_RPVALUE_3A;
1771 break;
1772
1773 default:
1774 LOG_ERR("Invalid Rp value: %d", data->rp);
1775 return -EINVAL;
1776 }
1777
1778 /* Pull on both CC1/CC2, determining source/sink role */
1779 switch (pull) {
1780 case TC_CC_RA:
1781 rolctl |= (UTCPD_ROLECTL_CC1_RA | UTCPD_ROLECTL_CC2_RA);
1782 break;
1783
1784 case TC_CC_RP:
1785 rolctl |= (UTCPD_ROLECTL_CC1_RP | UTCPD_ROLECTL_CC2_RP);
1786 break;
1787
1788 case TC_CC_RD:
1789 rolctl |= (UTCPD_ROLECTL_CC1_RD | UTCPD_ROLECTL_CC2_RD);
1790 break;
1791
1792 case TC_CC_OPEN:
1793 rolctl |= (UTCPD_ROLECTL_CC1_OPEN | UTCPD_ROLECTL_CC2_OPEN);
1794 break;
1795
1796 default:
1797 LOG_ERR("Invalid pull: %d", pull);
1798 return -EINVAL;
1799 }
1800
1801 /* Update CC1/CC2 pull values */
1802 rc = NUMAKER_UTCPD_REG_WRITE_BY_NAME(dev, ROLCTL, rolctl);
1803 if (rc < 0) {
1804 return rc;
1805 }
1806
1807 return 0;
1808 }
1809
1810 /**
1811 * @brief Sets a callback that can enable or discharge VCONN if the TCPC is
1812 * unable to or the system is configured in a way that does not use
1813 * the VCONN control capabilities of the TCPC
1814 */
numaker_tcpc_set_vconn_discharge_cb(const struct device * dev,tcpc_vconn_discharge_cb_t cb)1815 static void numaker_tcpc_set_vconn_discharge_cb(const struct device *dev,
1816 tcpc_vconn_discharge_cb_t cb)
1817 {
1818 struct numaker_tcpc_data *data = dev->data;
1819
1820 data->dpm.vconn_discharge_cb = cb;
1821 }
1822
1823 /**
1824 * @brief Sets a callback that can enable or disable VCONN if the TCPC is
1825 * unable to or the system is configured in a way that does not use
1826 * the VCONN control capabilities of the TCPC
1827 */
numaker_tcpc_set_vconn_cb(const struct device * dev,tcpc_vconn_control_cb_t vconn_cb)1828 static void numaker_tcpc_set_vconn_cb(const struct device *dev, tcpc_vconn_control_cb_t vconn_cb)
1829 {
1830 struct numaker_tcpc_data *data = dev->data;
1831
1832 data->dpm.vconn_cb = vconn_cb;
1833 }
1834
1835 /**
1836 * @brief Discharges VCONN
1837 *
1838 * @retval 0 on success
1839 * @retval -EIO on failure
1840 */
numaker_tcpc_vconn_discharge(const struct device * dev,bool enable)1841 static int numaker_tcpc_vconn_discharge(const struct device *dev, bool enable)
1842 {
1843 const struct numaker_tcpc_config *const config = dev->config;
1844 struct numaker_tcpc_data *data = dev->data;
1845 UTCPD_T *utcpd_base = config->utcpd_base;
1846 const struct gpio_dt_spec *vconn_discharge_spec = &config->utcpd.gpios.vconn_discharge;
1847 uint32_t ctl = NUMAKER_UTCPD_REG_READ_BY_NAME(dev, CTL);
1848 uint32_t vcdgctl = NUMAKER_UTCPD_REG_READ_BY_NAME(dev, VCDGCTL);
1849 enum tc_cc_polarity polarity =
1850 (ctl & UTCPD_CTL_ORIENT_Msk) ? TC_POLARITY_CC2 : TC_POLARITY_CC1;
1851
1852 /* Use DPM supplied VCONN discharge */
1853 if (data->dpm.vconn_discharge_cb) {
1854 return data->dpm.vconn_discharge_cb(dev, polarity, enable);
1855 }
1856
1857 /* Use GPIO VCONN discharge */
1858 if (vconn_discharge_spec->port != NULL) {
1859 return gpio_pin_set_dt(vconn_discharge_spec, enable);
1860 }
1861
1862 /* Use UTCPD VCONN discharge */
1863 if (enable) {
1864 vcdgctl |= UTCPD_VCDGCTL_VCDGEN_Msk;
1865 } else {
1866 vcdgctl &= ~UTCPD_VCDGCTL_VCDGEN_Msk;
1867 }
1868 return NUMAKER_UTCPD_REG_WRITE_BY_NAME(dev, VCDGCTL, vcdgctl);
1869 }
1870
1871 /**
1872 * @brief Enables or disables VCONN
1873 *
1874 * @retval 0 on success
1875 * @retval -EIO on failure
1876 */
numaker_tcpc_set_vconn(const struct device * dev,bool enable)1877 static int numaker_tcpc_set_vconn(const struct device *dev, bool enable)
1878 {
1879 const struct numaker_tcpc_config *const config = dev->config;
1880 struct numaker_tcpc_data *data = dev->data;
1881 UTCPD_T *utcpd_base = config->utcpd_base;
1882 uint32_t pwrctl = NUMAKER_UTCPD_REG_READ_BY_NAME(dev, PWRCTL);
1883 uint32_t ctl = NUMAKER_UTCPD_REG_READ_BY_NAME(dev, CTL);
1884 enum tc_cc_polarity polarity =
1885 (ctl & UTCPD_CTL_ORIENT_Msk) ? TC_POLARITY_CC2 : TC_POLARITY_CC1;
1886
1887 /* Use DPM supplied VCONN */
1888 if (data->dpm.vconn_cb) {
1889 return data->dpm.vconn_cb(dev, polarity, enable);
1890 }
1891
1892 /* Use UTCPD VCONN */
1893 if (enable) {
1894 pwrctl |= UTCPD_PWRCTL_VCEN_Msk;
1895 } else {
1896 pwrctl &= ~UTCPD_PWRCTL_VCEN_Msk;
1897 }
1898 return NUMAKER_UTCPD_REG_WRITE_BY_NAME(dev, PWRCTL, pwrctl);
1899 }
1900
1901 /**
1902 * @brief Sets the Power and Data Role of the PD message header
1903 *
1904 * @retval 0 on success
1905 * @retval -EIO on failure
1906 */
numaker_tcpc_set_roles(const struct device * dev,enum tc_power_role power_role,enum tc_data_role data_role)1907 static int numaker_tcpc_set_roles(const struct device *dev, enum tc_power_role power_role,
1908 enum tc_data_role data_role)
1909 {
1910 const struct numaker_tcpc_config *const config = dev->config;
1911 UTCPD_T *utcpd_base = config->utcpd_base;
1912 uint32_t mshead = NUMAKER_UTCPD_REG_READ_BY_NAME(dev, MSHEAD);
1913
1914 /* Power role for auto-reply GoodCRC */
1915 mshead &= ~UTCPD_MSHEAD_PWRROL_Msk;
1916 if (power_role == TC_ROLE_SOURCE) {
1917 mshead |= UTCPD_MHINFO_PROLE_SRC;
1918 } else {
1919 mshead |= UTCPD_MHINFO_PROLE_SNK;
1920 }
1921
1922 /* Data role for auto-reply GoodCRC */
1923 mshead &= ~UTCPD_MSHEAD_DAROL_Msk;
1924 if (data_role == TC_ROLE_DFP) {
1925 mshead |= UTCPD_MHINFO_DROLE_DFP;
1926 } else {
1927 mshead |= UTCPD_MHINFO_DROLE_UFP;
1928 }
1929
1930 /* Message Header for auto-reply GoodCRC */
1931 return NUMAKER_UTCPD_REG_WRITE_BY_NAME(dev, MSHEAD, mshead);
1932 }
1933
1934 /**
1935 * @brief Retrieves the Power Delivery message from the TCPC.
1936 * If buf is NULL, then only the status is returned, where 0 means there is a message pending and
1937 * -ENODATA means there is no pending message.
1938 *
1939 * @retval Greater or equal to 0 is the number of bytes received if buf parameter is provided
1940 * @retval 0 if there is a message pending and buf parameter is NULL
1941 * @retval -EIO on failure
1942 * @retval -ENODATA if no message is pending
1943 */
numaker_tcpc_get_rx_pending_msg(const struct device * dev,struct pd_msg * msg)1944 static int numaker_tcpc_get_rx_pending_msg(const struct device *dev, struct pd_msg *msg)
1945 {
1946 struct numaker_tcpc_data *data = dev->data;
1947
1948 /* Rx message pending? */
1949 if (!data->rx_msg_ready) {
1950 return -ENODATA;
1951 }
1952
1953 /* Query status only? */
1954 if (msg == NULL) {
1955 return 0;
1956 }
1957
1958 /* Dequeue Rx FIFO */
1959 *msg = data->rx_msg;
1960 data->rx_msg_ready = false;
1961
1962 /* Indicate Rx message returned */
1963 return 1;
1964 }
1965
1966 /**
1967 * @brief Enables the reception of SOP* message types
1968 *
1969 * @retval 0 on success
1970 * @retval -EIO on failure
1971 */
numaker_tcpc_set_rx_enable(const struct device * dev,bool enable)1972 static int numaker_tcpc_set_rx_enable(const struct device *dev, bool enable)
1973 {
1974 const struct numaker_tcpc_config *const config = dev->config;
1975 struct numaker_tcpc_data *data = dev->data;
1976 UTCPD_T *utcpd_base = config->utcpd_base;
1977 uint32_t dtrxevnt = 0;
1978
1979 /* Enable receive */
1980 if (enable) {
1981 /* Enable receive of SOP messages */
1982 dtrxevnt |= UTCPD_DTRXEVNT_SOPEN_Msk;
1983
1984 /* Enable receive of SOP'/SOP'' messages */
1985 if (data->rx_sop_prime_enabled) {
1986 dtrxevnt |= UTCPD_DTRXEVNT_SOPPEN_Msk | UTCPD_DTRXEVNT_SOPPPEN_Msk;
1987 }
1988
1989 /* Enable receive of Hard Reset */
1990 dtrxevnt |= UTCPD_DTRXEVNT_HRSTEN_Msk;
1991
1992 /* Don't enable receive of Cable Reset for not being Cable Plug */
1993 }
1994 return NUMAKER_UTCPD_REG_WRITE_BY_NAME(dev, DTRXEVNT, dtrxevnt);
1995 }
1996
1997 /**
1998 * @brief Sets the polarity of the CC lines
1999 *
2000 * @retval 0 on success
2001 * @retval -EIO on failure
2002 */
numaker_tcpc_set_cc_polarity(const struct device * dev,enum tc_cc_polarity polarity)2003 static int numaker_tcpc_set_cc_polarity(const struct device *dev, enum tc_cc_polarity polarity)
2004 {
2005 const struct numaker_tcpc_config *const config = dev->config;
2006 UTCPD_T *utcpd_base = config->utcpd_base;
2007 uint32_t ctl = NUMAKER_UTCPD_REG_READ_BY_NAME(dev, CTL);
2008
2009 /* Update CC polarity */
2010 switch (polarity) {
2011 case TC_POLARITY_CC1:
2012 ctl &= ~UTCPD_CTL_ORIENT_Msk;
2013 break;
2014
2015 case TC_POLARITY_CC2:
2016 ctl |= UTCPD_CTL_ORIENT_Msk;
2017 break;
2018
2019 default:
2020 LOG_ERR("Invalid CC polarity: %d", polarity);
2021 return -EINVAL;
2022 }
2023 return NUMAKER_UTCPD_REG_WRITE_BY_NAME(dev, CTL, ctl);
2024 }
2025
2026 /**
2027 * @brief Transmits a Power Delivery message
2028 *
2029 * @retval 0 on success
2030 * @retval -EIO on failure
2031 */
numaker_tcpc_transmit_data(const struct device * dev,struct pd_msg * msg)2032 static int numaker_tcpc_transmit_data(const struct device *dev, struct pd_msg *msg)
2033 {
2034 const struct numaker_tcpc_config *const config = dev->config;
2035 UTCPD_T *utcpd_base = config->utcpd_base;
2036 int rc;
2037 uint32_t txctl;
2038 uint32_t txctl_retrycnt;
2039 uint32_t txctl_txstype;
2040
2041 /* Not support Unchunked Extended Message exceeding PD_CONVERT_PD_HEADER_COUNT_TO_BYTES */
2042 if (msg->len > (PD_MAX_EXTENDED_MSG_LEGACY_LEN + 2)) {
2043 LOG_ERR("Not support Unchunked Extended Message exceeding "
2044 "PD_CONVERT_PD_HEADER_COUNT_TO_BYTES: %d",
2045 msg->len);
2046 return -EIO;
2047 }
2048
2049 /* txbcnt = 2 (Message Header) + Tx data byte count */
2050 rc = NUMAKER_UTCPD_REG_WRITE_BY_NAME(dev, TXBCNT, msg->len + 2);
2051 if (rc < 0) {
2052 return rc;
2053 }
2054
2055 /* Tx header */
2056 rc = NUMAKER_UTCPD_REG_WRITE_BY_NAME(dev, TXHEAD, msg->header.raw_value);
2057 if (rc < 0) {
2058 return rc;
2059 }
2060
2061 /* Tx data */
2062 rc = numaker_utcpd_tx_write_data(dev, msg->data, msg->len);
2063 if (rc < 0) {
2064 return rc;
2065 }
2066
2067 /* Tx control */
2068 if (msg->type < PD_PACKET_TX_HARD_RESET) {
2069 /* nRetryCount = 2 for PD REV 3.0 */
2070 txctl_retrycnt = 2 << UTCPD_TXCTL_RETRYCNT_Pos;
2071 } else if (msg->type <= PD_PACKET_TX_BIST_MODE_2) {
2072 /* Per TCPCI spec, no retry for non-SOP* transmission */
2073 txctl_retrycnt = 0;
2074 } else {
2075 LOG_ERR("Invalid PD packet type: %d", msg->type);
2076 return -EINVAL;
2077 }
2078 /* NOTE: Needn't extra cast for UTCPD_TXCTL.TXSTYPE aligning with pd_packet_type */
2079 txctl_txstype = ((uint32_t)msg->type) << UTCPD_TXCTL_TXSTYPE_Pos;
2080 txctl = txctl_retrycnt | txctl_txstype;
2081 return NUMAKER_UTCPD_REG_WRITE_BY_NAME(dev, TXCTL, txctl);
2082 }
2083
2084 /**
2085 * @brief Dump a set of TCPC registers
2086 *
2087 * @retval 0 on success
2088 * @retval -EIO on failure
2089 */
numaker_tcpc_dump_std_reg(const struct device * dev)2090 static int numaker_tcpc_dump_std_reg(const struct device *dev)
2091 {
2092 return numaker_utcpd_dump_regs(dev);
2093 }
2094
2095 /**
2096 * @brief Queries the current sinking state of the TCPC
2097 *
2098 * @retval true if sinking power
2099 * @retval false if not sinking power
2100 */
numaker_tcpc_get_snk_ctrl(const struct device * dev)2101 static int numaker_tcpc_get_snk_ctrl(const struct device *dev)
2102 {
2103 const struct numaker_tcpc_config *const config = dev->config;
2104 UTCPD_T *utcpd_base = config->utcpd_base;
2105 uint32_t pwrsts = NUMAKER_UTCPD_REG_READ_BY_NAME(dev, PWRSTS);
2106
2107 return (pwrsts & UTCPD_PWRSTS_SKVB_Msk) ? true : false;
2108 }
2109
2110 /**
2111 * @brief Queries the current sourcing state of the TCPC
2112 *
2113 * @retval true if sourcing power
2114 * @retval false if not sourcing power
2115 */
numaker_tcpc_get_src_ctrl(const struct device * dev)2116 static int numaker_tcpc_get_src_ctrl(const struct device *dev)
2117 {
2118 const struct numaker_tcpc_config *const config = dev->config;
2119 UTCPD_T *utcpd_base = config->utcpd_base;
2120 uint32_t pwrsts = NUMAKER_UTCPD_REG_READ_BY_NAME(dev, PWRSTS);
2121
2122 return (pwrsts & (UTCPD_PWRSTS_SRVB_Msk | UTCPD_PWRSTS_SRHV_Msk)) ? true : false;
2123 }
2124
2125 /**
2126 * @brief Enables the reception of SOP Prime messages
2127 *
2128 * @retval 0 on success
2129 * @retval -EIO on failure
2130 */
numaker_tcpc_sop_prime_enable(const struct device * dev,bool enable)2131 static int numaker_tcpc_sop_prime_enable(const struct device *dev, bool enable)
2132 {
2133 struct numaker_tcpc_data *data = dev->data;
2134
2135 data->rx_sop_prime_enabled = enable;
2136
2137 return 0;
2138 }
2139
2140 /**
2141 * @brief Controls the BIST Mode of the TCPC. It disables RX alerts while the
2142 * mode is active.
2143 *
2144 * @retval 0 on success
2145 * @retval -EIO on failure
2146 */
numaker_tcpc_set_bist_test_mode(const struct device * dev,bool enable)2147 static int numaker_tcpc_set_bist_test_mode(const struct device *dev, bool enable)
2148 {
2149 return numaker_utcpd_bist_test_mode_set_enable(dev, enable);
2150 }
2151
2152 /**
2153 * @brief Sets the alert function that's called when an interrupt is triggered
2154 * due to an alert bit
2155 *
2156 * @retval 0 on success
2157 */
numaker_tcpc_set_alert_handler_cb(const struct device * dev,tcpc_alert_handler_cb_t alert_handler,void * alert_data)2158 static int numaker_tcpc_set_alert_handler_cb(const struct device *dev,
2159 tcpc_alert_handler_cb_t alert_handler,
2160 void *alert_data)
2161 {
2162 struct numaker_tcpc_data *data = dev->data;
2163
2164 data->tcpc_alert.handler = alert_handler;
2165 data->tcpc_alert.data = alert_data;
2166
2167 return 0;
2168 }
2169
2170 /* Functions below with name pattern "*_tcpc_ppc_*" are to invoke by NuMaker PPC driver */
2171
numaker_tcpc_ppc_is_dead_battery_mode(const struct device * dev)2172 int numaker_tcpc_ppc_is_dead_battery_mode(const struct device *dev)
2173 {
2174 return numaker_utcpd_deadbattery_query_enable(dev);
2175 }
2176
numaker_tcpc_ppc_exit_dead_battery_mode(const struct device * dev)2177 int numaker_tcpc_ppc_exit_dead_battery_mode(const struct device *dev)
2178 {
2179 return numaker_utcpd_deadbattery_set_enable(dev, false);
2180 }
2181
numaker_tcpc_ppc_is_vbus_source(const struct device * dev)2182 int numaker_tcpc_ppc_is_vbus_source(const struct device *dev)
2183 {
2184 return numaker_utcpd_vbus_is_source(dev);
2185 }
2186
numaker_tcpc_ppc_is_vbus_sink(const struct device * dev)2187 int numaker_tcpc_ppc_is_vbus_sink(const struct device *dev)
2188 {
2189 return numaker_utcpd_vbus_is_sink(dev);
2190 }
2191
numaker_tcpc_ppc_set_snk_ctrl(const struct device * dev,bool enable)2192 int numaker_tcpc_ppc_set_snk_ctrl(const struct device *dev, bool enable)
2193 {
2194 const struct numaker_tcpc_config *const config = dev->config;
2195 UTCPD_T *utcpd_base = config->utcpd_base;
2196 uint32_t cmd;
2197
2198 if (enable) {
2199 cmd = UTCPD_CMD_SINK_VBUS;
2200 } else {
2201 cmd = UTCPD_CMD_DISABLE_SINK_VBUS;
2202 }
2203 return NUMAKER_UTCPD_REG_WRITE_BY_NAME(dev, CMD, cmd);
2204 }
2205
numaker_tcpc_ppc_set_src_ctrl(const struct device * dev,bool enable)2206 int numaker_tcpc_ppc_set_src_ctrl(const struct device *dev, bool enable)
2207 {
2208 const struct numaker_tcpc_config *const config = dev->config;
2209 UTCPD_T *utcpd_base = config->utcpd_base;
2210 uint32_t cmd;
2211
2212 if (enable) {
2213 /* NOTE: Source VBUS high voltage (UTCPD_CMD_SRC_VBUS_NONDEFAULT) N/A */
2214 cmd = UTCPD_CMD_SRC_VBUS_DEFAULT;
2215 } else {
2216 cmd = UTCPD_CMD_DISABLE_SRC_VBUS;
2217 }
2218 return NUMAKER_UTCPD_REG_WRITE_BY_NAME(dev, CMD, cmd);
2219 }
2220
numaker_tcpc_ppc_set_vbus_discharge(const struct device * dev,bool enable)2221 int numaker_tcpc_ppc_set_vbus_discharge(const struct device *dev, bool enable)
2222 {
2223 return numaker_utcpd_vbus_set_discharge(dev, enable);
2224 }
2225
numaker_tcpc_ppc_is_vbus_present(const struct device * dev)2226 int numaker_tcpc_ppc_is_vbus_present(const struct device *dev)
2227 {
2228 return numaker_utcpd_vbus_is_present(dev);
2229 }
2230
numaker_tcpc_ppc_set_event_handler(const struct device * dev,usbc_ppc_event_cb_t event_handler,void * event_data)2231 int numaker_tcpc_ppc_set_event_handler(const struct device *dev, usbc_ppc_event_cb_t event_handler,
2232 void *event_data)
2233 {
2234 struct numaker_tcpc_data *data = dev->data;
2235
2236 data->ppc_event.handler = event_handler;
2237 data->ppc_event.data = event_data;
2238
2239 return 0;
2240 }
2241
numaker_tcpc_ppc_dump_regs(const struct device * dev)2242 int numaker_tcpc_ppc_dump_regs(const struct device *dev)
2243 {
2244 return numaker_utcpd_dump_regs(dev);
2245 }
2246
2247 /* End of "*_tcpc_ppc_*" functions */
2248
2249 /* Functions below with name pattern "*_tcpc_vbus_*" are to invoke by NuMaker VBUS driver */
2250
numaker_tcpc_vbus_check_level(const struct device * dev,enum tc_vbus_level level)2251 bool numaker_tcpc_vbus_check_level(const struct device *dev, enum tc_vbus_level level)
2252 {
2253 const struct numaker_tcpc_config *const config = dev->config;
2254 UTCPD_T *utcpd_base = config->utcpd_base;
2255 uint32_t mv_norm;
2256 int rc = numaker_utcpd_vbus_measure(dev, &mv_norm);
2257 uint32_t pwrsts = NUMAKER_UTCPD_REG_READ_BY_NAME(dev, PWRSTS);
2258
2259 /* Fall back to PWRSTS.VBPS if VBUS measurement by EADC is not available */
2260 switch (level) {
2261 case TC_VBUS_SAFE0V:
2262 return (rc == 0) ? (mv_norm < PD_V_SAFE_0V_MAX_MV)
2263 : !(pwrsts & UTCPD_PWRSTS_VBPS_Msk);
2264 case TC_VBUS_PRESENT:
2265 return (rc == 0) ? (mv_norm >= PD_V_SAFE_5V_MIN_MV)
2266 : (pwrsts & UTCPD_PWRSTS_VBPS_Msk);
2267 case TC_VBUS_REMOVED:
2268 return (rc == 0) ? (mv_norm < TC_V_SINK_DISCONNECT_MAX_MV)
2269 : !(pwrsts & UTCPD_PWRSTS_VBPS_Msk);
2270 }
2271
2272 return false;
2273 }
2274
numaker_tcpc_vbus_measure(const struct device * dev,int * vbus_meas)2275 int numaker_tcpc_vbus_measure(const struct device *dev, int *vbus_meas)
2276 {
2277 int rc;
2278 uint32_t mv;
2279
2280 if (vbus_meas == NULL) {
2281 return -EINVAL;
2282 }
2283 *vbus_meas = 0;
2284
2285 rc = numaker_utcpd_vbus_measure(dev, &mv);
2286 if (rc < 0) {
2287 return rc;
2288 }
2289 *vbus_meas = mv;
2290
2291 return 0;
2292 }
2293
numaker_tcpc_vbus_discharge(const struct device * dev,bool enable)2294 int numaker_tcpc_vbus_discharge(const struct device *dev, bool enable)
2295 {
2296 return numaker_utcpd_vbus_set_discharge(dev, enable);
2297 }
2298
numaker_tcpc_vbus_enable(const struct device * dev,bool enable)2299 int numaker_tcpc_vbus_enable(const struct device *dev, bool enable)
2300 {
2301 /* VBUS measurement is made automatic through Timer-triggered EADC. */
2302 return 0;
2303 }
2304
2305 /* End of "*_tcpc_vbus_*" functions */
2306
2307 static DEVICE_API(tcpc, numaker_tcpc_driver_api) = {
2308 .init = numaker_tcpc_init_recycle,
2309 .get_cc = numaker_tcpc_get_cc,
2310 .select_rp_value = numaker_tcpc_select_rp_value,
2311 .get_rp_value = numaker_tcpc_get_rp_value,
2312 .set_cc = numaker_tcpc_set_cc,
2313 .set_vconn_discharge_cb = numaker_tcpc_set_vconn_discharge_cb,
2314 .set_vconn_cb = numaker_tcpc_set_vconn_cb,
2315 .vconn_discharge = numaker_tcpc_vconn_discharge,
2316 .set_vconn = numaker_tcpc_set_vconn,
2317 .set_roles = numaker_tcpc_set_roles,
2318 .get_rx_pending_msg = numaker_tcpc_get_rx_pending_msg,
2319 .set_rx_enable = numaker_tcpc_set_rx_enable,
2320 .set_cc_polarity = numaker_tcpc_set_cc_polarity,
2321 .transmit_data = numaker_tcpc_transmit_data,
2322 .dump_std_reg = numaker_tcpc_dump_std_reg,
2323 .get_snk_ctrl = numaker_tcpc_get_snk_ctrl,
2324 .get_src_ctrl = numaker_tcpc_get_src_ctrl,
2325 .sop_prime_enable = numaker_tcpc_sop_prime_enable,
2326 .set_bist_test_mode = numaker_tcpc_set_bist_test_mode,
2327 .set_alert_handler_cb = numaker_tcpc_set_alert_handler_cb,
2328 };
2329
2330 /* Same as RESET_DT_SPEC_INST_GET_BY_IDX, except by name */
2331 #define NUMAKER_RESET_DT_SPEC_INST_GET_BY_NAME(inst, name) \
2332 { \
2333 .dev = DEVICE_DT_GET(DT_INST_RESET_CTLR_BY_NAME(inst, name)), \
2334 .id = DT_INST_RESET_CELL_BY_NAME(inst, name, id), \
2335 }
2336
2337 /* Same as GPIO_DT_SPEC_GET_BY_IDX, except by name */
2338 #define NUMAKER_GPIO_DT_SPEC_GET_BY_NAME(node_id, prop, name) \
2339 { \
2340 .port = DEVICE_DT_GET(DT_PHANDLE_BY_NAME(node_id, prop, name)), \
2341 .pin = DT_PHA_BY_NAME(node_id, prop, name, pin), \
2342 .dt_flags = DT_PHA_BY_NAME(node_id, prop, name, flags), \
2343 }
2344
2345 /* Same as GPIO_DT_SPEC_INST_GET_BY_IDX_OR, except by name */
2346 #define NUMAKER_GPIO_DT_SPEC_INST_GET_BY_NAME_OR(inst, prop, name, default_value) \
2347 COND_CODE_1(DT_INST_PROP_HAS_NAME(inst, prop, name), \
2348 (NUMAKER_GPIO_DT_SPEC_GET_BY_NAME(DT_DRV_INST(inst), prop, name)), \
2349 (default_value))
2350
2351 /* Peripheral Clock Control by name */
2352 #define NUMAKER_PCC_INST_GET_BY_NAME(inst, name) \
2353 { \
2354 .subsys_id = NUMAKER_SCC_SUBSYS_ID_PCC, \
2355 .pcc.clk_modidx = DT_INST_CLOCKS_CELL_BY_NAME(inst, name, clock_module_index), \
2356 .pcc.clk_src = DT_INST_CLOCKS_CELL_BY_NAME(inst, name, clock_source), \
2357 .pcc.clk_div = DT_INST_CLOCKS_CELL_BY_NAME(inst, name, clock_divider), \
2358 }
2359
2360 /* UTCPD GPIOs */
2361 #define NUMAKER_UTCPD_GPIOS_INIT(inst) \
2362 { \
2363 .vbus_detect = \
2364 NUMAKER_GPIO_DT_SPEC_GET_BY_NAME(DT_DRV_INST(inst), gpios, vbus_detect), \
2365 .vbus_discharge = NUMAKER_GPIO_DT_SPEC_INST_GET_BY_NAME_OR(inst, gpios, \
2366 vbus_discharge, {0}), \
2367 .vconn_discharge = NUMAKER_GPIO_DT_SPEC_INST_GET_BY_NAME_OR(inst, gpios, \
2368 vconn_discharge, {0}), \
2369 }
2370
2371 /* UTCPD.PINPL.<PIN> cast */
2372 #define NUMAKER_UTCPD_PINPOL_CAST(inst, pin_dt, pin_utcpd) \
2373 (DT_ENUM_HAS_VALUE(DT_DRV_INST(inst), pin_dt, high_active) ? UTCPD_PINPL_##pin_utcpd##_Msk \
2374 : 0)
2375
2376 /* UTCPD.VBVOL.VBSCALE cast */
2377 #define NUMAKER_UTCPD_VBUS_DIVIDE_CAST(inst) NUMAKER_UTCPD_VBUS_DIVIDE_CAST_DIVIDE_20(inst)
2378 /* divide_20 */
2379 #define NUMAKER_UTCPD_VBUS_DIVIDE_CAST_DIVIDE_20(inst) \
2380 COND_CODE_1(DT_ENUM_HAS_VALUE(DT_DRV_INST(inst), vbus_divide, divide_20), \
2381 ({.bit = (0 << UTCPD_VBVOL_VBSCALE_Pos), .value = 20}), \
2382 (NUMAKER_UTCPD_VBUS_DIVIDE_CAST_DIVIDE_10(inst)))
2383 /* divide_10 */
2384 #define NUMAKER_UTCPD_VBUS_DIVIDE_CAST_DIVIDE_10(inst) \
2385 COND_CODE_1(DT_ENUM_HAS_VALUE(DT_DRV_INST(inst), vbus_divide, divide_10), \
2386 ({.bit = (1 << UTCPD_VBVOL_VBSCALE_Pos), .value = 10}), \
2387 (vbus-divide error))
2388
2389 /* UTCPD.PINPL */
2390 #define NUMAKER_UTCPD_PINPL_INIT(inst) \
2391 { \
2392 .bit = NUMAKER_UTCPD_PINPOL_CAST(inst, vconn_overcurrent_event_polarity, VCOCPL) | \
2393 NUMAKER_UTCPD_PINPOL_CAST(inst, vconn_discharge_polarity, VCDGENPL) | \
2394 NUMAKER_UTCPD_PINPOL_CAST(inst, vconn_enable_polarity, VCENPL) | \
2395 NUMAKER_UTCPD_PINPOL_CAST(inst, vbus_overcurrent_event_polarity, VBOCPL) | \
2396 NUMAKER_UTCPD_PINPOL_CAST(inst, vbus_forceoff_event_polarity, FOFFVBPL) | \
2397 NUMAKER_UTCPD_PINPOL_CAST(inst, frs_tx_polarity, TXFRSPL) | \
2398 NUMAKER_UTCPD_PINPOL_CAST(inst, vbus_discharge_enable_polarity, VBDGENPL) | \
2399 NUMAKER_UTCPD_PINPOL_CAST(inst, vbus_sink_enable_polarity, VBSKENPL) | \
2400 NUMAKER_UTCPD_PINPOL_CAST(inst, vbus_source_enable_polarity, VBSRENPL) \
2401 }
2402
2403 /* UTCPD.VBVOL */
2404 #define NUMAKER_UTCPD_VBVOL_INIT(inst) \
2405 { \
2406 .vbscale = NUMAKER_UTCPD_VBUS_DIVIDE_CAST(inst), \
2407 }
2408
2409 #define NUMAKER_UTCPD_INIT(inst) \
2410 { \
2411 .gpios = NUMAKER_UTCPD_GPIOS_INIT(inst), \
2412 .dead_battery = DT_INST_PROP(inst, dead_battery), \
2413 .pinpl = NUMAKER_UTCPD_PINPL_INIT(inst), .vbvol = NUMAKER_UTCPD_VBVOL_INIT(inst), \
2414 }
2415
2416 /* EADC register address is duplicated for easy implementation.
2417 * They must be the same.
2418 */
2419 #define BUILD_ASSERT_NUMAKER_EADC_REG(inst) \
2420 IF_ENABLED(DT_NODE_HAS_PROP(DT_DRV_INST(inst), io_channels), \
2421 (BUILD_ASSERT(DT_INST_REG_ADDR_BY_NAME(inst, eadc) == \
2422 DT_REG_ADDR(DT_INST_IO_CHANNELS_CTLR(inst)));))
2423
2424 #define NUMAKER_EADC_TRGSRC_CAST(inst) \
2425 ((DT_INST_REG_ADDR_BY_NAME(inst, timer) == TIMER0_BASE) ? EADC_TIMER0_TRIGGER \
2426 : (DT_INST_REG_ADDR_BY_NAME(inst, timer) == TIMER1_BASE) ? EADC_TIMER1_TRIGGER \
2427 : (DT_INST_REG_ADDR_BY_NAME(inst, timer) == TIMER2_BASE) ? EADC_TIMER2_TRIGGER \
2428 : (DT_INST_REG_ADDR_BY_NAME(inst, timer) == TIMER3_BASE) ? EADC_TIMER3_TRIGGER \
2429 : NUMAKER_INVALID_VALUE)
2430
2431 #define BUILD_ASSERT_NUMAKER_EADC_TRGSRC_CAST(inst) \
2432 BUILD_ASSERT(NUMAKER_EADC_TRGSRC_CAST(inst) != NUMAKER_INVALID_VALUE, \
2433 "NUMAKER_EADC_TRGSRC_CAST error");
2434
2435 /* Notes on specifying EADC channels
2436 *
2437 * 1. Must be in order of chn_vbus, chn_vconn, etc.
2438 * 2. The front channel can be absent, e.g. only chn_vconn.
2439 * 3. Build assert will check the above rules.
2440 */
2441 #define NUMAKER_EADC_SPEC_GET_BY_IDX_COMMA(node_id, prop, idx) ADC_DT_SPEC_GET_BY_IDX(node_id, idx),
2442
2443 #define NUMAKER_EADC_SPEC_DEFINE(inst) \
2444 IF_ENABLED( \
2445 DT_NODE_HAS_PROP(DT_DRV_INST(inst), io_channels), \
2446 (static const struct adc_dt_spec eadc_specs##inst[] = {DT_FOREACH_PROP_ELEM( \
2447 DT_DRV_INST(inst), io_channels, NUMAKER_EADC_SPEC_GET_BY_IDX_COMMA)};))
2448
2449 /* Note on EADC spec index
2450 *
2451 * These indexes must be integer literal, or meet macro expansion error.
2452 * However, macro expansion just does text replacement, no evaluation.
2453 * To overcome this, UTIL_INC() and friends are invoked to do evaluation
2454 * at preprocess time.
2455 */
2456 #define NUMAKER_EADC_SPEC_IDX_VBUS(inst) 0
2457 #define NUMAKER_EADC_SPEC_IDX_VCONN(inst) \
2458 COND_CODE_1(DT_INST_PROP_HAS_NAME(inst, io_channels, chn_vbus), \
2459 (UTIL_INC(NUMAKER_EADC_SPEC_IDX_VBUS(inst))), \
2460 (NUMAKER_EADC_SPEC_IDX_VBUS(inst)))
2461
2462 #define NUMAKER_EADC_SPEC_PTR_VBUS(inst) \
2463 COND_CODE_1(DT_INST_PROP_HAS_NAME(inst, io_channels, chn_vbus), \
2464 (&eadc_specs##inst[NUMAKER_EADC_SPEC_IDX_VBUS(inst)]), (NULL))
2465 #define NUMAKER_EADC_SPEC_PTR_VCONN(inst) \
2466 COND_CODE_1(DT_INST_PROP_HAS_NAME(inst, io_channels, chn_vconn), \
2467 (&eadc_specs##inst[NUMAKER_EADC_SPEC_IDX_VCONN(inst)]), (NULL))
2468
2469 #define NUMAKER_EADC_DEVICE_BY_NAME(inst, name) \
2470 DEVICE_DT_GET(DT_IO_CHANNELS_CTLR_BY_NAME(DT_DRV_INST(inst), name))
2471 #define NUMAKER_EADC_DEVICE_BY_IDX(inst, idx) \
2472 DEVICE_DT_GET(DT_IO_CHANNELS_CTLR_BY_IDX(DT_DRV_INST(inst), idx))
2473
2474 #define NUMAKER_EADC_INPUT_BY_NAME(inst, name) DT_IO_CHANNELS_INPUT_BY_NAME(DT_DRV_INST(inst), name)
2475 #define NUMAKER_EADC_INPUT_BY_IDX(inst, idx) DT_IO_CHANNELS_INPUT_BY_IDX(DT_DRV_INST(inst), idx)
2476
2477 #define BUILD_ASSERT_NUMAKER_EADC_SPEC_VBUS(inst) \
2478 IF_ENABLED(DT_INST_PROP_HAS_NAME(inst, io_channels, chn_vbus), \
2479 (BUILD_ASSERT(NUMAKER_EADC_DEVICE_BY_NAME(inst, chn_vbus) == \
2480 NUMAKER_EADC_DEVICE_BY_IDX( \
2481 inst, NUMAKER_EADC_SPEC_IDX_VBUS(inst)), \
2482 "EADC device for VBUS error"); \
2483 BUILD_ASSERT(NUMAKER_EADC_INPUT_BY_NAME(inst, chn_vbus) == \
2484 NUMAKER_EADC_INPUT_BY_IDX( \
2485 inst, NUMAKER_EADC_SPEC_IDX_VBUS(inst)), \
2486 "EADC channel for VBUS error");))
2487
2488 #define BUILD_ASSERT_NUMAKER_EADC_SPEC_VCONN(inst) \
2489 IF_ENABLED(DT_INST_PROP_HAS_NAME(inst, io_channels, chn_vconn), \
2490 (BUILD_ASSERT(NUMAKER_EADC_DEVICE_BY_NAME(inst, chn_vconn) == \
2491 NUMAKER_EADC_DEVICE_BY_IDX( \
2492 inst, NUMAKER_EADC_SPEC_IDX_VCONN(inst)), \
2493 "EADC device for VCONN error"); \
2494 BUILD_ASSERT(NUMAKER_EADC_INPUT_BY_NAME(inst, chn_vconn) == \
2495 NUMAKER_EADC_INPUT_BY_IDX( \
2496 inst, NUMAKER_EADC_SPEC_IDX_VCONN(inst)), \
2497 "EADC channel for VCONN error");))
2498
2499 #define NUMAKER_EADC_INIT(inst) \
2500 { \
2501 .spec_vbus = NUMAKER_EADC_SPEC_PTR_VBUS(inst), \
2502 .spec_vconn = NUMAKER_EADC_SPEC_PTR_VCONN(inst), \
2503 .timer_trigger_rate = DT_INST_PROP(inst, adc_measure_timer_trigger_rate), \
2504 .trgsel_vbus = NUMAKER_EADC_TRGSRC_CAST(inst), \
2505 .trgsel_vconn = NUMAKER_EADC_TRGSRC_CAST(inst), \
2506 }
2507
2508 #define NUMAKER_TCPC_INIT(inst) \
2509 PINCTRL_DT_INST_DEFINE(inst); \
2510 \
2511 NUMAKER_EADC_SPEC_DEFINE(inst); \
2512 \
2513 static void numaker_utcpd_irq_config_func_##inst(const struct device *dev) \
2514 { \
2515 IRQ_CONNECT(DT_INST_IRQ_BY_NAME(inst, utcpd, irq), \
2516 DT_INST_IRQ_BY_NAME(inst, utcpd, priority), numaker_utcpd_isr, \
2517 DEVICE_DT_INST_GET(inst), 0); \
2518 \
2519 irq_enable(DT_INST_IRQ_BY_NAME(inst, utcpd, irq)); \
2520 } \
2521 \
2522 static void numaker_utcpd_irq_unconfig_func_##inst(const struct device *dev) \
2523 { \
2524 irq_disable(DT_INST_IRQ_BY_NAME(inst, utcpd, irq)); \
2525 } \
2526 \
2527 static const struct numaker_tcpc_config numaker_tcpc_config_##inst = { \
2528 .utcpd_base = (UTCPD_T *)DT_INST_REG_ADDR_BY_NAME(inst, utcpd), \
2529 .eadc_base = (EADC_T *)DT_INST_REG_ADDR_BY_NAME(inst, eadc), \
2530 .timer_base = (TIMER_T *)DT_INST_REG_ADDR_BY_NAME(inst, timer), \
2531 .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \
2532 .clkctrl_dev = DEVICE_DT_GET(DT_PARENT(DT_INST_CLOCKS_CTLR(inst))), \
2533 .pcc_utcpd = NUMAKER_PCC_INST_GET_BY_NAME(inst, utcpd), \
2534 .pcc_timer = NUMAKER_PCC_INST_GET_BY_NAME(inst, timer), \
2535 .reset_utcpd = NUMAKER_RESET_DT_SPEC_INST_GET_BY_NAME(inst, utcpd), \
2536 .reset_timer = NUMAKER_RESET_DT_SPEC_INST_GET_BY_NAME(inst, timer), \
2537 .irq_config_func_utcpd = numaker_utcpd_irq_config_func_##inst, \
2538 .irq_unconfig_func_utcpd = numaker_utcpd_irq_unconfig_func_##inst, \
2539 .utcpd = NUMAKER_UTCPD_INIT(inst), \
2540 .eadc = NUMAKER_EADC_INIT(inst), \
2541 }; \
2542 \
2543 BUILD_ASSERT_NUMAKER_EADC_REG(inst); \
2544 BUILD_ASSERT_NUMAKER_EADC_TRGSRC_CAST(inst); \
2545 BUILD_ASSERT_NUMAKER_EADC_SPEC_VBUS(inst); \
2546 BUILD_ASSERT_NUMAKER_EADC_SPEC_VCONN(inst); \
2547 \
2548 static struct numaker_tcpc_data numaker_tcpc_data_##inst; \
2549 \
2550 DEVICE_DT_INST_DEFINE(inst, numaker_tcpc_init_startup, NULL, &numaker_tcpc_data_##inst, \
2551 &numaker_tcpc_config_##inst, POST_KERNEL, \
2552 CONFIG_USBC_TCPC_INIT_PRIORITY, &numaker_tcpc_driver_api);
2553
2554 DT_INST_FOREACH_STATUS_OKAY(NUMAKER_TCPC_INIT);
2555