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