1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* |
3 | * OTG Finite State Machine from OTG spec |
4 | * |
5 | * Copyright (C) 2007,2008 Freescale Semiconductor, Inc. |
6 | * |
7 | * Author: Li Yang <LeoLi@freescale.com> |
8 | * Jerry Huang <Chang-Ming.Huang@freescale.com> |
9 | */ |
10 | |
11 | #include <linux/module.h> |
12 | #include <linux/kernel.h> |
13 | #include <linux/types.h> |
14 | #include <linux/mutex.h> |
15 | #include <linux/delay.h> |
16 | #include <linux/usb.h> |
17 | #include <linux/usb/gadget.h> |
18 | #include <linux/usb/otg.h> |
19 | #include <linux/usb/otg-fsm.h> |
20 | |
21 | #ifdef VERBOSE |
22 | #define VDBG(fmt, args...) pr_debug("[%s] " fmt, \ |
23 | __func__, ## args) |
24 | #else |
25 | #define VDBG(stuff...) do {} while (0) |
26 | #endif |
27 | |
28 | /* Change USB protocol when there is a protocol change */ |
29 | static int otg_set_protocol(struct otg_fsm *fsm, int protocol) |
30 | { |
31 | int ret = 0; |
32 | |
33 | if (fsm->protocol != protocol) { |
34 | VDBG("Changing role fsm->protocol= %d; new protocol= %d\n" , |
35 | fsm->protocol, protocol); |
36 | /* stop old protocol */ |
37 | if (fsm->protocol == PROTO_HOST) |
38 | ret = otg_start_host(fsm, on: 0); |
39 | else if (fsm->protocol == PROTO_GADGET) |
40 | ret = otg_start_gadget(fsm, on: 0); |
41 | if (ret) |
42 | return ret; |
43 | |
44 | /* start new protocol */ |
45 | if (protocol == PROTO_HOST) |
46 | ret = otg_start_host(fsm, on: 1); |
47 | else if (protocol == PROTO_GADGET) |
48 | ret = otg_start_gadget(fsm, on: 1); |
49 | if (ret) |
50 | return ret; |
51 | |
52 | fsm->protocol = protocol; |
53 | return 0; |
54 | } |
55 | |
56 | return 0; |
57 | } |
58 | |
59 | /* Called when leaving a state. Do state clean up jobs here */ |
60 | static void otg_leave_state(struct otg_fsm *fsm, enum usb_otg_state old_state) |
61 | { |
62 | switch (old_state) { |
63 | case OTG_STATE_B_IDLE: |
64 | otg_del_timer(fsm, timer: B_SE0_SRP); |
65 | fsm->b_se0_srp = 0; |
66 | fsm->adp_sns = 0; |
67 | fsm->adp_prb = 0; |
68 | break; |
69 | case OTG_STATE_B_SRP_INIT: |
70 | fsm->data_pulse = 0; |
71 | fsm->b_srp_done = 0; |
72 | break; |
73 | case OTG_STATE_B_PERIPHERAL: |
74 | if (fsm->otg->gadget) |
75 | fsm->otg->gadget->host_request_flag = 0; |
76 | break; |
77 | case OTG_STATE_B_WAIT_ACON: |
78 | otg_del_timer(fsm, timer: B_ASE0_BRST); |
79 | fsm->b_ase0_brst_tmout = 0; |
80 | break; |
81 | case OTG_STATE_B_HOST: |
82 | break; |
83 | case OTG_STATE_A_IDLE: |
84 | fsm->adp_prb = 0; |
85 | break; |
86 | case OTG_STATE_A_WAIT_VRISE: |
87 | otg_del_timer(fsm, timer: A_WAIT_VRISE); |
88 | fsm->a_wait_vrise_tmout = 0; |
89 | break; |
90 | case OTG_STATE_A_WAIT_BCON: |
91 | otg_del_timer(fsm, timer: A_WAIT_BCON); |
92 | fsm->a_wait_bcon_tmout = 0; |
93 | break; |
94 | case OTG_STATE_A_HOST: |
95 | otg_del_timer(fsm, timer: A_WAIT_ENUM); |
96 | break; |
97 | case OTG_STATE_A_SUSPEND: |
98 | otg_del_timer(fsm, timer: A_AIDL_BDIS); |
99 | fsm->a_aidl_bdis_tmout = 0; |
100 | fsm->a_suspend_req_inf = 0; |
101 | break; |
102 | case OTG_STATE_A_PERIPHERAL: |
103 | otg_del_timer(fsm, timer: A_BIDL_ADIS); |
104 | fsm->a_bidl_adis_tmout = 0; |
105 | if (fsm->otg->gadget) |
106 | fsm->otg->gadget->host_request_flag = 0; |
107 | break; |
108 | case OTG_STATE_A_WAIT_VFALL: |
109 | otg_del_timer(fsm, timer: A_WAIT_VFALL); |
110 | fsm->a_wait_vfall_tmout = 0; |
111 | otg_del_timer(fsm, timer: A_WAIT_VRISE); |
112 | break; |
113 | case OTG_STATE_A_VBUS_ERR: |
114 | break; |
115 | default: |
116 | break; |
117 | } |
118 | } |
119 | |
120 | static void otg_hnp_polling_work(struct work_struct *work) |
121 | { |
122 | struct otg_fsm *fsm = container_of(to_delayed_work(work), |
123 | struct otg_fsm, hnp_polling_work); |
124 | struct usb_device *udev; |
125 | enum usb_otg_state state = fsm->otg->state; |
126 | u8 flag; |
127 | int retval; |
128 | |
129 | if (state != OTG_STATE_A_HOST && state != OTG_STATE_B_HOST) |
130 | return; |
131 | |
132 | udev = usb_hub_find_child(hdev: fsm->otg->host->root_hub, port1: 1); |
133 | if (!udev) { |
134 | dev_err(fsm->otg->host->controller, |
135 | "no usb dev connected, can't start HNP polling\n" ); |
136 | return; |
137 | } |
138 | |
139 | *fsm->host_req_flag = 0; |
140 | /* Get host request flag from connected USB device */ |
141 | retval = usb_control_msg(dev: udev, |
142 | usb_rcvctrlpipe(udev, 0), |
143 | USB_REQ_GET_STATUS, |
144 | USB_DIR_IN | USB_RECIP_DEVICE, |
145 | value: 0, |
146 | OTG_STS_SELECTOR, |
147 | data: fsm->host_req_flag, |
148 | size: 1, |
149 | USB_CTRL_GET_TIMEOUT); |
150 | if (retval != 1) { |
151 | dev_err(&udev->dev, "Get one byte OTG status failed\n" ); |
152 | return; |
153 | } |
154 | |
155 | flag = *fsm->host_req_flag; |
156 | if (flag == 0) { |
157 | /* Continue HNP polling */ |
158 | schedule_delayed_work(dwork: &fsm->hnp_polling_work, |
159 | delay: msecs_to_jiffies(T_HOST_REQ_POLL)); |
160 | return; |
161 | } else if (flag != HOST_REQUEST_FLAG) { |
162 | dev_err(&udev->dev, "host request flag %d is invalid\n" , flag); |
163 | return; |
164 | } |
165 | |
166 | /* Host request flag is set */ |
167 | if (state == OTG_STATE_A_HOST) { |
168 | /* Set b_hnp_enable */ |
169 | if (!fsm->otg->host->b_hnp_enable) { |
170 | retval = usb_control_msg(dev: udev, |
171 | usb_sndctrlpipe(udev, 0), |
172 | USB_REQ_SET_FEATURE, requesttype: 0, |
173 | USB_DEVICE_B_HNP_ENABLE, |
174 | index: 0, NULL, size: 0, |
175 | USB_CTRL_SET_TIMEOUT); |
176 | if (retval >= 0) |
177 | fsm->otg->host->b_hnp_enable = 1; |
178 | } |
179 | fsm->a_bus_req = 0; |
180 | } else if (state == OTG_STATE_B_HOST) { |
181 | fsm->b_bus_req = 0; |
182 | } |
183 | |
184 | otg_statemachine(fsm); |
185 | } |
186 | |
187 | static void otg_start_hnp_polling(struct otg_fsm *fsm) |
188 | { |
189 | /* |
190 | * The memory of host_req_flag should be allocated by |
191 | * controller driver, otherwise, hnp polling is not started. |
192 | */ |
193 | if (!fsm->host_req_flag) |
194 | return; |
195 | |
196 | if (!fsm->hnp_work_inited) { |
197 | INIT_DELAYED_WORK(&fsm->hnp_polling_work, otg_hnp_polling_work); |
198 | fsm->hnp_work_inited = true; |
199 | } |
200 | |
201 | schedule_delayed_work(dwork: &fsm->hnp_polling_work, |
202 | delay: msecs_to_jiffies(T_HOST_REQ_POLL)); |
203 | } |
204 | |
205 | /* Called when entering a state */ |
206 | static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state) |
207 | { |
208 | if (fsm->otg->state == new_state) |
209 | return 0; |
210 | VDBG("Set state: %s\n" , usb_otg_state_string(new_state)); |
211 | otg_leave_state(fsm, old_state: fsm->otg->state); |
212 | switch (new_state) { |
213 | case OTG_STATE_B_IDLE: |
214 | otg_drv_vbus(fsm, on: 0); |
215 | otg_chrg_vbus(fsm, on: 0); |
216 | otg_loc_conn(fsm, on: 0); |
217 | otg_loc_sof(fsm, on: 0); |
218 | /* |
219 | * Driver is responsible for starting ADP probing |
220 | * if ADP sensing times out. |
221 | */ |
222 | otg_start_adp_sns(fsm); |
223 | otg_set_protocol(fsm, PROTO_UNDEF); |
224 | otg_add_timer(fsm, timer: B_SE0_SRP); |
225 | break; |
226 | case OTG_STATE_B_SRP_INIT: |
227 | otg_start_pulse(fsm); |
228 | otg_loc_sof(fsm, on: 0); |
229 | otg_set_protocol(fsm, PROTO_UNDEF); |
230 | otg_add_timer(fsm, timer: B_SRP_FAIL); |
231 | break; |
232 | case OTG_STATE_B_PERIPHERAL: |
233 | otg_chrg_vbus(fsm, on: 0); |
234 | otg_loc_sof(fsm, on: 0); |
235 | otg_set_protocol(fsm, PROTO_GADGET); |
236 | otg_loc_conn(fsm, on: 1); |
237 | break; |
238 | case OTG_STATE_B_WAIT_ACON: |
239 | otg_chrg_vbus(fsm, on: 0); |
240 | otg_loc_conn(fsm, on: 0); |
241 | otg_loc_sof(fsm, on: 0); |
242 | otg_set_protocol(fsm, PROTO_HOST); |
243 | otg_add_timer(fsm, timer: B_ASE0_BRST); |
244 | fsm->a_bus_suspend = 0; |
245 | break; |
246 | case OTG_STATE_B_HOST: |
247 | otg_chrg_vbus(fsm, on: 0); |
248 | otg_loc_conn(fsm, on: 0); |
249 | otg_loc_sof(fsm, on: 1); |
250 | otg_set_protocol(fsm, PROTO_HOST); |
251 | usb_bus_start_enum(bus: fsm->otg->host, |
252 | port_num: fsm->otg->host->otg_port); |
253 | otg_start_hnp_polling(fsm); |
254 | break; |
255 | case OTG_STATE_A_IDLE: |
256 | otg_drv_vbus(fsm, on: 0); |
257 | otg_chrg_vbus(fsm, on: 0); |
258 | otg_loc_conn(fsm, on: 0); |
259 | otg_loc_sof(fsm, on: 0); |
260 | otg_start_adp_prb(fsm); |
261 | otg_set_protocol(fsm, PROTO_HOST); |
262 | break; |
263 | case OTG_STATE_A_WAIT_VRISE: |
264 | otg_drv_vbus(fsm, on: 1); |
265 | otg_loc_conn(fsm, on: 0); |
266 | otg_loc_sof(fsm, on: 0); |
267 | otg_set_protocol(fsm, PROTO_HOST); |
268 | otg_add_timer(fsm, timer: A_WAIT_VRISE); |
269 | break; |
270 | case OTG_STATE_A_WAIT_BCON: |
271 | otg_drv_vbus(fsm, on: 1); |
272 | otg_loc_conn(fsm, on: 0); |
273 | otg_loc_sof(fsm, on: 0); |
274 | otg_set_protocol(fsm, PROTO_HOST); |
275 | otg_add_timer(fsm, timer: A_WAIT_BCON); |
276 | break; |
277 | case OTG_STATE_A_HOST: |
278 | otg_drv_vbus(fsm, on: 1); |
279 | otg_loc_conn(fsm, on: 0); |
280 | otg_loc_sof(fsm, on: 1); |
281 | otg_set_protocol(fsm, PROTO_HOST); |
282 | /* |
283 | * When HNP is triggered while a_bus_req = 0, a_host will |
284 | * suspend too fast to complete a_set_b_hnp_en |
285 | */ |
286 | if (!fsm->a_bus_req || fsm->a_suspend_req_inf) |
287 | otg_add_timer(fsm, timer: A_WAIT_ENUM); |
288 | otg_start_hnp_polling(fsm); |
289 | break; |
290 | case OTG_STATE_A_SUSPEND: |
291 | otg_drv_vbus(fsm, on: 1); |
292 | otg_loc_conn(fsm, on: 0); |
293 | otg_loc_sof(fsm, on: 0); |
294 | otg_set_protocol(fsm, PROTO_HOST); |
295 | otg_add_timer(fsm, timer: A_AIDL_BDIS); |
296 | |
297 | break; |
298 | case OTG_STATE_A_PERIPHERAL: |
299 | otg_loc_sof(fsm, on: 0); |
300 | otg_set_protocol(fsm, PROTO_GADGET); |
301 | otg_drv_vbus(fsm, on: 1); |
302 | otg_loc_conn(fsm, on: 1); |
303 | otg_add_timer(fsm, timer: A_BIDL_ADIS); |
304 | break; |
305 | case OTG_STATE_A_WAIT_VFALL: |
306 | otg_drv_vbus(fsm, on: 0); |
307 | otg_loc_conn(fsm, on: 0); |
308 | otg_loc_sof(fsm, on: 0); |
309 | otg_set_protocol(fsm, PROTO_HOST); |
310 | otg_add_timer(fsm, timer: A_WAIT_VFALL); |
311 | break; |
312 | case OTG_STATE_A_VBUS_ERR: |
313 | otg_drv_vbus(fsm, on: 0); |
314 | otg_loc_conn(fsm, on: 0); |
315 | otg_loc_sof(fsm, on: 0); |
316 | otg_set_protocol(fsm, PROTO_UNDEF); |
317 | break; |
318 | default: |
319 | break; |
320 | } |
321 | |
322 | fsm->otg->state = new_state; |
323 | fsm->state_changed = 1; |
324 | return 0; |
325 | } |
326 | |
327 | /* State change judgement */ |
328 | int otg_statemachine(struct otg_fsm *fsm) |
329 | { |
330 | enum usb_otg_state state; |
331 | |
332 | mutex_lock(&fsm->lock); |
333 | |
334 | state = fsm->otg->state; |
335 | fsm->state_changed = 0; |
336 | /* State machine state change judgement */ |
337 | |
338 | switch (state) { |
339 | case OTG_STATE_UNDEFINED: |
340 | VDBG("fsm->id = %d\n" , fsm->id); |
341 | if (fsm->id) |
342 | otg_set_state(fsm, new_state: OTG_STATE_B_IDLE); |
343 | else |
344 | otg_set_state(fsm, new_state: OTG_STATE_A_IDLE); |
345 | break; |
346 | case OTG_STATE_B_IDLE: |
347 | if (!fsm->id) |
348 | otg_set_state(fsm, new_state: OTG_STATE_A_IDLE); |
349 | else if (fsm->b_sess_vld && fsm->otg->gadget) |
350 | otg_set_state(fsm, new_state: OTG_STATE_B_PERIPHERAL); |
351 | else if ((fsm->b_bus_req || fsm->adp_change || fsm->power_up) && |
352 | fsm->b_ssend_srp && fsm->b_se0_srp) |
353 | otg_set_state(fsm, new_state: OTG_STATE_B_SRP_INIT); |
354 | break; |
355 | case OTG_STATE_B_SRP_INIT: |
356 | if (!fsm->id || fsm->b_srp_done) |
357 | otg_set_state(fsm, new_state: OTG_STATE_B_IDLE); |
358 | break; |
359 | case OTG_STATE_B_PERIPHERAL: |
360 | if (!fsm->id || !fsm->b_sess_vld) |
361 | otg_set_state(fsm, new_state: OTG_STATE_B_IDLE); |
362 | else if (fsm->b_bus_req && fsm->otg-> |
363 | gadget->b_hnp_enable && fsm->a_bus_suspend) |
364 | otg_set_state(fsm, new_state: OTG_STATE_B_WAIT_ACON); |
365 | break; |
366 | case OTG_STATE_B_WAIT_ACON: |
367 | if (fsm->a_conn) |
368 | otg_set_state(fsm, new_state: OTG_STATE_B_HOST); |
369 | else if (!fsm->id || !fsm->b_sess_vld) |
370 | otg_set_state(fsm, new_state: OTG_STATE_B_IDLE); |
371 | else if (fsm->a_bus_resume || fsm->b_ase0_brst_tmout) { |
372 | fsm->b_ase0_brst_tmout = 0; |
373 | otg_set_state(fsm, new_state: OTG_STATE_B_PERIPHERAL); |
374 | } |
375 | break; |
376 | case OTG_STATE_B_HOST: |
377 | if (!fsm->id || !fsm->b_sess_vld) |
378 | otg_set_state(fsm, new_state: OTG_STATE_B_IDLE); |
379 | else if (!fsm->b_bus_req || !fsm->a_conn || fsm->test_device) |
380 | otg_set_state(fsm, new_state: OTG_STATE_B_PERIPHERAL); |
381 | break; |
382 | case OTG_STATE_A_IDLE: |
383 | if (fsm->id) |
384 | otg_set_state(fsm, new_state: OTG_STATE_B_IDLE); |
385 | else if (!fsm->a_bus_drop && (fsm->a_bus_req || |
386 | fsm->a_srp_det || fsm->adp_change || fsm->power_up)) |
387 | otg_set_state(fsm, new_state: OTG_STATE_A_WAIT_VRISE); |
388 | break; |
389 | case OTG_STATE_A_WAIT_VRISE: |
390 | if (fsm->a_vbus_vld) |
391 | otg_set_state(fsm, new_state: OTG_STATE_A_WAIT_BCON); |
392 | else if (fsm->id || fsm->a_bus_drop || |
393 | fsm->a_wait_vrise_tmout) |
394 | otg_set_state(fsm, new_state: OTG_STATE_A_WAIT_VFALL); |
395 | break; |
396 | case OTG_STATE_A_WAIT_BCON: |
397 | if (!fsm->a_vbus_vld) |
398 | otg_set_state(fsm, new_state: OTG_STATE_A_VBUS_ERR); |
399 | else if (fsm->b_conn) |
400 | otg_set_state(fsm, new_state: OTG_STATE_A_HOST); |
401 | else if (fsm->id || fsm->a_bus_drop || fsm->a_wait_bcon_tmout) |
402 | otg_set_state(fsm, new_state: OTG_STATE_A_WAIT_VFALL); |
403 | break; |
404 | case OTG_STATE_A_HOST: |
405 | if (fsm->id || fsm->a_bus_drop) |
406 | otg_set_state(fsm, new_state: OTG_STATE_A_WAIT_VFALL); |
407 | else if ((!fsm->a_bus_req || fsm->a_suspend_req_inf) && |
408 | fsm->otg->host->b_hnp_enable) |
409 | otg_set_state(fsm, new_state: OTG_STATE_A_SUSPEND); |
410 | else if (!fsm->b_conn) |
411 | otg_set_state(fsm, new_state: OTG_STATE_A_WAIT_BCON); |
412 | else if (!fsm->a_vbus_vld) |
413 | otg_set_state(fsm, new_state: OTG_STATE_A_VBUS_ERR); |
414 | break; |
415 | case OTG_STATE_A_SUSPEND: |
416 | if (!fsm->b_conn && fsm->otg->host->b_hnp_enable) |
417 | otg_set_state(fsm, new_state: OTG_STATE_A_PERIPHERAL); |
418 | else if (!fsm->b_conn && !fsm->otg->host->b_hnp_enable) |
419 | otg_set_state(fsm, new_state: OTG_STATE_A_WAIT_BCON); |
420 | else if (fsm->a_bus_req || fsm->b_bus_resume) |
421 | otg_set_state(fsm, new_state: OTG_STATE_A_HOST); |
422 | else if (fsm->id || fsm->a_bus_drop || fsm->a_aidl_bdis_tmout) |
423 | otg_set_state(fsm, new_state: OTG_STATE_A_WAIT_VFALL); |
424 | else if (!fsm->a_vbus_vld) |
425 | otg_set_state(fsm, new_state: OTG_STATE_A_VBUS_ERR); |
426 | break; |
427 | case OTG_STATE_A_PERIPHERAL: |
428 | if (fsm->id || fsm->a_bus_drop) |
429 | otg_set_state(fsm, new_state: OTG_STATE_A_WAIT_VFALL); |
430 | else if (fsm->a_bidl_adis_tmout || fsm->b_bus_suspend) |
431 | otg_set_state(fsm, new_state: OTG_STATE_A_WAIT_BCON); |
432 | else if (!fsm->a_vbus_vld) |
433 | otg_set_state(fsm, new_state: OTG_STATE_A_VBUS_ERR); |
434 | break; |
435 | case OTG_STATE_A_WAIT_VFALL: |
436 | if (fsm->a_wait_vfall_tmout) |
437 | otg_set_state(fsm, new_state: OTG_STATE_A_IDLE); |
438 | break; |
439 | case OTG_STATE_A_VBUS_ERR: |
440 | if (fsm->id || fsm->a_bus_drop || fsm->a_clr_err) |
441 | otg_set_state(fsm, new_state: OTG_STATE_A_WAIT_VFALL); |
442 | break; |
443 | default: |
444 | break; |
445 | } |
446 | mutex_unlock(lock: &fsm->lock); |
447 | |
448 | VDBG("quit statemachine, changed = %d\n" , fsm->state_changed); |
449 | return fsm->state_changed; |
450 | } |
451 | EXPORT_SYMBOL_GPL(otg_statemachine); |
452 | MODULE_LICENSE("GPL" ); |
453 | |