1 /*
2  * Copyright (c) 2022 The Chromium OS Authors
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/logging/log.h>
8 LOG_MODULE_DECLARE(usbc_stack, CONFIG_USBC_STACK_LOG_LEVEL);
9 
10 #include "usbc_stack.h"
11 #include "usbc_tc_snk_states_internal.h"
12 #include "usbc_tc_src_states_internal.h"
13 #include "usbc_tc_common_internal.h"
14 #include <zephyr/drivers/usb_c/usbc_ppc.h>
15 
16 static const struct smf_state tc_states[TC_STATE_COUNT];
17 static int tc_init(const struct device *dev);
18 
19 /**
20  * @brief Initializes the state machine and enters the Disabled state
21  */
tc_subsys_init(const struct device * dev)22 void tc_subsys_init(const struct device *dev)
23 {
24 	struct usbc_port_data *data = dev->data;
25 	struct tc_sm_t *tc = data->tc;
26 
27 	/* Save the port device object so states can access it */
28 	tc->dev = dev;
29 
30 	/* Initialize the state machine */
31 	smf_set_initial(SMF_CTX(tc), &tc_states[TC_DISABLED_STATE]);
32 }
33 
34 /**
35  * @brief Runs the Type-C layer
36  */
tc_run(const struct device * dev,const int32_t dpm_request)37 void tc_run(const struct device *dev, const int32_t dpm_request)
38 {
39 	struct usbc_port_data *data = dev->data;
40 	const struct device *tcpc = data->tcpc;
41 	struct tc_sm_t *tc = data->tc;
42 	int ret;
43 
44 	/* These requests are implicitly set by the Device Policy Manager */
45 	if (dpm_request == PRIV_PORT_REQUEST_START) {
46 		data->tc_enabled = true;
47 	} else if (dpm_request == PRIV_PORT_REQUEST_SUSPEND) {
48 		data->tc_enabled = false;
49 		tc_set_state(dev, TC_DISABLED_STATE);
50 	}
51 
52 	switch (data->tc_sm_state) {
53 	case SM_PAUSED:
54 		if (data->tc_enabled == false) {
55 			break;
56 		}
57 	/* fall through */
58 	case SM_INIT:
59 		/* Initialize the Type-C layer */
60 		ret = tc_init(dev);
61 		if (ret != 0 && ret != -EAGAIN) {
62 			/* Transition to Disabled State */
63 			LOG_ERR("Disabling the Type-C Layer");
64 			data->tc_enabled = false;
65 			tc_set_state(dev, TC_DISABLED_STATE);
66 		}
67 
68 		if (ret != 0) {
69 			break;
70 		}
71 
72 		data->tc_sm_state = SM_RUN;
73 	/* fall through */
74 	case SM_RUN:
75 		if (data->tc_enabled == false) {
76 			tc_pd_enable(dev, false);
77 			data->tc_sm_state = SM_PAUSED;
78 			break;
79 		}
80 
81 		/* Sample CC lines */
82 		if (tcpc_get_cc(tcpc, &tc->cc1, &tc->cc2) != 0) {
83 			/* If this function fails, it may mean that the TCPC is in sleep mode or
84 			 * the communication with TCPC has failed, so we can assume that the CC
85 			 * lines are open or existing connection is faulty.
86 			 */
87 			tc->cc1 = TC_CC_VOLT_OPEN;
88 			tc->cc2 = TC_CC_VOLT_OPEN;
89 		}
90 
91 		/* Detect polarity */
92 		tc->cc_polarity = (tc->cc1 > tc->cc2) ? TC_POLARITY_CC1 : TC_POLARITY_CC2;
93 
94 		/* Execute any asyncronous Device Policy Manager Requests */
95 		if (dpm_request == REQUEST_TC_ERROR_RECOVERY) {
96 			/* Transition to Error Recovery State */
97 			tc_set_state(dev, TC_ERROR_RECOVERY_STATE);
98 		} else if (dpm_request == REQUEST_TC_DISABLED) {
99 			/* Transition to Disabled State */
100 			tc_set_state(dev, TC_DISABLED_STATE);
101 		}
102 
103 		/* Run state machine */
104 		smf_run_state(SMF_CTX(tc));
105 	}
106 }
107 
108 /**
109  * @brief Checks if the TC Layer is in an Attached state
110  */
tc_is_in_attached_state(const struct device * dev)111 bool tc_is_in_attached_state(const struct device *dev)
112 {
113 #ifdef CONFIG_USBC_CSM_SINK_ONLY
114 	return (tc_get_state(dev) == TC_ATTACHED_SNK_STATE);
115 #else
116 	return (tc_get_state(dev) == TC_ATTACHED_SRC_STATE);
117 #endif
118 }
119 
120 /**
121  * @brief Initializes the Type-C layer
122  */
tc_init(const struct device * dev)123 static int tc_init(const struct device *dev)
124 {
125 	struct usbc_port_data *data = dev->data;
126 	struct tc_sm_t *tc = data->tc;
127 	const struct device *tcpc = data->tcpc;
128 	int ret;
129 
130 	/* Initialize the timers */
131 	usbc_timer_init(&tc->tc_t_error_recovery, TC_T_ERROR_RECOVERY_SOURCE_MIN_MS);
132 	usbc_timer_init(&tc->tc_t_cc_debounce, TC_T_CC_DEBOUNCE_MAX_MS);
133 	usbc_timer_init(&tc->tc_t_rp_value_change, TC_T_RP_VALUE_CHANGE_MAX_MS);
134 #ifdef CONFIG_USBC_CSM_SOURCE_ONLY
135 	usbc_timer_init(&tc->tc_t_vconn_off, TC_T_VCONN_OFF_MAX_MS);
136 #endif
137 
138 	/* Clear the flags */
139 	tc->flags = ATOMIC_INIT(0);
140 
141 	/* Initialize the TCPC */
142 	ret = tcpc_init(tcpc);
143 	if (ret != 0) {
144 		LOG_ERR("TCPC initialization failed: %d", ret);
145 		return ret;
146 	}
147 
148 #ifdef CONFIG_USBC_CSM_SOURCE_ONLY
149 	/* Stop sourcing VBUS by policy callback and/or TCPC */
150 	ret = usbc_policy_src_en(dev, tcpc, false);
151 	if (ret != 0) {
152 		LOG_ERR("Couldn't disable vbus sourcing: %d", ret);
153 		return ret;
154 	}
155 
156 	/* Disable VBUS sourcing by the PPC */
157 	if (data->ppc != NULL) {
158 		ppc_set_src_ctrl(data->ppc, false);
159 	}
160 
161 	/* Stop sourcing VCONN */
162 	ret = tcpc_set_vconn(tcpc, false);
163 	if (ret != 0 && ret != -ENOTSUP) {
164 		LOG_ERR("Couldn't disable vconn: %d", ret);
165 		return ret;
166 	}
167 #endif
168 
169 	/* Initialize the state machine */
170 	/*
171 	 * Start out in error recovery state so the CC lines are opened for a
172 	 * short while if this is a system reset.
173 	 */
174 	tc_set_state(dev, TC_ERROR_RECOVERY_STATE);
175 
176 	return 0;
177 }
178 
179 /**
180  * @brief Sets a Type-C state
181  */
tc_set_state(const struct device * dev,const enum tc_state_t state)182 void tc_set_state(const struct device *dev, const enum tc_state_t state)
183 {
184 	struct usbc_port_data *data = dev->data;
185 	struct tc_sm_t *tc = data->tc;
186 
187 	__ASSERT(state < ARRAY_SIZE(tc_states), "invalid tc_state %d", state);
188 	smf_set_state(SMF_CTX(tc), &tc_states[state]);
189 }
190 
191 /**
192  * @brief Get the Type-C current state
193  */
tc_get_state(const struct device * dev)194 enum tc_state_t tc_get_state(const struct device *dev)
195 {
196 	struct usbc_port_data *data = dev->data;
197 
198 	return data->tc->ctx.current - &tc_states[0];
199 }
200 
201 /**
202  * @brief Enable Power Delivery
203  */
tc_pd_enable(const struct device * dev,const bool enable)204 void tc_pd_enable(const struct device *dev, const bool enable)
205 {
206 	if (enable) {
207 		prl_start(dev);
208 		pe_start(dev);
209 	} else {
210 		prl_suspend(dev);
211 		pe_suspend(dev);
212 	}
213 }
214 
215 /**
216  * @brief TCPC CC/Rp management
217  */
tc_select_src_collision_rp(const struct device * dev,enum tc_rp_value rp)218 void tc_select_src_collision_rp(const struct device *dev, enum tc_rp_value rp)
219 {
220 	struct usbc_port_data *data = dev->data;
221 	const struct device *tcpc = data->tcpc;
222 	int ret;
223 
224 	/* Select Rp value */
225 	ret = tcpc_select_rp_value(tcpc, rp);
226 	if (ret != 0 && ret != -ENOTSUP) {
227 		LOG_ERR("Couldn't set Rp value to %d: %d", rp, ret);
228 		tc_set_state(dev, TC_ERROR_RECOVERY_STATE);
229 		return;
230 	}
231 
232 	/* Place Rp on CC lines */
233 	ret = tcpc_set_cc(tcpc, TC_CC_RP);
234 	if (ret != 0) {
235 		LOG_ERR("Couldn't set CC lines to Rp: %d", ret);
236 		tc_set_state(dev, TC_ERROR_RECOVERY_STATE);
237 	}
238 }
239 
240 /**
241  * @brief CC Open Entry
242  */
tc_cc_open_entry(void * obj)243 static void tc_cc_open_entry(void *obj)
244 {
245 	struct tc_sm_t *tc = (struct tc_sm_t *)obj;
246 	const struct device *dev = tc->dev;
247 	struct usbc_port_data *data = dev->data;
248 	const struct device *tcpc = data->tcpc;
249 	int ret;
250 
251 	tc->cc_voltage = TC_CC_VOLT_OPEN;
252 
253 	/* Disable VCONN */
254 	ret = tcpc_set_vconn(tcpc, false);
255 	if (ret != 0 && ret != -ENOSYS) {
256 		LOG_ERR("Couldn't disable vconn: %d", ret);
257 		tc_set_state(dev, TC_ERROR_RECOVERY_STATE);
258 		return;
259 	}
260 
261 	/* Open CC lines */
262 	ret = tcpc_set_cc(tcpc, TC_CC_OPEN);
263 	if (ret != 0) {
264 		LOG_ERR("Couldn't set CC lines to open: %d", ret);
265 		tc_set_state(dev, TC_ERROR_RECOVERY_STATE);
266 	}
267 }
268 
269 /**
270  * @brief Disabled Entry
271  */
tc_disabled_entry(void * obj)272 static void tc_disabled_entry(void *obj)
273 {
274 	LOG_INF("Disabled");
275 }
276 
277 /**
278  * @brief Disabled Run
279  */
tc_disabled_run(void * obj)280 static void tc_disabled_run(void *obj)
281 {
282 	/* Do nothing */
283 }
284 
285 /**
286  * @brief ErrorRecovery Entry
287  */
tc_error_recovery_entry(void * obj)288 static void tc_error_recovery_entry(void *obj)
289 {
290 	struct tc_sm_t *tc = (struct tc_sm_t *)obj;
291 
292 	LOG_INF("ErrorRecovery");
293 
294 	/* Start tErrorRecovery timer */
295 	usbc_timer_start(&tc->tc_t_error_recovery);
296 }
297 
298 /**
299  * @brief ErrorRecovery Run
300  */
tc_error_recovery_run(void * obj)301 static void tc_error_recovery_run(void *obj)
302 {
303 	struct tc_sm_t *tc = (struct tc_sm_t *)obj;
304 	const struct device *dev = tc->dev;
305 
306 	/* Wait for expiry */
307 	if (usbc_timer_expired(&tc->tc_t_error_recovery) == false) {
308 		return;
309 	}
310 
311 #ifdef CONFIG_USBC_CSM_SINK_ONLY
312 	/* Transition to Unattached.SNK */
313 	tc_set_state(dev, TC_UNATTACHED_SNK_STATE);
314 #else
315 	/* Transition to Unattached.SRC */
316 	tc_set_state(dev, TC_UNATTACHED_SRC_STATE);
317 #endif
318 }
319 
320 /**
321  * @brief Type-C State Table
322  */
323 static const struct smf_state tc_states[TC_STATE_COUNT] = {
324 	/* Super States */
325 	[TC_CC_OPEN_SUPER_STATE] = SMF_CREATE_STATE(
326 		tc_cc_open_entry,
327 		NULL,
328 		NULL,
329 		NULL,
330 		NULL),
331 #ifdef CONFIG_USBC_CSM_SINK_ONLY
332 	[TC_CC_RD_SUPER_STATE] = SMF_CREATE_STATE(
333 		tc_cc_rd_entry,
334 		NULL,
335 		NULL,
336 		NULL,
337 		NULL),
338 #else
339 	[TC_CC_RP_SUPER_STATE] = SMF_CREATE_STATE(
340 		tc_cc_rp_entry,
341 		NULL,
342 		NULL,
343 		NULL,
344 		NULL),
345 #endif
346 	/* Normal States */
347 #ifdef CONFIG_USBC_CSM_SINK_ONLY
348 	[TC_UNATTACHED_SNK_STATE] = SMF_CREATE_STATE(
349 		tc_unattached_snk_entry,
350 		tc_unattached_snk_run,
351 		NULL,
352 		&tc_states[TC_CC_RD_SUPER_STATE],
353 		NULL),
354 	[TC_ATTACH_WAIT_SNK_STATE] = SMF_CREATE_STATE(
355 		tc_attach_wait_snk_entry,
356 		tc_attach_wait_snk_run,
357 		tc_attach_wait_snk_exit,
358 		&tc_states[TC_CC_RD_SUPER_STATE],
359 		NULL),
360 	[TC_ATTACHED_SNK_STATE] = SMF_CREATE_STATE(
361 		tc_attached_snk_entry,
362 		tc_attached_snk_run,
363 		tc_attached_snk_exit,
364 		NULL,
365 		NULL),
366 #else
367 	[TC_UNATTACHED_SRC_STATE] = SMF_CREATE_STATE(
368 		tc_unattached_src_entry,
369 		tc_unattached_src_run,
370 		NULL,
371 		&tc_states[TC_CC_RP_SUPER_STATE],
372 		NULL),
373 	[TC_UNATTACHED_WAIT_SRC_STATE] = SMF_CREATE_STATE(
374 		tc_unattached_wait_src_entry,
375 		tc_unattached_wait_src_run,
376 		tc_unattached_wait_src_exit,
377 		NULL,
378 		NULL),
379 	[TC_ATTACH_WAIT_SRC_STATE] = SMF_CREATE_STATE(
380 		tc_attach_wait_src_entry,
381 		tc_attach_wait_src_run,
382 		tc_attach_wait_src_exit,
383 		&tc_states[TC_CC_RP_SUPER_STATE],
384 		NULL),
385 	[TC_ATTACHED_SRC_STATE] = SMF_CREATE_STATE(
386 		tc_attached_src_entry,
387 		tc_attached_src_run,
388 		tc_attached_src_exit,
389 		NULL,
390 		NULL),
391 #endif
392 	[TC_DISABLED_STATE] = SMF_CREATE_STATE(
393 		tc_disabled_entry,
394 		tc_disabled_run,
395 		NULL,
396 		&tc_states[TC_CC_OPEN_SUPER_STATE],
397 		NULL),
398 	[TC_ERROR_RECOVERY_STATE] = SMF_CREATE_STATE(
399 		tc_error_recovery_entry,
400 		tc_error_recovery_run,
401 		NULL,
402 		&tc_states[TC_CC_OPEN_SUPER_STATE],
403 		NULL),
404 };
405 BUILD_ASSERT(ARRAY_SIZE(tc_states) == TC_STATE_COUNT);
406