162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * OTG Finite State Machine from OTG spec 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2007,2008 Freescale Semiconductor, Inc. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Author: Li Yang <LeoLi@freescale.com> 862306a36Sopenharmony_ci * Jerry Huang <Chang-Ming.Huang@freescale.com> 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/module.h> 1262306a36Sopenharmony_ci#include <linux/kernel.h> 1362306a36Sopenharmony_ci#include <linux/types.h> 1462306a36Sopenharmony_ci#include <linux/mutex.h> 1562306a36Sopenharmony_ci#include <linux/delay.h> 1662306a36Sopenharmony_ci#include <linux/usb.h> 1762306a36Sopenharmony_ci#include <linux/usb/gadget.h> 1862306a36Sopenharmony_ci#include <linux/usb/otg.h> 1962306a36Sopenharmony_ci#include <linux/usb/otg-fsm.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#ifdef VERBOSE 2262306a36Sopenharmony_ci#define VDBG(fmt, args...) pr_debug("[%s] " fmt, \ 2362306a36Sopenharmony_ci __func__, ## args) 2462306a36Sopenharmony_ci#else 2562306a36Sopenharmony_ci#define VDBG(stuff...) do {} while (0) 2662306a36Sopenharmony_ci#endif 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/* Change USB protocol when there is a protocol change */ 2962306a36Sopenharmony_cistatic int otg_set_protocol(struct otg_fsm *fsm, int protocol) 3062306a36Sopenharmony_ci{ 3162306a36Sopenharmony_ci int ret = 0; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci if (fsm->protocol != protocol) { 3462306a36Sopenharmony_ci VDBG("Changing role fsm->protocol= %d; new protocol= %d\n", 3562306a36Sopenharmony_ci fsm->protocol, protocol); 3662306a36Sopenharmony_ci /* stop old protocol */ 3762306a36Sopenharmony_ci if (fsm->protocol == PROTO_HOST) 3862306a36Sopenharmony_ci ret = otg_start_host(fsm, 0); 3962306a36Sopenharmony_ci else if (fsm->protocol == PROTO_GADGET) 4062306a36Sopenharmony_ci ret = otg_start_gadget(fsm, 0); 4162306a36Sopenharmony_ci if (ret) 4262306a36Sopenharmony_ci return ret; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci /* start new protocol */ 4562306a36Sopenharmony_ci if (protocol == PROTO_HOST) 4662306a36Sopenharmony_ci ret = otg_start_host(fsm, 1); 4762306a36Sopenharmony_ci else if (protocol == PROTO_GADGET) 4862306a36Sopenharmony_ci ret = otg_start_gadget(fsm, 1); 4962306a36Sopenharmony_ci if (ret) 5062306a36Sopenharmony_ci return ret; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci fsm->protocol = protocol; 5362306a36Sopenharmony_ci return 0; 5462306a36Sopenharmony_ci } 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci return 0; 5762306a36Sopenharmony_ci} 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci/* Called when leaving a state. Do state clean up jobs here */ 6062306a36Sopenharmony_cistatic void otg_leave_state(struct otg_fsm *fsm, enum usb_otg_state old_state) 6162306a36Sopenharmony_ci{ 6262306a36Sopenharmony_ci switch (old_state) { 6362306a36Sopenharmony_ci case OTG_STATE_B_IDLE: 6462306a36Sopenharmony_ci otg_del_timer(fsm, B_SE0_SRP); 6562306a36Sopenharmony_ci fsm->b_se0_srp = 0; 6662306a36Sopenharmony_ci fsm->adp_sns = 0; 6762306a36Sopenharmony_ci fsm->adp_prb = 0; 6862306a36Sopenharmony_ci break; 6962306a36Sopenharmony_ci case OTG_STATE_B_SRP_INIT: 7062306a36Sopenharmony_ci fsm->data_pulse = 0; 7162306a36Sopenharmony_ci fsm->b_srp_done = 0; 7262306a36Sopenharmony_ci break; 7362306a36Sopenharmony_ci case OTG_STATE_B_PERIPHERAL: 7462306a36Sopenharmony_ci if (fsm->otg->gadget) 7562306a36Sopenharmony_ci fsm->otg->gadget->host_request_flag = 0; 7662306a36Sopenharmony_ci break; 7762306a36Sopenharmony_ci case OTG_STATE_B_WAIT_ACON: 7862306a36Sopenharmony_ci otg_del_timer(fsm, B_ASE0_BRST); 7962306a36Sopenharmony_ci fsm->b_ase0_brst_tmout = 0; 8062306a36Sopenharmony_ci break; 8162306a36Sopenharmony_ci case OTG_STATE_B_HOST: 8262306a36Sopenharmony_ci break; 8362306a36Sopenharmony_ci case OTG_STATE_A_IDLE: 8462306a36Sopenharmony_ci fsm->adp_prb = 0; 8562306a36Sopenharmony_ci break; 8662306a36Sopenharmony_ci case OTG_STATE_A_WAIT_VRISE: 8762306a36Sopenharmony_ci otg_del_timer(fsm, A_WAIT_VRISE); 8862306a36Sopenharmony_ci fsm->a_wait_vrise_tmout = 0; 8962306a36Sopenharmony_ci break; 9062306a36Sopenharmony_ci case OTG_STATE_A_WAIT_BCON: 9162306a36Sopenharmony_ci otg_del_timer(fsm, A_WAIT_BCON); 9262306a36Sopenharmony_ci fsm->a_wait_bcon_tmout = 0; 9362306a36Sopenharmony_ci break; 9462306a36Sopenharmony_ci case OTG_STATE_A_HOST: 9562306a36Sopenharmony_ci otg_del_timer(fsm, A_WAIT_ENUM); 9662306a36Sopenharmony_ci break; 9762306a36Sopenharmony_ci case OTG_STATE_A_SUSPEND: 9862306a36Sopenharmony_ci otg_del_timer(fsm, A_AIDL_BDIS); 9962306a36Sopenharmony_ci fsm->a_aidl_bdis_tmout = 0; 10062306a36Sopenharmony_ci fsm->a_suspend_req_inf = 0; 10162306a36Sopenharmony_ci break; 10262306a36Sopenharmony_ci case OTG_STATE_A_PERIPHERAL: 10362306a36Sopenharmony_ci otg_del_timer(fsm, A_BIDL_ADIS); 10462306a36Sopenharmony_ci fsm->a_bidl_adis_tmout = 0; 10562306a36Sopenharmony_ci if (fsm->otg->gadget) 10662306a36Sopenharmony_ci fsm->otg->gadget->host_request_flag = 0; 10762306a36Sopenharmony_ci break; 10862306a36Sopenharmony_ci case OTG_STATE_A_WAIT_VFALL: 10962306a36Sopenharmony_ci otg_del_timer(fsm, A_WAIT_VFALL); 11062306a36Sopenharmony_ci fsm->a_wait_vfall_tmout = 0; 11162306a36Sopenharmony_ci otg_del_timer(fsm, A_WAIT_VRISE); 11262306a36Sopenharmony_ci break; 11362306a36Sopenharmony_ci case OTG_STATE_A_VBUS_ERR: 11462306a36Sopenharmony_ci break; 11562306a36Sopenharmony_ci default: 11662306a36Sopenharmony_ci break; 11762306a36Sopenharmony_ci } 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cistatic void otg_hnp_polling_work(struct work_struct *work) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci struct otg_fsm *fsm = container_of(to_delayed_work(work), 12362306a36Sopenharmony_ci struct otg_fsm, hnp_polling_work); 12462306a36Sopenharmony_ci struct usb_device *udev; 12562306a36Sopenharmony_ci enum usb_otg_state state = fsm->otg->state; 12662306a36Sopenharmony_ci u8 flag; 12762306a36Sopenharmony_ci int retval; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci if (state != OTG_STATE_A_HOST && state != OTG_STATE_B_HOST) 13062306a36Sopenharmony_ci return; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci udev = usb_hub_find_child(fsm->otg->host->root_hub, 1); 13362306a36Sopenharmony_ci if (!udev) { 13462306a36Sopenharmony_ci dev_err(fsm->otg->host->controller, 13562306a36Sopenharmony_ci "no usb dev connected, can't start HNP polling\n"); 13662306a36Sopenharmony_ci return; 13762306a36Sopenharmony_ci } 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci *fsm->host_req_flag = 0; 14062306a36Sopenharmony_ci /* Get host request flag from connected USB device */ 14162306a36Sopenharmony_ci retval = usb_control_msg(udev, 14262306a36Sopenharmony_ci usb_rcvctrlpipe(udev, 0), 14362306a36Sopenharmony_ci USB_REQ_GET_STATUS, 14462306a36Sopenharmony_ci USB_DIR_IN | USB_RECIP_DEVICE, 14562306a36Sopenharmony_ci 0, 14662306a36Sopenharmony_ci OTG_STS_SELECTOR, 14762306a36Sopenharmony_ci fsm->host_req_flag, 14862306a36Sopenharmony_ci 1, 14962306a36Sopenharmony_ci USB_CTRL_GET_TIMEOUT); 15062306a36Sopenharmony_ci if (retval != 1) { 15162306a36Sopenharmony_ci dev_err(&udev->dev, "Get one byte OTG status failed\n"); 15262306a36Sopenharmony_ci return; 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci flag = *fsm->host_req_flag; 15662306a36Sopenharmony_ci if (flag == 0) { 15762306a36Sopenharmony_ci /* Continue HNP polling */ 15862306a36Sopenharmony_ci schedule_delayed_work(&fsm->hnp_polling_work, 15962306a36Sopenharmony_ci msecs_to_jiffies(T_HOST_REQ_POLL)); 16062306a36Sopenharmony_ci return; 16162306a36Sopenharmony_ci } else if (flag != HOST_REQUEST_FLAG) { 16262306a36Sopenharmony_ci dev_err(&udev->dev, "host request flag %d is invalid\n", flag); 16362306a36Sopenharmony_ci return; 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci /* Host request flag is set */ 16762306a36Sopenharmony_ci if (state == OTG_STATE_A_HOST) { 16862306a36Sopenharmony_ci /* Set b_hnp_enable */ 16962306a36Sopenharmony_ci if (!fsm->otg->host->b_hnp_enable) { 17062306a36Sopenharmony_ci retval = usb_control_msg(udev, 17162306a36Sopenharmony_ci usb_sndctrlpipe(udev, 0), 17262306a36Sopenharmony_ci USB_REQ_SET_FEATURE, 0, 17362306a36Sopenharmony_ci USB_DEVICE_B_HNP_ENABLE, 17462306a36Sopenharmony_ci 0, NULL, 0, 17562306a36Sopenharmony_ci USB_CTRL_SET_TIMEOUT); 17662306a36Sopenharmony_ci if (retval >= 0) 17762306a36Sopenharmony_ci fsm->otg->host->b_hnp_enable = 1; 17862306a36Sopenharmony_ci } 17962306a36Sopenharmony_ci fsm->a_bus_req = 0; 18062306a36Sopenharmony_ci } else if (state == OTG_STATE_B_HOST) { 18162306a36Sopenharmony_ci fsm->b_bus_req = 0; 18262306a36Sopenharmony_ci } 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci otg_statemachine(fsm); 18562306a36Sopenharmony_ci} 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_cistatic void otg_start_hnp_polling(struct otg_fsm *fsm) 18862306a36Sopenharmony_ci{ 18962306a36Sopenharmony_ci /* 19062306a36Sopenharmony_ci * The memory of host_req_flag should be allocated by 19162306a36Sopenharmony_ci * controller driver, otherwise, hnp polling is not started. 19262306a36Sopenharmony_ci */ 19362306a36Sopenharmony_ci if (!fsm->host_req_flag) 19462306a36Sopenharmony_ci return; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci if (!fsm->hnp_work_inited) { 19762306a36Sopenharmony_ci INIT_DELAYED_WORK(&fsm->hnp_polling_work, otg_hnp_polling_work); 19862306a36Sopenharmony_ci fsm->hnp_work_inited = true; 19962306a36Sopenharmony_ci } 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci schedule_delayed_work(&fsm->hnp_polling_work, 20262306a36Sopenharmony_ci msecs_to_jiffies(T_HOST_REQ_POLL)); 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci/* Called when entering a state */ 20662306a36Sopenharmony_cistatic int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci if (fsm->otg->state == new_state) 20962306a36Sopenharmony_ci return 0; 21062306a36Sopenharmony_ci VDBG("Set state: %s\n", usb_otg_state_string(new_state)); 21162306a36Sopenharmony_ci otg_leave_state(fsm, fsm->otg->state); 21262306a36Sopenharmony_ci switch (new_state) { 21362306a36Sopenharmony_ci case OTG_STATE_B_IDLE: 21462306a36Sopenharmony_ci otg_drv_vbus(fsm, 0); 21562306a36Sopenharmony_ci otg_chrg_vbus(fsm, 0); 21662306a36Sopenharmony_ci otg_loc_conn(fsm, 0); 21762306a36Sopenharmony_ci otg_loc_sof(fsm, 0); 21862306a36Sopenharmony_ci /* 21962306a36Sopenharmony_ci * Driver is responsible for starting ADP probing 22062306a36Sopenharmony_ci * if ADP sensing times out. 22162306a36Sopenharmony_ci */ 22262306a36Sopenharmony_ci otg_start_adp_sns(fsm); 22362306a36Sopenharmony_ci otg_set_protocol(fsm, PROTO_UNDEF); 22462306a36Sopenharmony_ci otg_add_timer(fsm, B_SE0_SRP); 22562306a36Sopenharmony_ci break; 22662306a36Sopenharmony_ci case OTG_STATE_B_SRP_INIT: 22762306a36Sopenharmony_ci otg_start_pulse(fsm); 22862306a36Sopenharmony_ci otg_loc_sof(fsm, 0); 22962306a36Sopenharmony_ci otg_set_protocol(fsm, PROTO_UNDEF); 23062306a36Sopenharmony_ci otg_add_timer(fsm, B_SRP_FAIL); 23162306a36Sopenharmony_ci break; 23262306a36Sopenharmony_ci case OTG_STATE_B_PERIPHERAL: 23362306a36Sopenharmony_ci otg_chrg_vbus(fsm, 0); 23462306a36Sopenharmony_ci otg_loc_sof(fsm, 0); 23562306a36Sopenharmony_ci otg_set_protocol(fsm, PROTO_GADGET); 23662306a36Sopenharmony_ci otg_loc_conn(fsm, 1); 23762306a36Sopenharmony_ci break; 23862306a36Sopenharmony_ci case OTG_STATE_B_WAIT_ACON: 23962306a36Sopenharmony_ci otg_chrg_vbus(fsm, 0); 24062306a36Sopenharmony_ci otg_loc_conn(fsm, 0); 24162306a36Sopenharmony_ci otg_loc_sof(fsm, 0); 24262306a36Sopenharmony_ci otg_set_protocol(fsm, PROTO_HOST); 24362306a36Sopenharmony_ci otg_add_timer(fsm, B_ASE0_BRST); 24462306a36Sopenharmony_ci fsm->a_bus_suspend = 0; 24562306a36Sopenharmony_ci break; 24662306a36Sopenharmony_ci case OTG_STATE_B_HOST: 24762306a36Sopenharmony_ci otg_chrg_vbus(fsm, 0); 24862306a36Sopenharmony_ci otg_loc_conn(fsm, 0); 24962306a36Sopenharmony_ci otg_loc_sof(fsm, 1); 25062306a36Sopenharmony_ci otg_set_protocol(fsm, PROTO_HOST); 25162306a36Sopenharmony_ci usb_bus_start_enum(fsm->otg->host, 25262306a36Sopenharmony_ci fsm->otg->host->otg_port); 25362306a36Sopenharmony_ci otg_start_hnp_polling(fsm); 25462306a36Sopenharmony_ci break; 25562306a36Sopenharmony_ci case OTG_STATE_A_IDLE: 25662306a36Sopenharmony_ci otg_drv_vbus(fsm, 0); 25762306a36Sopenharmony_ci otg_chrg_vbus(fsm, 0); 25862306a36Sopenharmony_ci otg_loc_conn(fsm, 0); 25962306a36Sopenharmony_ci otg_loc_sof(fsm, 0); 26062306a36Sopenharmony_ci otg_start_adp_prb(fsm); 26162306a36Sopenharmony_ci otg_set_protocol(fsm, PROTO_HOST); 26262306a36Sopenharmony_ci break; 26362306a36Sopenharmony_ci case OTG_STATE_A_WAIT_VRISE: 26462306a36Sopenharmony_ci otg_drv_vbus(fsm, 1); 26562306a36Sopenharmony_ci otg_loc_conn(fsm, 0); 26662306a36Sopenharmony_ci otg_loc_sof(fsm, 0); 26762306a36Sopenharmony_ci otg_set_protocol(fsm, PROTO_HOST); 26862306a36Sopenharmony_ci otg_add_timer(fsm, A_WAIT_VRISE); 26962306a36Sopenharmony_ci break; 27062306a36Sopenharmony_ci case OTG_STATE_A_WAIT_BCON: 27162306a36Sopenharmony_ci otg_drv_vbus(fsm, 1); 27262306a36Sopenharmony_ci otg_loc_conn(fsm, 0); 27362306a36Sopenharmony_ci otg_loc_sof(fsm, 0); 27462306a36Sopenharmony_ci otg_set_protocol(fsm, PROTO_HOST); 27562306a36Sopenharmony_ci otg_add_timer(fsm, A_WAIT_BCON); 27662306a36Sopenharmony_ci break; 27762306a36Sopenharmony_ci case OTG_STATE_A_HOST: 27862306a36Sopenharmony_ci otg_drv_vbus(fsm, 1); 27962306a36Sopenharmony_ci otg_loc_conn(fsm, 0); 28062306a36Sopenharmony_ci otg_loc_sof(fsm, 1); 28162306a36Sopenharmony_ci otg_set_protocol(fsm, PROTO_HOST); 28262306a36Sopenharmony_ci /* 28362306a36Sopenharmony_ci * When HNP is triggered while a_bus_req = 0, a_host will 28462306a36Sopenharmony_ci * suspend too fast to complete a_set_b_hnp_en 28562306a36Sopenharmony_ci */ 28662306a36Sopenharmony_ci if (!fsm->a_bus_req || fsm->a_suspend_req_inf) 28762306a36Sopenharmony_ci otg_add_timer(fsm, A_WAIT_ENUM); 28862306a36Sopenharmony_ci otg_start_hnp_polling(fsm); 28962306a36Sopenharmony_ci break; 29062306a36Sopenharmony_ci case OTG_STATE_A_SUSPEND: 29162306a36Sopenharmony_ci otg_drv_vbus(fsm, 1); 29262306a36Sopenharmony_ci otg_loc_conn(fsm, 0); 29362306a36Sopenharmony_ci otg_loc_sof(fsm, 0); 29462306a36Sopenharmony_ci otg_set_protocol(fsm, PROTO_HOST); 29562306a36Sopenharmony_ci otg_add_timer(fsm, A_AIDL_BDIS); 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci break; 29862306a36Sopenharmony_ci case OTG_STATE_A_PERIPHERAL: 29962306a36Sopenharmony_ci otg_loc_sof(fsm, 0); 30062306a36Sopenharmony_ci otg_set_protocol(fsm, PROTO_GADGET); 30162306a36Sopenharmony_ci otg_drv_vbus(fsm, 1); 30262306a36Sopenharmony_ci otg_loc_conn(fsm, 1); 30362306a36Sopenharmony_ci otg_add_timer(fsm, A_BIDL_ADIS); 30462306a36Sopenharmony_ci break; 30562306a36Sopenharmony_ci case OTG_STATE_A_WAIT_VFALL: 30662306a36Sopenharmony_ci otg_drv_vbus(fsm, 0); 30762306a36Sopenharmony_ci otg_loc_conn(fsm, 0); 30862306a36Sopenharmony_ci otg_loc_sof(fsm, 0); 30962306a36Sopenharmony_ci otg_set_protocol(fsm, PROTO_HOST); 31062306a36Sopenharmony_ci otg_add_timer(fsm, A_WAIT_VFALL); 31162306a36Sopenharmony_ci break; 31262306a36Sopenharmony_ci case OTG_STATE_A_VBUS_ERR: 31362306a36Sopenharmony_ci otg_drv_vbus(fsm, 0); 31462306a36Sopenharmony_ci otg_loc_conn(fsm, 0); 31562306a36Sopenharmony_ci otg_loc_sof(fsm, 0); 31662306a36Sopenharmony_ci otg_set_protocol(fsm, PROTO_UNDEF); 31762306a36Sopenharmony_ci break; 31862306a36Sopenharmony_ci default: 31962306a36Sopenharmony_ci break; 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci fsm->otg->state = new_state; 32362306a36Sopenharmony_ci fsm->state_changed = 1; 32462306a36Sopenharmony_ci return 0; 32562306a36Sopenharmony_ci} 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci/* State change judgement */ 32862306a36Sopenharmony_ciint otg_statemachine(struct otg_fsm *fsm) 32962306a36Sopenharmony_ci{ 33062306a36Sopenharmony_ci enum usb_otg_state state; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci mutex_lock(&fsm->lock); 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci state = fsm->otg->state; 33562306a36Sopenharmony_ci fsm->state_changed = 0; 33662306a36Sopenharmony_ci /* State machine state change judgement */ 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci switch (state) { 33962306a36Sopenharmony_ci case OTG_STATE_UNDEFINED: 34062306a36Sopenharmony_ci VDBG("fsm->id = %d\n", fsm->id); 34162306a36Sopenharmony_ci if (fsm->id) 34262306a36Sopenharmony_ci otg_set_state(fsm, OTG_STATE_B_IDLE); 34362306a36Sopenharmony_ci else 34462306a36Sopenharmony_ci otg_set_state(fsm, OTG_STATE_A_IDLE); 34562306a36Sopenharmony_ci break; 34662306a36Sopenharmony_ci case OTG_STATE_B_IDLE: 34762306a36Sopenharmony_ci if (!fsm->id) 34862306a36Sopenharmony_ci otg_set_state(fsm, OTG_STATE_A_IDLE); 34962306a36Sopenharmony_ci else if (fsm->b_sess_vld && fsm->otg->gadget) 35062306a36Sopenharmony_ci otg_set_state(fsm, OTG_STATE_B_PERIPHERAL); 35162306a36Sopenharmony_ci else if ((fsm->b_bus_req || fsm->adp_change || fsm->power_up) && 35262306a36Sopenharmony_ci fsm->b_ssend_srp && fsm->b_se0_srp) 35362306a36Sopenharmony_ci otg_set_state(fsm, OTG_STATE_B_SRP_INIT); 35462306a36Sopenharmony_ci break; 35562306a36Sopenharmony_ci case OTG_STATE_B_SRP_INIT: 35662306a36Sopenharmony_ci if (!fsm->id || fsm->b_srp_done) 35762306a36Sopenharmony_ci otg_set_state(fsm, OTG_STATE_B_IDLE); 35862306a36Sopenharmony_ci break; 35962306a36Sopenharmony_ci case OTG_STATE_B_PERIPHERAL: 36062306a36Sopenharmony_ci if (!fsm->id || !fsm->b_sess_vld) 36162306a36Sopenharmony_ci otg_set_state(fsm, OTG_STATE_B_IDLE); 36262306a36Sopenharmony_ci else if (fsm->b_bus_req && fsm->otg-> 36362306a36Sopenharmony_ci gadget->b_hnp_enable && fsm->a_bus_suspend) 36462306a36Sopenharmony_ci otg_set_state(fsm, OTG_STATE_B_WAIT_ACON); 36562306a36Sopenharmony_ci break; 36662306a36Sopenharmony_ci case OTG_STATE_B_WAIT_ACON: 36762306a36Sopenharmony_ci if (fsm->a_conn) 36862306a36Sopenharmony_ci otg_set_state(fsm, OTG_STATE_B_HOST); 36962306a36Sopenharmony_ci else if (!fsm->id || !fsm->b_sess_vld) 37062306a36Sopenharmony_ci otg_set_state(fsm, OTG_STATE_B_IDLE); 37162306a36Sopenharmony_ci else if (fsm->a_bus_resume || fsm->b_ase0_brst_tmout) { 37262306a36Sopenharmony_ci fsm->b_ase0_brst_tmout = 0; 37362306a36Sopenharmony_ci otg_set_state(fsm, OTG_STATE_B_PERIPHERAL); 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci break; 37662306a36Sopenharmony_ci case OTG_STATE_B_HOST: 37762306a36Sopenharmony_ci if (!fsm->id || !fsm->b_sess_vld) 37862306a36Sopenharmony_ci otg_set_state(fsm, OTG_STATE_B_IDLE); 37962306a36Sopenharmony_ci else if (!fsm->b_bus_req || !fsm->a_conn || fsm->test_device) 38062306a36Sopenharmony_ci otg_set_state(fsm, OTG_STATE_B_PERIPHERAL); 38162306a36Sopenharmony_ci break; 38262306a36Sopenharmony_ci case OTG_STATE_A_IDLE: 38362306a36Sopenharmony_ci if (fsm->id) 38462306a36Sopenharmony_ci otg_set_state(fsm, OTG_STATE_B_IDLE); 38562306a36Sopenharmony_ci else if (!fsm->a_bus_drop && (fsm->a_bus_req || 38662306a36Sopenharmony_ci fsm->a_srp_det || fsm->adp_change || fsm->power_up)) 38762306a36Sopenharmony_ci otg_set_state(fsm, OTG_STATE_A_WAIT_VRISE); 38862306a36Sopenharmony_ci break; 38962306a36Sopenharmony_ci case OTG_STATE_A_WAIT_VRISE: 39062306a36Sopenharmony_ci if (fsm->a_vbus_vld) 39162306a36Sopenharmony_ci otg_set_state(fsm, OTG_STATE_A_WAIT_BCON); 39262306a36Sopenharmony_ci else if (fsm->id || fsm->a_bus_drop || 39362306a36Sopenharmony_ci fsm->a_wait_vrise_tmout) 39462306a36Sopenharmony_ci otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL); 39562306a36Sopenharmony_ci break; 39662306a36Sopenharmony_ci case OTG_STATE_A_WAIT_BCON: 39762306a36Sopenharmony_ci if (!fsm->a_vbus_vld) 39862306a36Sopenharmony_ci otg_set_state(fsm, OTG_STATE_A_VBUS_ERR); 39962306a36Sopenharmony_ci else if (fsm->b_conn) 40062306a36Sopenharmony_ci otg_set_state(fsm, OTG_STATE_A_HOST); 40162306a36Sopenharmony_ci else if (fsm->id || fsm->a_bus_drop || fsm->a_wait_bcon_tmout) 40262306a36Sopenharmony_ci otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL); 40362306a36Sopenharmony_ci break; 40462306a36Sopenharmony_ci case OTG_STATE_A_HOST: 40562306a36Sopenharmony_ci if (fsm->id || fsm->a_bus_drop) 40662306a36Sopenharmony_ci otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL); 40762306a36Sopenharmony_ci else if ((!fsm->a_bus_req || fsm->a_suspend_req_inf) && 40862306a36Sopenharmony_ci fsm->otg->host->b_hnp_enable) 40962306a36Sopenharmony_ci otg_set_state(fsm, OTG_STATE_A_SUSPEND); 41062306a36Sopenharmony_ci else if (!fsm->b_conn) 41162306a36Sopenharmony_ci otg_set_state(fsm, OTG_STATE_A_WAIT_BCON); 41262306a36Sopenharmony_ci else if (!fsm->a_vbus_vld) 41362306a36Sopenharmony_ci otg_set_state(fsm, OTG_STATE_A_VBUS_ERR); 41462306a36Sopenharmony_ci break; 41562306a36Sopenharmony_ci case OTG_STATE_A_SUSPEND: 41662306a36Sopenharmony_ci if (!fsm->b_conn && fsm->otg->host->b_hnp_enable) 41762306a36Sopenharmony_ci otg_set_state(fsm, OTG_STATE_A_PERIPHERAL); 41862306a36Sopenharmony_ci else if (!fsm->b_conn && !fsm->otg->host->b_hnp_enable) 41962306a36Sopenharmony_ci otg_set_state(fsm, OTG_STATE_A_WAIT_BCON); 42062306a36Sopenharmony_ci else if (fsm->a_bus_req || fsm->b_bus_resume) 42162306a36Sopenharmony_ci otg_set_state(fsm, OTG_STATE_A_HOST); 42262306a36Sopenharmony_ci else if (fsm->id || fsm->a_bus_drop || fsm->a_aidl_bdis_tmout) 42362306a36Sopenharmony_ci otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL); 42462306a36Sopenharmony_ci else if (!fsm->a_vbus_vld) 42562306a36Sopenharmony_ci otg_set_state(fsm, OTG_STATE_A_VBUS_ERR); 42662306a36Sopenharmony_ci break; 42762306a36Sopenharmony_ci case OTG_STATE_A_PERIPHERAL: 42862306a36Sopenharmony_ci if (fsm->id || fsm->a_bus_drop) 42962306a36Sopenharmony_ci otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL); 43062306a36Sopenharmony_ci else if (fsm->a_bidl_adis_tmout || fsm->b_bus_suspend) 43162306a36Sopenharmony_ci otg_set_state(fsm, OTG_STATE_A_WAIT_BCON); 43262306a36Sopenharmony_ci else if (!fsm->a_vbus_vld) 43362306a36Sopenharmony_ci otg_set_state(fsm, OTG_STATE_A_VBUS_ERR); 43462306a36Sopenharmony_ci break; 43562306a36Sopenharmony_ci case OTG_STATE_A_WAIT_VFALL: 43662306a36Sopenharmony_ci if (fsm->a_wait_vfall_tmout) 43762306a36Sopenharmony_ci otg_set_state(fsm, OTG_STATE_A_IDLE); 43862306a36Sopenharmony_ci break; 43962306a36Sopenharmony_ci case OTG_STATE_A_VBUS_ERR: 44062306a36Sopenharmony_ci if (fsm->id || fsm->a_bus_drop || fsm->a_clr_err) 44162306a36Sopenharmony_ci otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL); 44262306a36Sopenharmony_ci break; 44362306a36Sopenharmony_ci default: 44462306a36Sopenharmony_ci break; 44562306a36Sopenharmony_ci } 44662306a36Sopenharmony_ci mutex_unlock(&fsm->lock); 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci VDBG("quit statemachine, changed = %d\n", fsm->state_changed); 44962306a36Sopenharmony_ci return fsm->state_changed; 45062306a36Sopenharmony_ci} 45162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(otg_statemachine); 45262306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 453