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