1 /*
2  * Copyright (c) 2023 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_src_states_internal.h"
12 #include <zephyr/drivers/usb_c/usbc_ppc.h>
13 
14 /**
15  * @brief Spec. Release 1.3, section 4.5.2.2.7 Unattached.SRC State
16  *
17  * When in the Unattached.SRC state, the port is waiting to detect the
18  * presence of a Sink or an Accessory.
19  *
20  * Requirements:
21  *   1: The port shall not drive VBUS or VCONN.
22  *      NOTE: Implemented in the tc_attached_src_exit
23  *            function and initially set the tc_init function.
24  *
25  *   2: The port shall provide a separate Rp termination on the CC1 and
26  *      CC2 pins.
27  *      NOTE: Implemented in the tc_cc_rp super state.
28  */
29 
tc_unattached_src_entry(void * obj)30 void tc_unattached_src_entry(void *obj)
31 {
32 	LOG_INF("Unattached.SRC");
33 }
34 
tc_unattached_src_run(void * obj)35 void tc_unattached_src_run(void *obj)
36 {
37 	struct tc_sm_t *tc = (struct tc_sm_t *)obj;
38 	const struct device *dev = tc->dev;
39 
40 	/*
41 	 * Transition to AttachWait.SRC when:
42 	 *   The SRC.Rd is detected on either CC1 or CC2 pin or
43 	 *   SRC.Ra is detected on both CC1 and CC2 pins.
44 	 *   NOTE: Audio Adapter Accessory Mode is not supported, so
45 	 *   SRC.Ra will not be checked.
46 	 */
47 	if (tcpc_is_cc_at_least_one_rd(tc->cc1, tc->cc2)) {
48 		tc_set_state(dev, TC_ATTACH_WAIT_SRC_STATE);
49 	}
50 }
51 
52 /**
53  * @brief Spec. Release 1.3, section 4.5.2.2.6 UnattachedWait.SRC State
54  *
55  * When in the UnattachedWait.SRC state, the port is discharging the CC pin
56  * that was providing VCONN in the previous Attached.SRC state.
57  *
58  * Requirements:
59  *  1: The port shall not enable VBUS or VCONN.
60  *     NOTE: Implemented in tc_attached_src_exit
61  *
62  *  2: The port shall continue to provide an Rp termination on the CC pin not
63  *     being discharged.
64  *     NOTE: Implemented in TC_CC_RP_SUPER_STATE super state.
65  *
66  *  3: The port shall provide an Rdch termination on the CC pin being
67  *     discharged.
68  *     NOTE: Implemented in tc_unattached_wait_src_entry
69  */
70 
tc_unattached_wait_src_entry(void * obj)71 void tc_unattached_wait_src_entry(void *obj)
72 {
73 	struct tc_sm_t *tc = (struct tc_sm_t *)obj;
74 	const struct device *dev = tc->dev;
75 	struct usbc_port_data *data = dev->data;
76 	const struct device *tcpc = data->tcpc;
77 
78 	LOG_INF("UnattachedWait.SRC");
79 
80 	/* Start discharging VCONN */
81 	tcpc_vconn_discharge(tcpc, true);
82 
83 	/* Start VCONN off timer */
84 	usbc_timer_start(&tc->tc_t_vconn_off);
85 }
86 
tc_unattached_wait_src_run(void * obj)87 void tc_unattached_wait_src_run(void *obj)
88 {
89 	struct tc_sm_t *tc = (struct tc_sm_t *)obj;
90 	const struct device *dev = tc->dev;
91 
92 	/* CC Debounce time should be enough time for VCONN to discharge */
93 	if (usbc_timer_expired(&tc->tc_t_vconn_off)) {
94 		tc_set_state(dev, TC_UNATTACHED_SRC_STATE);
95 	}
96 }
97 
tc_unattached_wait_src_exit(void * obj)98 void tc_unattached_wait_src_exit(void *obj)
99 {
100 	struct tc_sm_t *tc = (struct tc_sm_t *)obj;
101 	const struct device *dev = tc->dev;
102 	struct usbc_port_data *data = dev->data;
103 	const struct device *tcpc = data->tcpc;
104 
105 	/* Stop discharging VCONN */
106 	tcpc_vconn_discharge(tcpc, false);
107 
108 	/* Stop timer */
109 	usbc_timer_stop(&tc->tc_t_vconn_off);
110 }
111 
112 /**
113  * @brief Spec. Release 1.3, section 4.5.2.2.8 AttachWait.SRC State
114  *
115  * The AttachWait.SRC state is used to ensure that the state of both of
116  * the CC1 and CC2 pins is stable after a Sink is connected.
117  *
118  * Requirements:
119  *   The requirements for this state are identical to Unattached.SRC.
120  */
121 
tc_attach_wait_src_entry(void * obj)122 void tc_attach_wait_src_entry(void *obj)
123 {
124 	struct tc_sm_t *tc = (struct tc_sm_t *)obj;
125 
126 	LOG_INF("AttachWait.SRC");
127 
128 	/* Initialize the cc state to open */
129 	tc->cc_state = TC_CC_NONE;
130 }
131 
tc_attach_wait_src_run(void * obj)132 void tc_attach_wait_src_run(void *obj)
133 {
134 	struct tc_sm_t *tc = (struct tc_sm_t *)obj;
135 	const struct device *dev = tc->dev;
136 	struct usbc_port_data *data = dev->data;
137 	const struct device *vbus = data->vbus;
138 	enum tc_cc_states new_cc_state;
139 
140 	/* Is a connection detected? */
141 	if (tcpc_is_cc_at_least_one_rd(tc->cc1, tc->cc2)) {
142 		/* UFP attached */
143 		new_cc_state = TC_CC_UFP_ATTACHED;
144 	} else {
145 		/* No UFP */
146 		tc_set_state(dev, TC_UNATTACHED_SRC_STATE);
147 		return;
148 	}
149 
150 	/* Debounce the cc state */
151 	if (new_cc_state != tc->cc_state) {
152 		/* Start debouce timer */
153 		usbc_timer_start(&tc->tc_t_cc_debounce);
154 		tc->cc_state = new_cc_state;
155 	}
156 
157 	/* Wait for CC debounce */
158 	if (usbc_timer_running(&tc->tc_t_cc_debounce) &&
159 		!usbc_timer_expired(&tc->tc_t_cc_debounce)) {
160 		return;
161 	}
162 
163 	/*
164 	 * The port shall transition to Attached.SRC when VBUS is at vSafe0V
165 	 * and the SRC.Rd state is detected on exactly one of the CC1 or CC2
166 	 * pins for at least tCCDebounce.
167 	 */
168 	if (usbc_vbus_check_level(vbus, TC_VBUS_SAFE0V)) {
169 		if (new_cc_state == TC_CC_UFP_ATTACHED) {
170 			tc_set_state(dev, TC_ATTACHED_SRC_STATE);
171 		}
172 	}
173 }
174 
tc_attach_wait_src_exit(void * obj)175 void tc_attach_wait_src_exit(void *obj)
176 {
177 	struct tc_sm_t *tc = (struct tc_sm_t *)obj;
178 
179 	/* Stop debounce timer */
180 	usbc_timer_stop(&tc->tc_t_cc_debounce);
181 }
182 
183 /**
184  * @brief Spec. Release 1.3, section 4.5.2.2.9 Attached.SRC State
185  *
186  * When in the Attached.SRC state, the port is attached and operating as a
187  * Source. When the port initially enters this state it is also operating
188  * as a DFP. Subsequently, the initial power and data roles can be changed
189  * using USB PD commands.
190  *
191  * Requirements:
192  *  1: If the port needs to determine the orientation of the connector, it
193  *     shall do so only upon entry to the Attached.SRC state by detecting
194  *     which of the CC1 or CC2 pins is connected through the
195  *     cable, i.e., which CC pin is in the SRC.Rd state.
196  *     NOTE: Implemented in tc_attached_src_entry.
197  *
198  * 2: If the port has entered this state from the AttachWait.SRC state,
199  *    the SRC.Rd state will be on only one of the CC1 or CC2 pins. The
200  *    port shall source current on this CC pin and monitor its state.
201  *    NOTE: Implemented in the super state of AttachWait.SRC.
202  *
203  * 3: The port shall provide an Rp
204  *    NOTE: Implemented in the super state of AttachWait.SRC.
205  *
206  * 5: The port shall supply VBUS current at the level it advertises on Rp.
207  *    NOTE: Implemented in tc_attached_src_entry.
208  *
209  * 7: The port shall not initiate any USB PD communications until VBUS
210  *    reaches vSafe5V.
211  *    NOTE: Implemented in tc_attached_src_run.
212  *
213  * 8: The port may negotiate a USB PD PR_Swap, DR_Swap or VCONN_Swap.
214  *    NOTE: Implemented in tc_attached_src_run.
215  *
216  * 9: If the port supplies VCONN, it shall do so within t_VCONN_ON.
217  *    NOTE: Implemented in tc_attached_src_entry.
218  */
219 
tc_attached_src_entry(void * obj)220 void tc_attached_src_entry(void *obj)
221 {
222 	struct tc_sm_t *tc = (struct tc_sm_t *)obj;
223 	const struct device *dev = tc->dev;
224 	struct usbc_port_data *data = dev->data;
225 	const struct device *tcpc = data->tcpc;
226 	int ret;
227 
228 	LOG_INF("Attached.SRC");
229 
230 	/* Initial data role for source is DFP */
231 	tcpc_set_roles(tcpc, TC_ROLE_SOURCE, TC_ROLE_DFP);
232 
233 	/* Set cc polarity */
234 	ret = tcpc_set_cc_polarity(tcpc, tc->cc_polarity);
235 	if (ret != 0) {
236 		LOG_ERR("Couldn't set CC polarity to %d: %d", tc->cc_polarity, ret);
237 		tc_set_state(dev, TC_ERROR_RECOVERY_STATE);
238 		return;
239 	}
240 
241 	/* Start sourcing VBUS */
242 	if (usbc_policy_src_en(dev, tcpc, true) == 0) {
243 		/* Start sourcing VCONN */
244 		if (policy_check(dev, CHECK_VCONN_CONTROL)) {
245 			if (tcpc_set_vconn(tcpc, true) == 0) {
246 				atomic_set_bit(&tc->flags, TC_FLAGS_VCONN_ON);
247 			} else {
248 				LOG_ERR("VCONN can't be enabled\n");
249 			}
250 		}
251 	} else {
252 		LOG_ERR("Power Supply can't be enabled\n");
253 	}
254 
255 	/* Enable PD */
256 	tc_pd_enable(dev, true);
257 
258 	/* Enable the VBUS sourcing by the PPC */
259 	if (data->ppc != NULL) {
260 		ret = ppc_set_src_ctrl(data->ppc, true);
261 		if (ret < 0 && ret != -ENOSYS) {
262 			LOG_ERR("Couldn't disable PPC source");
263 		}
264 	}
265 }
266 
tc_attached_src_run(void * obj)267 void tc_attached_src_run(void *obj)
268 {
269 	struct tc_sm_t *tc = (struct tc_sm_t *)obj;
270 	const struct device *dev = tc->dev;
271 
272 	/* Monitor for CC disconnection */
273 	if (tcpc_is_cc_open(tc->cc1, tc->cc2)) {
274 		/*
275 		 * A Source that is supplying VCONN or has yielded VCONN source
276 		 * responsibility to the Sink through USBPD VCONN_Swap messaging
277 		 * shall transition to UnattachedWait.SRC when the SRC.Open state
278 		 * is detected on the monitored CC pin. The Source shall detect
279 		 * the SRC.Open state within tSRCDisconnect, but should detect
280 		 * it as quickly as possible.
281 		 */
282 		if (atomic_test_and_clear_bit(&tc->flags, TC_FLAGS_VCONN_ON)) {
283 			tc_set_state(dev, TC_UNATTACHED_WAIT_SRC_STATE);
284 		}
285 		/*
286 		 * A Source that is not supplying VCONN and has not yielded
287 		 * VCONN responsibility to the Sink through USBPD VCONN_Swap
288 		 * messaging shall transition to Unattached.SRC when the
289 		 * SRC.Open state is detected on the monitored CC pin. The
290 		 * Source shall detect the SRC.Open state within tSRCDisconnect,
291 		 * but should detect it as quickly as possible.
292 		 */
293 		else {
294 			tc_set_state(dev, TC_UNATTACHED_SRC_STATE);
295 		}
296 	}
297 }
298 
tc_attached_src_exit(void * obj)299 void tc_attached_src_exit(void *obj)
300 {
301 	struct tc_sm_t *tc = (struct tc_sm_t *)obj;
302 	const struct device *dev = tc->dev;
303 	struct usbc_port_data *data = dev->data;
304 	const struct device *tcpc = data->tcpc;
305 	int ret;
306 
307 	/* Disable PD */
308 	tc_pd_enable(dev, false);
309 
310 	/* Stop sourcing VBUS */
311 	if (usbc_policy_src_en(dev, tcpc, false) != 0) {
312 		LOG_ERR("Couldn't disable VBUS source");
313 	}
314 
315 	/* Disable the VBUS sourcing by the PPC */
316 	if (data->ppc != NULL) {
317 		ret = ppc_set_src_ctrl(data->ppc, false);
318 		if (ret < 0 && ret != -ENOSYS) {
319 			LOG_ERR("Couldn't disable PPC source");
320 		}
321 	}
322 
323 	/* Stop sourcing VCONN */
324 	ret = tcpc_set_vconn(tcpc, false);
325 	if (ret != 0 && ret != -ENOSYS) {
326 		LOG_ERR("Couldn't disable VCONN source");
327 	}
328 }
329 
330 /**
331  * @brief This is a super state for Source States that
332  *	  requirement the Rp value placed on the CC lines.
333  */
tc_cc_rp_entry(void * obj)334 void tc_cc_rp_entry(void *obj)
335 {
336 	struct tc_sm_t *tc = (struct tc_sm_t *)obj;
337 	const struct device *dev = tc->dev;
338 	struct usbc_port_data *data = dev->data;
339 	const struct device *tcpc = data->tcpc;
340 	enum tc_rp_value rp = TC_RP_USB;
341 	int ret;
342 
343 	/*
344 	 * Get initial Rp value from Device Policy Manager or use
345 	 * default TC_RP_USB.
346 	 */
347 	if (data->policy_cb_get_src_rp) {
348 		data->policy_cb_get_src_rp(dev, &rp);
349 	}
350 
351 	/* Select Rp value */
352 	ret = tcpc_select_rp_value(tcpc, rp);
353 	if (ret != 0 && ret != -ENOTSUP) {
354 		LOG_ERR("Couldn't set Rp value to %d: %d", rp, ret);
355 		tc_set_state(dev, TC_ERROR_RECOVERY_STATE);
356 		return;
357 	}
358 
359 	/* Place Rp on CC lines */
360 	ret = tcpc_set_cc(tcpc, TC_CC_RP);
361 	if (ret != 0) {
362 		LOG_ERR("Couldn't set CC lines to Rp: %d", ret);
363 		tc_set_state(dev, TC_ERROR_RECOVERY_STATE);
364 	}
365 }
366