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 
15 static const struct smf_state tc_states[TC_STATE_COUNT];
16 static void tc_init(const struct device *dev);
17 
18 /**
19  * @brief Initializes the state machine and enters the Disabled state
20  */
tc_subsys_init(const struct device * dev)21 void tc_subsys_init(const struct device *dev)
22 {
23 	struct usbc_port_data *data = dev->data;
24 	struct tc_sm_t *tc = data->tc;
25 
26 	/* Save the port device object so states can access it */
27 	tc->dev = dev;
28 
29 	/* Initialize the state machine */
30 	smf_set_initial(SMF_CTX(tc), &tc_states[TC_DISABLED_STATE]);
31 }
32 
33 /**
34  * @brief Runs the Type-C layer
35  */
tc_run(const struct device * dev,const int32_t dpm_request)36 void tc_run(const struct device *dev, const int32_t dpm_request)
37 {
38 	struct usbc_port_data *data = dev->data;
39 	const struct device *tcpc = data->tcpc;
40 	struct tc_sm_t *tc = data->tc;
41 
42 	/* These requests are implicitly set by the Device Policy Manager */
43 	if (dpm_request == PRIV_PORT_REQUEST_START) {
44 		data->tc_enabled = true;
45 	} else if (dpm_request == PRIV_PORT_REQUEST_SUSPEND) {
46 		data->tc_enabled = false;
47 		tc_set_state(dev, TC_DISABLED_STATE);
48 	}
49 
50 	switch (data->tc_sm_state) {
51 	case SM_PAUSED:
52 		if (data->tc_enabled == false) {
53 			break;
54 		}
55 	/* fall through */
56 	case SM_INIT:
57 		/* Initialize the Type-C layer */
58 		tc_init(dev);
59 		data->tc_sm_state = SM_RUN;
60 	/* fall through */
61 	case SM_RUN:
62 		if (data->tc_enabled == false) {
63 			tc_pd_enable(dev, false);
64 			data->tc_sm_state = SM_PAUSED;
65 			break;
66 		}
67 
68 		/* Sample CC lines */
69 		tcpc_get_cc(tcpc, &tc->cc1, &tc->cc2);
70 
71 		/* Detect polarity */
72 		tc->cc_polarity = (tc->cc1 > tc->cc2) ? TC_POLARITY_CC1 : TC_POLARITY_CC2;
73 
74 		/* Execute any asyncronous Device Policy Manager Requests */
75 		if (dpm_request == REQUEST_TC_ERROR_RECOVERY) {
76 			/* Transition to Error Recovery State */
77 			tc_set_state(dev, TC_ERROR_RECOVERY_STATE);
78 		} else if (dpm_request == REQUEST_TC_DISABLED) {
79 			/* Transition to Disabled State */
80 			tc_set_state(dev, TC_DISABLED_STATE);
81 		}
82 
83 		/* Run state machine */
84 		smf_run_state(SMF_CTX(tc));
85 	}
86 }
87 
88 /**
89  * @brief Checks if the TC Layer is in an Attached state
90  */
tc_is_in_attached_state(const struct device * dev)91 bool tc_is_in_attached_state(const struct device *dev)
92 {
93 #ifdef CONFIG_USBC_CSM_SINK_ONLY
94 	return (tc_get_state(dev) == TC_ATTACHED_SNK_STATE);
95 #else
96 	return (tc_get_state(dev) == TC_ATTACHED_SRC_STATE);
97 #endif
98 }
99 
100 /**
101  * @brief Initializes the Type-C layer
102  */
tc_init(const struct device * dev)103 static void tc_init(const struct device *dev)
104 {
105 	struct usbc_port_data *data = dev->data;
106 	struct tc_sm_t *tc = data->tc;
107 	const struct device *tcpc = data->tcpc;
108 
109 	/* Initialize the timers */
110 	usbc_timer_init(&tc->tc_t_error_recovery, TC_T_ERROR_RECOVERY_SOURCE_MIN_MS);
111 	usbc_timer_init(&tc->tc_t_cc_debounce, TC_T_CC_DEBOUNCE_MAX_MS);
112 	usbc_timer_init(&tc->tc_t_rp_value_change, TC_T_RP_VALUE_CHANGE_MAX_MS);
113 #ifdef CONFIG_USBC_CSM_SOURCE_ONLY
114 	usbc_timer_init(&tc->tc_t_vconn_off, TC_T_VCONN_OFF_MAX_MS);
115 #endif
116 
117 	/* Clear the flags */
118 	tc->flags = ATOMIC_INIT(0);
119 
120 	/* Initialize the TCPC */
121 	tcpc_init(tcpc);
122 
123 #ifdef CONFIG_USBC_CSM_SOURCE_ONLY
124 	/* Stop sourcing VBUS */
125 	data->policy_cb_src_en(dev, false);
126 
127 	/* Stop sourcing VCONN */
128 	tcpc_set_vconn(tcpc, false);
129 #endif
130 
131 	/* Initialize the state machine */
132 	/*
133 	 * Start out in error recovery state so the CC lines are opened for a
134 	 * short while if this is a system reset.
135 	 */
136 	tc_set_state(dev, TC_ERROR_RECOVERY_STATE);
137 }
138 
139 /**
140  * @brief Sets a Type-C state
141  */
tc_set_state(const struct device * dev,const enum tc_state_t state)142 void tc_set_state(const struct device *dev, const enum tc_state_t state)
143 {
144 	struct usbc_port_data *data = dev->data;
145 	struct tc_sm_t *tc = data->tc;
146 
147 	__ASSERT(state < ARRAY_SIZE(tc_states), "invalid tc_state %d", state);
148 	smf_set_state(SMF_CTX(tc), &tc_states[state]);
149 }
150 
151 /**
152  * @brief Get the Type-C current state
153  */
tc_get_state(const struct device * dev)154 enum tc_state_t tc_get_state(const struct device *dev)
155 {
156 	struct usbc_port_data *data = dev->data;
157 
158 	return data->tc->ctx.current - &tc_states[0];
159 }
160 
161 /**
162  * @brief Enable Power Delivery
163  */
tc_pd_enable(const struct device * dev,const bool enable)164 void tc_pd_enable(const struct device *dev, const bool enable)
165 {
166 	if (enable) {
167 		prl_start(dev);
168 		pe_start(dev);
169 	} else {
170 		prl_suspend(dev);
171 		pe_suspend(dev);
172 	}
173 }
174 
175 /**
176  * @brief TCPC CC/Rp management
177  */
tc_select_src_collision_rp(const struct device * dev,enum tc_rp_value rp)178 void tc_select_src_collision_rp(const struct device *dev, enum tc_rp_value rp)
179 {
180 	struct usbc_port_data *data = dev->data;
181 	const struct device *tcpc = data->tcpc;
182 
183 	/* Select Rp value */
184 	tcpc_select_rp_value(tcpc, rp);
185 
186 	/* Place Rp on CC lines */
187 	tcpc_set_cc(tcpc, TC_CC_RP);
188 }
189 
190 /**
191  * @brief CC Open Entry
192  */
tc_cc_open_entry(void * obj)193 static void tc_cc_open_entry(void *obj)
194 {
195 	struct tc_sm_t *tc = (struct tc_sm_t *)obj;
196 	const struct device *dev = tc->dev;
197 	struct usbc_port_data *data = dev->data;
198 	const struct device *tcpc = data->tcpc;
199 
200 	tc->cc_voltage = TC_CC_VOLT_OPEN;
201 
202 	/* Disable VCONN */
203 	tcpc_set_vconn(tcpc, false);
204 
205 	/* Open CC lines */
206 	tcpc_set_cc(tcpc, TC_CC_OPEN);
207 }
208 
209 /**
210  * @brief Disabled Entry
211  */
tc_disabled_entry(void * obj)212 static void tc_disabled_entry(void *obj)
213 {
214 	LOG_INF("Disabled");
215 }
216 
217 /**
218  * @brief Disabled Run
219  */
tc_disabled_run(void * obj)220 static void tc_disabled_run(void *obj)
221 {
222 	/* Do nothing */
223 }
224 
225 /**
226  * @brief ErrorRecovery Entry
227  */
tc_error_recovery_entry(void * obj)228 static void tc_error_recovery_entry(void *obj)
229 {
230 	struct tc_sm_t *tc = (struct tc_sm_t *)obj;
231 
232 	LOG_INF("ErrorRecovery");
233 
234 	/* Start tErrorRecovery timer */
235 	usbc_timer_start(&tc->tc_t_error_recovery);
236 }
237 
238 /**
239  * @brief ErrorRecovery Run
240  */
tc_error_recovery_run(void * obj)241 static void tc_error_recovery_run(void *obj)
242 {
243 	struct tc_sm_t *tc = (struct tc_sm_t *)obj;
244 	const struct device *dev = tc->dev;
245 
246 	/* Wait for expiry */
247 	if (usbc_timer_expired(&tc->tc_t_error_recovery) == false) {
248 		return;
249 	}
250 
251 #ifdef CONFIG_USBC_CSM_SINK_ONLY
252 	/* Transition to Unattached.SNK */
253 	tc_set_state(dev, TC_UNATTACHED_SNK_STATE);
254 #else
255 	/* Transition to Unattached.SRC */
256 	tc_set_state(dev, TC_UNATTACHED_SRC_STATE);
257 #endif
258 }
259 
260 /**
261  * @brief Type-C State Table
262  */
263 static const struct smf_state tc_states[TC_STATE_COUNT] = {
264 	/* Super States */
265 	[TC_CC_OPEN_SUPER_STATE] = SMF_CREATE_STATE(
266 		tc_cc_open_entry,
267 		NULL,
268 		NULL,
269 		NULL),
270 #ifdef CONFIG_USBC_CSM_SINK_ONLY
271 	[TC_CC_RD_SUPER_STATE] = SMF_CREATE_STATE(
272 		tc_cc_rd_entry,
273 		NULL,
274 		NULL,
275 		NULL),
276 #else
277 	[TC_CC_RP_SUPER_STATE] = SMF_CREATE_STATE(
278 		tc_cc_rp_entry,
279 		NULL,
280 		NULL,
281 		NULL),
282 #endif
283 	/* Normal States */
284 #ifdef CONFIG_USBC_CSM_SINK_ONLY
285 	[TC_UNATTACHED_SNK_STATE] = SMF_CREATE_STATE(
286 		tc_unattached_snk_entry,
287 		tc_unattached_snk_run,
288 		NULL,
289 		&tc_states[TC_CC_RD_SUPER_STATE]),
290 	[TC_ATTACH_WAIT_SNK_STATE] = SMF_CREATE_STATE(
291 		tc_attach_wait_snk_entry,
292 		tc_attach_wait_snk_run,
293 		tc_attach_wait_snk_exit,
294 		&tc_states[TC_CC_RD_SUPER_STATE]),
295 	[TC_ATTACHED_SNK_STATE] = SMF_CREATE_STATE(
296 		tc_attached_snk_entry,
297 		tc_attached_snk_run,
298 		tc_attached_snk_exit,
299 		NULL),
300 #else
301 	[TC_UNATTACHED_SRC_STATE] = SMF_CREATE_STATE(
302 		tc_unattached_src_entry,
303 		tc_unattached_src_run,
304 		NULL,
305 		&tc_states[TC_CC_RP_SUPER_STATE]),
306 	[TC_UNATTACHED_WAIT_SRC_STATE] = SMF_CREATE_STATE(
307 		tc_unattached_wait_src_entry,
308 		tc_unattached_wait_src_run,
309 		tc_unattached_wait_src_exit,
310 		NULL),
311 	[TC_ATTACH_WAIT_SRC_STATE] = SMF_CREATE_STATE(
312 		tc_attach_wait_src_entry,
313 		tc_attach_wait_src_run,
314 		tc_attach_wait_src_exit,
315 		&tc_states[TC_CC_RP_SUPER_STATE]),
316 	[TC_ATTACHED_SRC_STATE] = SMF_CREATE_STATE(
317 		tc_attached_src_entry,
318 		tc_attached_src_run,
319 		tc_attached_src_exit,
320 		NULL),
321 #endif
322 	[TC_DISABLED_STATE] = SMF_CREATE_STATE(
323 		tc_disabled_entry,
324 		tc_disabled_run,
325 		NULL,
326 		&tc_states[TC_CC_OPEN_SUPER_STATE]),
327 	[TC_ERROR_RECOVERY_STATE] = SMF_CREATE_STATE(
328 		tc_error_recovery_entry,
329 		tc_error_recovery_run,
330 		NULL,
331 		&tc_states[TC_CC_OPEN_SUPER_STATE]),
332 };
333 BUILD_ASSERT(ARRAY_SIZE(tc_states) == TC_STATE_COUNT);
334