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