15fd54aceSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0+
21dfa91aaSPeter Chen /*
31dfa91aaSPeter Chen * OTG Finite State Machine from OTG spec
41dfa91aaSPeter Chen *
51dfa91aaSPeter Chen * Copyright (C) 2007,2008 Freescale Semiconductor, Inc.
61dfa91aaSPeter Chen *
71dfa91aaSPeter Chen * Author: Li Yang <LeoLi@freescale.com>
81dfa91aaSPeter Chen * Jerry Huang <Chang-Ming.Huang@freescale.com>
91dfa91aaSPeter Chen */
101dfa91aaSPeter Chen
11ea1d39a3SOscar #include <linux/module.h>
121dfa91aaSPeter Chen #include <linux/kernel.h>
131dfa91aaSPeter Chen #include <linux/types.h>
141dfa91aaSPeter Chen #include <linux/mutex.h>
151dfa91aaSPeter Chen #include <linux/delay.h>
161dfa91aaSPeter Chen #include <linux/usb.h>
171dfa91aaSPeter Chen #include <linux/usb/gadget.h>
181dfa91aaSPeter Chen #include <linux/usb/otg.h>
191dfa91aaSPeter Chen #include <linux/usb/otg-fsm.h>
201dfa91aaSPeter Chen
21e92634cdSRoger Quadros #ifdef VERBOSE
22e92634cdSRoger Quadros #define VDBG(fmt, args...) pr_debug("[%s] " fmt, \
23e92634cdSRoger Quadros __func__, ## args)
24e92634cdSRoger Quadros #else
25e92634cdSRoger Quadros #define VDBG(stuff...) do {} while (0)
26e92634cdSRoger Quadros #endif
27e92634cdSRoger Quadros
281dfa91aaSPeter Chen /* Change USB protocol when there is a protocol change */
otg_set_protocol(struct otg_fsm * fsm,int protocol)291dfa91aaSPeter Chen static int otg_set_protocol(struct otg_fsm *fsm, int protocol)
301dfa91aaSPeter Chen {
311dfa91aaSPeter Chen int ret = 0;
321dfa91aaSPeter Chen
331dfa91aaSPeter Chen if (fsm->protocol != protocol) {
341dfa91aaSPeter Chen VDBG("Changing role fsm->protocol= %d; new protocol= %d\n",
351dfa91aaSPeter Chen fsm->protocol, protocol);
361dfa91aaSPeter Chen /* stop old protocol */
371dfa91aaSPeter Chen if (fsm->protocol == PROTO_HOST)
381dfa91aaSPeter Chen ret = otg_start_host(fsm, 0);
391dfa91aaSPeter Chen else if (fsm->protocol == PROTO_GADGET)
401dfa91aaSPeter Chen ret = otg_start_gadget(fsm, 0);
411dfa91aaSPeter Chen if (ret)
421dfa91aaSPeter Chen return ret;
431dfa91aaSPeter Chen
441dfa91aaSPeter Chen /* start new protocol */
451dfa91aaSPeter Chen if (protocol == PROTO_HOST)
461dfa91aaSPeter Chen ret = otg_start_host(fsm, 1);
471dfa91aaSPeter Chen else if (protocol == PROTO_GADGET)
481dfa91aaSPeter Chen ret = otg_start_gadget(fsm, 1);
491dfa91aaSPeter Chen if (ret)
501dfa91aaSPeter Chen return ret;
511dfa91aaSPeter Chen
521dfa91aaSPeter Chen fsm->protocol = protocol;
531dfa91aaSPeter Chen return 0;
541dfa91aaSPeter Chen }
551dfa91aaSPeter Chen
561dfa91aaSPeter Chen return 0;
571dfa91aaSPeter Chen }
581dfa91aaSPeter Chen
591dfa91aaSPeter Chen /* Called when leaving a state. Do state clean up jobs here */
otg_leave_state(struct otg_fsm * fsm,enum usb_otg_state old_state)601dfa91aaSPeter Chen static void otg_leave_state(struct otg_fsm *fsm, enum usb_otg_state old_state)
611dfa91aaSPeter Chen {
621dfa91aaSPeter Chen switch (old_state) {
631dfa91aaSPeter Chen case OTG_STATE_B_IDLE:
641dfa91aaSPeter Chen otg_del_timer(fsm, B_SE0_SRP);
651dfa91aaSPeter Chen fsm->b_se0_srp = 0;
661dfa91aaSPeter Chen fsm->adp_sns = 0;
671dfa91aaSPeter Chen fsm->adp_prb = 0;
681dfa91aaSPeter Chen break;
691dfa91aaSPeter Chen case OTG_STATE_B_SRP_INIT:
701dfa91aaSPeter Chen fsm->data_pulse = 0;
711dfa91aaSPeter Chen fsm->b_srp_done = 0;
721dfa91aaSPeter Chen break;
731dfa91aaSPeter Chen case OTG_STATE_B_PERIPHERAL:
74ae57e97aSLi Jun if (fsm->otg->gadget)
75ae57e97aSLi Jun fsm->otg->gadget->host_request_flag = 0;
761dfa91aaSPeter Chen break;
771dfa91aaSPeter Chen case OTG_STATE_B_WAIT_ACON:
781dfa91aaSPeter Chen otg_del_timer(fsm, B_ASE0_BRST);
791dfa91aaSPeter Chen fsm->b_ase0_brst_tmout = 0;
801dfa91aaSPeter Chen break;
811dfa91aaSPeter Chen case OTG_STATE_B_HOST:
821dfa91aaSPeter Chen break;
831dfa91aaSPeter Chen case OTG_STATE_A_IDLE:
841dfa91aaSPeter Chen fsm->adp_prb = 0;
851dfa91aaSPeter Chen break;
861dfa91aaSPeter Chen case OTG_STATE_A_WAIT_VRISE:
871dfa91aaSPeter Chen otg_del_timer(fsm, A_WAIT_VRISE);
881dfa91aaSPeter Chen fsm->a_wait_vrise_tmout = 0;
891dfa91aaSPeter Chen break;
901dfa91aaSPeter Chen case OTG_STATE_A_WAIT_BCON:
911dfa91aaSPeter Chen otg_del_timer(fsm, A_WAIT_BCON);
921dfa91aaSPeter Chen fsm->a_wait_bcon_tmout = 0;
931dfa91aaSPeter Chen break;
941dfa91aaSPeter Chen case OTG_STATE_A_HOST:
951dfa91aaSPeter Chen otg_del_timer(fsm, A_WAIT_ENUM);
961dfa91aaSPeter Chen break;
971dfa91aaSPeter Chen case OTG_STATE_A_SUSPEND:
981dfa91aaSPeter Chen otg_del_timer(fsm, A_AIDL_BDIS);
991dfa91aaSPeter Chen fsm->a_aidl_bdis_tmout = 0;
1001dfa91aaSPeter Chen fsm->a_suspend_req_inf = 0;
1011dfa91aaSPeter Chen break;
1021dfa91aaSPeter Chen case OTG_STATE_A_PERIPHERAL:
1031dfa91aaSPeter Chen otg_del_timer(fsm, A_BIDL_ADIS);
1041dfa91aaSPeter Chen fsm->a_bidl_adis_tmout = 0;
105ae57e97aSLi Jun if (fsm->otg->gadget)
106ae57e97aSLi Jun fsm->otg->gadget->host_request_flag = 0;
1071dfa91aaSPeter Chen break;
1081dfa91aaSPeter Chen case OTG_STATE_A_WAIT_VFALL:
1091dfa91aaSPeter Chen otg_del_timer(fsm, A_WAIT_VFALL);
1101dfa91aaSPeter Chen fsm->a_wait_vfall_tmout = 0;
1111dfa91aaSPeter Chen otg_del_timer(fsm, A_WAIT_VRISE);
1121dfa91aaSPeter Chen break;
1131dfa91aaSPeter Chen case OTG_STATE_A_VBUS_ERR:
1141dfa91aaSPeter Chen break;
1151dfa91aaSPeter Chen default:
1161dfa91aaSPeter Chen break;
1171dfa91aaSPeter Chen }
1181dfa91aaSPeter Chen }
1191dfa91aaSPeter Chen
otg_hnp_polling_work(struct work_struct * work)120ae57e97aSLi Jun static void otg_hnp_polling_work(struct work_struct *work)
121ae57e97aSLi Jun {
122ae57e97aSLi Jun struct otg_fsm *fsm = container_of(to_delayed_work(work),
123ae57e97aSLi Jun struct otg_fsm, hnp_polling_work);
124ae57e97aSLi Jun struct usb_device *udev;
125ae57e97aSLi Jun enum usb_otg_state state = fsm->otg->state;
126ae57e97aSLi Jun u8 flag;
127ae57e97aSLi Jun int retval;
128ae57e97aSLi Jun
129ae57e97aSLi Jun if (state != OTG_STATE_A_HOST && state != OTG_STATE_B_HOST)
130ae57e97aSLi Jun return;
131ae57e97aSLi Jun
132ae57e97aSLi Jun udev = usb_hub_find_child(fsm->otg->host->root_hub, 1);
133ae57e97aSLi Jun if (!udev) {
134ae57e97aSLi Jun dev_err(fsm->otg->host->controller,
135ae57e97aSLi Jun "no usb dev connected, can't start HNP polling\n");
136ae57e97aSLi Jun return;
137ae57e97aSLi Jun }
138ae57e97aSLi Jun
139ae57e97aSLi Jun *fsm->host_req_flag = 0;
140ae57e97aSLi Jun /* Get host request flag from connected USB device */
141ae57e97aSLi Jun retval = usb_control_msg(udev,
142ae57e97aSLi Jun usb_rcvctrlpipe(udev, 0),
143ae57e97aSLi Jun USB_REQ_GET_STATUS,
144ae57e97aSLi Jun USB_DIR_IN | USB_RECIP_DEVICE,
145ae57e97aSLi Jun 0,
146ae57e97aSLi Jun OTG_STS_SELECTOR,
147ae57e97aSLi Jun fsm->host_req_flag,
148ae57e97aSLi Jun 1,
149ae57e97aSLi Jun USB_CTRL_GET_TIMEOUT);
150ae57e97aSLi Jun if (retval != 1) {
151ae57e97aSLi Jun dev_err(&udev->dev, "Get one byte OTG status failed\n");
152ae57e97aSLi Jun return;
153ae57e97aSLi Jun }
154ae57e97aSLi Jun
155ae57e97aSLi Jun flag = *fsm->host_req_flag;
156ae57e97aSLi Jun if (flag == 0) {
157ae57e97aSLi Jun /* Continue HNP polling */
158ae57e97aSLi Jun schedule_delayed_work(&fsm->hnp_polling_work,
159ae57e97aSLi Jun msecs_to_jiffies(T_HOST_REQ_POLL));
160ae57e97aSLi Jun return;
161ae57e97aSLi Jun } else if (flag != HOST_REQUEST_FLAG) {
162ae57e97aSLi Jun dev_err(&udev->dev, "host request flag %d is invalid\n", flag);
163ae57e97aSLi Jun return;
164ae57e97aSLi Jun }
165ae57e97aSLi Jun
166ae57e97aSLi Jun /* Host request flag is set */
167ae57e97aSLi Jun if (state == OTG_STATE_A_HOST) {
168ae57e97aSLi Jun /* Set b_hnp_enable */
169ae57e97aSLi Jun if (!fsm->otg->host->b_hnp_enable) {
170ae57e97aSLi Jun retval = usb_control_msg(udev,
171ae57e97aSLi Jun usb_sndctrlpipe(udev, 0),
172ae57e97aSLi Jun USB_REQ_SET_FEATURE, 0,
173ae57e97aSLi Jun USB_DEVICE_B_HNP_ENABLE,
174ae57e97aSLi Jun 0, NULL, 0,
175ae57e97aSLi Jun USB_CTRL_SET_TIMEOUT);
176ae57e97aSLi Jun if (retval >= 0)
177ae57e97aSLi Jun fsm->otg->host->b_hnp_enable = 1;
178ae57e97aSLi Jun }
179ae57e97aSLi Jun fsm->a_bus_req = 0;
180ae57e97aSLi Jun } else if (state == OTG_STATE_B_HOST) {
181ae57e97aSLi Jun fsm->b_bus_req = 0;
182ae57e97aSLi Jun }
183ae57e97aSLi Jun
184ae57e97aSLi Jun otg_statemachine(fsm);
185ae57e97aSLi Jun }
186ae57e97aSLi Jun
otg_start_hnp_polling(struct otg_fsm * fsm)187ae57e97aSLi Jun static void otg_start_hnp_polling(struct otg_fsm *fsm)
188ae57e97aSLi Jun {
189ae57e97aSLi Jun /*
190ae57e97aSLi Jun * The memory of host_req_flag should be allocated by
191ae57e97aSLi Jun * controller driver, otherwise, hnp polling is not started.
192ae57e97aSLi Jun */
193ae57e97aSLi Jun if (!fsm->host_req_flag)
194ae57e97aSLi Jun return;
195ae57e97aSLi Jun
196*bf88fef0SDmitry Osipenko if (!fsm->hnp_work_inited) {
197ae57e97aSLi Jun INIT_DELAYED_WORK(&fsm->hnp_polling_work, otg_hnp_polling_work);
198*bf88fef0SDmitry Osipenko fsm->hnp_work_inited = true;
199*bf88fef0SDmitry Osipenko }
200*bf88fef0SDmitry Osipenko
201ae57e97aSLi Jun schedule_delayed_work(&fsm->hnp_polling_work,
202ae57e97aSLi Jun msecs_to_jiffies(T_HOST_REQ_POLL));
203ae57e97aSLi Jun }
204ae57e97aSLi Jun
2051dfa91aaSPeter Chen /* Called when entering a state */
otg_set_state(struct otg_fsm * fsm,enum usb_otg_state new_state)2061dfa91aaSPeter Chen static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
2071dfa91aaSPeter Chen {
208e47d9254SAntoine Tenart if (fsm->otg->state == new_state)
2091dfa91aaSPeter Chen return 0;
2101dfa91aaSPeter Chen VDBG("Set state: %s\n", usb_otg_state_string(new_state));
211e47d9254SAntoine Tenart otg_leave_state(fsm, fsm->otg->state);
2121dfa91aaSPeter Chen switch (new_state) {
2131dfa91aaSPeter Chen case OTG_STATE_B_IDLE:
2141dfa91aaSPeter Chen otg_drv_vbus(fsm, 0);
2151dfa91aaSPeter Chen otg_chrg_vbus(fsm, 0);
2161dfa91aaSPeter Chen otg_loc_conn(fsm, 0);
2171dfa91aaSPeter Chen otg_loc_sof(fsm, 0);
2181dfa91aaSPeter Chen /*
2191dfa91aaSPeter Chen * Driver is responsible for starting ADP probing
2201dfa91aaSPeter Chen * if ADP sensing times out.
2211dfa91aaSPeter Chen */
2221dfa91aaSPeter Chen otg_start_adp_sns(fsm);
2231dfa91aaSPeter Chen otg_set_protocol(fsm, PROTO_UNDEF);
2241dfa91aaSPeter Chen otg_add_timer(fsm, B_SE0_SRP);
2251dfa91aaSPeter Chen break;
2261dfa91aaSPeter Chen case OTG_STATE_B_SRP_INIT:
2271dfa91aaSPeter Chen otg_start_pulse(fsm);
2281dfa91aaSPeter Chen otg_loc_sof(fsm, 0);
2291dfa91aaSPeter Chen otg_set_protocol(fsm, PROTO_UNDEF);
2301dfa91aaSPeter Chen otg_add_timer(fsm, B_SRP_FAIL);
2311dfa91aaSPeter Chen break;
2321dfa91aaSPeter Chen case OTG_STATE_B_PERIPHERAL:
2331dfa91aaSPeter Chen otg_chrg_vbus(fsm, 0);
2341dfa91aaSPeter Chen otg_loc_sof(fsm, 0);
2351dfa91aaSPeter Chen otg_set_protocol(fsm, PROTO_GADGET);
236a886bd92SPeter Chen otg_loc_conn(fsm, 1);
2371dfa91aaSPeter Chen break;
2381dfa91aaSPeter Chen case OTG_STATE_B_WAIT_ACON:
2391dfa91aaSPeter Chen otg_chrg_vbus(fsm, 0);
2401dfa91aaSPeter Chen otg_loc_conn(fsm, 0);
2411dfa91aaSPeter Chen otg_loc_sof(fsm, 0);
2421dfa91aaSPeter Chen otg_set_protocol(fsm, PROTO_HOST);
2431dfa91aaSPeter Chen otg_add_timer(fsm, B_ASE0_BRST);
2441dfa91aaSPeter Chen fsm->a_bus_suspend = 0;
2451dfa91aaSPeter Chen break;
2461dfa91aaSPeter Chen case OTG_STATE_B_HOST:
2471dfa91aaSPeter Chen otg_chrg_vbus(fsm, 0);
2481dfa91aaSPeter Chen otg_loc_conn(fsm, 0);
2491dfa91aaSPeter Chen otg_loc_sof(fsm, 1);
2501dfa91aaSPeter Chen otg_set_protocol(fsm, PROTO_HOST);
2511dfa91aaSPeter Chen usb_bus_start_enum(fsm->otg->host,
2521dfa91aaSPeter Chen fsm->otg->host->otg_port);
253ae57e97aSLi Jun otg_start_hnp_polling(fsm);
2541dfa91aaSPeter Chen break;
2551dfa91aaSPeter Chen case OTG_STATE_A_IDLE:
2561dfa91aaSPeter Chen otg_drv_vbus(fsm, 0);
2571dfa91aaSPeter Chen otg_chrg_vbus(fsm, 0);
2581dfa91aaSPeter Chen otg_loc_conn(fsm, 0);
2591dfa91aaSPeter Chen otg_loc_sof(fsm, 0);
2601dfa91aaSPeter Chen otg_start_adp_prb(fsm);
2611dfa91aaSPeter Chen otg_set_protocol(fsm, PROTO_HOST);
2621dfa91aaSPeter Chen break;
2631dfa91aaSPeter Chen case OTG_STATE_A_WAIT_VRISE:
2641dfa91aaSPeter Chen otg_drv_vbus(fsm, 1);
2651dfa91aaSPeter Chen otg_loc_conn(fsm, 0);
2661dfa91aaSPeter Chen otg_loc_sof(fsm, 0);
2671dfa91aaSPeter Chen otg_set_protocol(fsm, PROTO_HOST);
2681dfa91aaSPeter Chen otg_add_timer(fsm, A_WAIT_VRISE);
2691dfa91aaSPeter Chen break;
2701dfa91aaSPeter Chen case OTG_STATE_A_WAIT_BCON:
2711dfa91aaSPeter Chen otg_drv_vbus(fsm, 1);
2721dfa91aaSPeter Chen otg_loc_conn(fsm, 0);
2731dfa91aaSPeter Chen otg_loc_sof(fsm, 0);
2741dfa91aaSPeter Chen otg_set_protocol(fsm, PROTO_HOST);
2751dfa91aaSPeter Chen otg_add_timer(fsm, A_WAIT_BCON);
2761dfa91aaSPeter Chen break;
2771dfa91aaSPeter Chen case OTG_STATE_A_HOST:
2781dfa91aaSPeter Chen otg_drv_vbus(fsm, 1);
2791dfa91aaSPeter Chen otg_loc_conn(fsm, 0);
2801dfa91aaSPeter Chen otg_loc_sof(fsm, 1);
2811dfa91aaSPeter Chen otg_set_protocol(fsm, PROTO_HOST);
2821dfa91aaSPeter Chen /*
2831dfa91aaSPeter Chen * When HNP is triggered while a_bus_req = 0, a_host will
2841dfa91aaSPeter Chen * suspend too fast to complete a_set_b_hnp_en
2851dfa91aaSPeter Chen */
2861dfa91aaSPeter Chen if (!fsm->a_bus_req || fsm->a_suspend_req_inf)
2871dfa91aaSPeter Chen otg_add_timer(fsm, A_WAIT_ENUM);
288ae57e97aSLi Jun otg_start_hnp_polling(fsm);
2891dfa91aaSPeter Chen break;
2901dfa91aaSPeter Chen case OTG_STATE_A_SUSPEND:
2911dfa91aaSPeter Chen otg_drv_vbus(fsm, 1);
2921dfa91aaSPeter Chen otg_loc_conn(fsm, 0);
2931dfa91aaSPeter Chen otg_loc_sof(fsm, 0);
2941dfa91aaSPeter Chen otg_set_protocol(fsm, PROTO_HOST);
2951dfa91aaSPeter Chen otg_add_timer(fsm, A_AIDL_BDIS);
2961dfa91aaSPeter Chen
2971dfa91aaSPeter Chen break;
2981dfa91aaSPeter Chen case OTG_STATE_A_PERIPHERAL:
2991dfa91aaSPeter Chen otg_loc_sof(fsm, 0);
3001dfa91aaSPeter Chen otg_set_protocol(fsm, PROTO_GADGET);
3011dfa91aaSPeter Chen otg_drv_vbus(fsm, 1);
302a886bd92SPeter Chen otg_loc_conn(fsm, 1);
3031dfa91aaSPeter Chen otg_add_timer(fsm, A_BIDL_ADIS);
3041dfa91aaSPeter Chen break;
3051dfa91aaSPeter Chen case OTG_STATE_A_WAIT_VFALL:
3061dfa91aaSPeter Chen otg_drv_vbus(fsm, 0);
3071dfa91aaSPeter Chen otg_loc_conn(fsm, 0);
3081dfa91aaSPeter Chen otg_loc_sof(fsm, 0);
3091dfa91aaSPeter Chen otg_set_protocol(fsm, PROTO_HOST);
3101dfa91aaSPeter Chen otg_add_timer(fsm, A_WAIT_VFALL);
3111dfa91aaSPeter Chen break;
3121dfa91aaSPeter Chen case OTG_STATE_A_VBUS_ERR:
3131dfa91aaSPeter Chen otg_drv_vbus(fsm, 0);
3141dfa91aaSPeter Chen otg_loc_conn(fsm, 0);
3151dfa91aaSPeter Chen otg_loc_sof(fsm, 0);
3161dfa91aaSPeter Chen otg_set_protocol(fsm, PROTO_UNDEF);
3171dfa91aaSPeter Chen break;
3181dfa91aaSPeter Chen default:
3191dfa91aaSPeter Chen break;
3201dfa91aaSPeter Chen }
3211dfa91aaSPeter Chen
322e47d9254SAntoine Tenart fsm->otg->state = new_state;
3234e332df6SRoger Quadros fsm->state_changed = 1;
3241dfa91aaSPeter Chen return 0;
3251dfa91aaSPeter Chen }
3261dfa91aaSPeter Chen
3271dfa91aaSPeter Chen /* State change judgement */
otg_statemachine(struct otg_fsm * fsm)3281dfa91aaSPeter Chen int otg_statemachine(struct otg_fsm *fsm)
3291dfa91aaSPeter Chen {
3301dfa91aaSPeter Chen enum usb_otg_state state;
3311dfa91aaSPeter Chen
3321dfa91aaSPeter Chen mutex_lock(&fsm->lock);
3331dfa91aaSPeter Chen
334e47d9254SAntoine Tenart state = fsm->otg->state;
3354e332df6SRoger Quadros fsm->state_changed = 0;
3361dfa91aaSPeter Chen /* State machine state change judgement */
3371dfa91aaSPeter Chen
3381dfa91aaSPeter Chen switch (state) {
3391dfa91aaSPeter Chen case OTG_STATE_UNDEFINED:
3401dfa91aaSPeter Chen VDBG("fsm->id = %d\n", fsm->id);
3411dfa91aaSPeter Chen if (fsm->id)
3421dfa91aaSPeter Chen otg_set_state(fsm, OTG_STATE_B_IDLE);
3431dfa91aaSPeter Chen else
3441dfa91aaSPeter Chen otg_set_state(fsm, OTG_STATE_A_IDLE);
3451dfa91aaSPeter Chen break;
3461dfa91aaSPeter Chen case OTG_STATE_B_IDLE:
3471dfa91aaSPeter Chen if (!fsm->id)
3481dfa91aaSPeter Chen otg_set_state(fsm, OTG_STATE_A_IDLE);
3491dfa91aaSPeter Chen else if (fsm->b_sess_vld && fsm->otg->gadget)
3501dfa91aaSPeter Chen otg_set_state(fsm, OTG_STATE_B_PERIPHERAL);
3511dfa91aaSPeter Chen else if ((fsm->b_bus_req || fsm->adp_change || fsm->power_up) &&
3521dfa91aaSPeter Chen fsm->b_ssend_srp && fsm->b_se0_srp)
3531dfa91aaSPeter Chen otg_set_state(fsm, OTG_STATE_B_SRP_INIT);
3541dfa91aaSPeter Chen break;
3551dfa91aaSPeter Chen case OTG_STATE_B_SRP_INIT:
3561dfa91aaSPeter Chen if (!fsm->id || fsm->b_srp_done)
3571dfa91aaSPeter Chen otg_set_state(fsm, OTG_STATE_B_IDLE);
3581dfa91aaSPeter Chen break;
3591dfa91aaSPeter Chen case OTG_STATE_B_PERIPHERAL:
3601dfa91aaSPeter Chen if (!fsm->id || !fsm->b_sess_vld)
3611dfa91aaSPeter Chen otg_set_state(fsm, OTG_STATE_B_IDLE);
3621dfa91aaSPeter Chen else if (fsm->b_bus_req && fsm->otg->
3631dfa91aaSPeter Chen gadget->b_hnp_enable && fsm->a_bus_suspend)
3641dfa91aaSPeter Chen otg_set_state(fsm, OTG_STATE_B_WAIT_ACON);
3651dfa91aaSPeter Chen break;
3661dfa91aaSPeter Chen case OTG_STATE_B_WAIT_ACON:
3671dfa91aaSPeter Chen if (fsm->a_conn)
3681dfa91aaSPeter Chen otg_set_state(fsm, OTG_STATE_B_HOST);
3691dfa91aaSPeter Chen else if (!fsm->id || !fsm->b_sess_vld)
3701dfa91aaSPeter Chen otg_set_state(fsm, OTG_STATE_B_IDLE);
3711dfa91aaSPeter Chen else if (fsm->a_bus_resume || fsm->b_ase0_brst_tmout) {
3721dfa91aaSPeter Chen fsm->b_ase0_brst_tmout = 0;
3731dfa91aaSPeter Chen otg_set_state(fsm, OTG_STATE_B_PERIPHERAL);
3741dfa91aaSPeter Chen }
3751dfa91aaSPeter Chen break;
3761dfa91aaSPeter Chen case OTG_STATE_B_HOST:
3771dfa91aaSPeter Chen if (!fsm->id || !fsm->b_sess_vld)
3781dfa91aaSPeter Chen otg_set_state(fsm, OTG_STATE_B_IDLE);
3791dfa91aaSPeter Chen else if (!fsm->b_bus_req || !fsm->a_conn || fsm->test_device)
3801dfa91aaSPeter Chen otg_set_state(fsm, OTG_STATE_B_PERIPHERAL);
3811dfa91aaSPeter Chen break;
3821dfa91aaSPeter Chen case OTG_STATE_A_IDLE:
3831dfa91aaSPeter Chen if (fsm->id)
3841dfa91aaSPeter Chen otg_set_state(fsm, OTG_STATE_B_IDLE);
3851dfa91aaSPeter Chen else if (!fsm->a_bus_drop && (fsm->a_bus_req ||
3861dfa91aaSPeter Chen fsm->a_srp_det || fsm->adp_change || fsm->power_up))
3871dfa91aaSPeter Chen otg_set_state(fsm, OTG_STATE_A_WAIT_VRISE);
3881dfa91aaSPeter Chen break;
3891dfa91aaSPeter Chen case OTG_STATE_A_WAIT_VRISE:
3901dfa91aaSPeter Chen if (fsm->a_vbus_vld)
3911dfa91aaSPeter Chen otg_set_state(fsm, OTG_STATE_A_WAIT_BCON);
3921dfa91aaSPeter Chen else if (fsm->id || fsm->a_bus_drop ||
3931dfa91aaSPeter Chen fsm->a_wait_vrise_tmout)
3941dfa91aaSPeter Chen otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL);
3951dfa91aaSPeter Chen break;
3961dfa91aaSPeter Chen case OTG_STATE_A_WAIT_BCON:
3971dfa91aaSPeter Chen if (!fsm->a_vbus_vld)
3981dfa91aaSPeter Chen otg_set_state(fsm, OTG_STATE_A_VBUS_ERR);
3991dfa91aaSPeter Chen else if (fsm->b_conn)
4001dfa91aaSPeter Chen otg_set_state(fsm, OTG_STATE_A_HOST);
4011dfa91aaSPeter Chen else if (fsm->id || fsm->a_bus_drop || fsm->a_wait_bcon_tmout)
4021dfa91aaSPeter Chen otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL);
4031dfa91aaSPeter Chen break;
4041dfa91aaSPeter Chen case OTG_STATE_A_HOST:
4051dfa91aaSPeter Chen if (fsm->id || fsm->a_bus_drop)
4061dfa91aaSPeter Chen otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL);
4071dfa91aaSPeter Chen else if ((!fsm->a_bus_req || fsm->a_suspend_req_inf) &&
4081dfa91aaSPeter Chen fsm->otg->host->b_hnp_enable)
4091dfa91aaSPeter Chen otg_set_state(fsm, OTG_STATE_A_SUSPEND);
4101dfa91aaSPeter Chen else if (!fsm->b_conn)
4111dfa91aaSPeter Chen otg_set_state(fsm, OTG_STATE_A_WAIT_BCON);
4121dfa91aaSPeter Chen else if (!fsm->a_vbus_vld)
4131dfa91aaSPeter Chen otg_set_state(fsm, OTG_STATE_A_VBUS_ERR);
4141dfa91aaSPeter Chen break;
4151dfa91aaSPeter Chen case OTG_STATE_A_SUSPEND:
4161dfa91aaSPeter Chen if (!fsm->b_conn && fsm->otg->host->b_hnp_enable)
4171dfa91aaSPeter Chen otg_set_state(fsm, OTG_STATE_A_PERIPHERAL);
4181dfa91aaSPeter Chen else if (!fsm->b_conn && !fsm->otg->host->b_hnp_enable)
4191dfa91aaSPeter Chen otg_set_state(fsm, OTG_STATE_A_WAIT_BCON);
4201dfa91aaSPeter Chen else if (fsm->a_bus_req || fsm->b_bus_resume)
4211dfa91aaSPeter Chen otg_set_state(fsm, OTG_STATE_A_HOST);
4221dfa91aaSPeter Chen else if (fsm->id || fsm->a_bus_drop || fsm->a_aidl_bdis_tmout)
4231dfa91aaSPeter Chen otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL);
4241dfa91aaSPeter Chen else if (!fsm->a_vbus_vld)
4251dfa91aaSPeter Chen otg_set_state(fsm, OTG_STATE_A_VBUS_ERR);
4261dfa91aaSPeter Chen break;
4271dfa91aaSPeter Chen case OTG_STATE_A_PERIPHERAL:
4281dfa91aaSPeter Chen if (fsm->id || fsm->a_bus_drop)
4291dfa91aaSPeter Chen otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL);
4301dfa91aaSPeter Chen else if (fsm->a_bidl_adis_tmout || fsm->b_bus_suspend)
4311dfa91aaSPeter Chen otg_set_state(fsm, OTG_STATE_A_WAIT_BCON);
4321dfa91aaSPeter Chen else if (!fsm->a_vbus_vld)
4331dfa91aaSPeter Chen otg_set_state(fsm, OTG_STATE_A_VBUS_ERR);
4341dfa91aaSPeter Chen break;
4351dfa91aaSPeter Chen case OTG_STATE_A_WAIT_VFALL:
4361dfa91aaSPeter Chen if (fsm->a_wait_vfall_tmout)
4371dfa91aaSPeter Chen otg_set_state(fsm, OTG_STATE_A_IDLE);
4381dfa91aaSPeter Chen break;
4391dfa91aaSPeter Chen case OTG_STATE_A_VBUS_ERR:
4401dfa91aaSPeter Chen if (fsm->id || fsm->a_bus_drop || fsm->a_clr_err)
4411dfa91aaSPeter Chen otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL);
4421dfa91aaSPeter Chen break;
4431dfa91aaSPeter Chen default:
4441dfa91aaSPeter Chen break;
4451dfa91aaSPeter Chen }
4461dfa91aaSPeter Chen mutex_unlock(&fsm->lock);
4471dfa91aaSPeter Chen
4484e332df6SRoger Quadros VDBG("quit statemachine, changed = %d\n", fsm->state_changed);
4494e332df6SRoger Quadros return fsm->state_changed;
4501dfa91aaSPeter Chen }
4511dfa91aaSPeter Chen EXPORT_SYMBOL_GPL(otg_statemachine);
452ea1d39a3SOscar MODULE_LICENSE("GPL");
453