18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * OTG Finite State Machine from OTG spec
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2007,2008 Freescale Semiconductor, Inc.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Author:	Li Yang <LeoLi@freescale.com>
88c2ecf20Sopenharmony_ci *		Jerry Huang <Chang-Ming.Huang@freescale.com>
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/module.h>
128c2ecf20Sopenharmony_ci#include <linux/kernel.h>
138c2ecf20Sopenharmony_ci#include <linux/types.h>
148c2ecf20Sopenharmony_ci#include <linux/mutex.h>
158c2ecf20Sopenharmony_ci#include <linux/delay.h>
168c2ecf20Sopenharmony_ci#include <linux/usb.h>
178c2ecf20Sopenharmony_ci#include <linux/usb/gadget.h>
188c2ecf20Sopenharmony_ci#include <linux/usb/otg.h>
198c2ecf20Sopenharmony_ci#include <linux/usb/otg-fsm.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#ifdef VERBOSE
228c2ecf20Sopenharmony_ci#define VDBG(fmt, args...) pr_debug("[%s]  " fmt, \
238c2ecf20Sopenharmony_ci				 __func__, ## args)
248c2ecf20Sopenharmony_ci#else
258c2ecf20Sopenharmony_ci#define VDBG(stuff...)	do {} while (0)
268c2ecf20Sopenharmony_ci#endif
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci/* Change USB protocol when there is a protocol change */
298c2ecf20Sopenharmony_cistatic int otg_set_protocol(struct otg_fsm *fsm, int protocol)
308c2ecf20Sopenharmony_ci{
318c2ecf20Sopenharmony_ci	int ret = 0;
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	if (fsm->protocol != protocol) {
348c2ecf20Sopenharmony_ci		VDBG("Changing role fsm->protocol= %d; new protocol= %d\n",
358c2ecf20Sopenharmony_ci			fsm->protocol, protocol);
368c2ecf20Sopenharmony_ci		/* stop old protocol */
378c2ecf20Sopenharmony_ci		if (fsm->protocol == PROTO_HOST)
388c2ecf20Sopenharmony_ci			ret = otg_start_host(fsm, 0);
398c2ecf20Sopenharmony_ci		else if (fsm->protocol == PROTO_GADGET)
408c2ecf20Sopenharmony_ci			ret = otg_start_gadget(fsm, 0);
418c2ecf20Sopenharmony_ci		if (ret)
428c2ecf20Sopenharmony_ci			return ret;
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci		/* start new protocol */
458c2ecf20Sopenharmony_ci		if (protocol == PROTO_HOST)
468c2ecf20Sopenharmony_ci			ret = otg_start_host(fsm, 1);
478c2ecf20Sopenharmony_ci		else if (protocol == PROTO_GADGET)
488c2ecf20Sopenharmony_ci			ret = otg_start_gadget(fsm, 1);
498c2ecf20Sopenharmony_ci		if (ret)
508c2ecf20Sopenharmony_ci			return ret;
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci		fsm->protocol = protocol;
538c2ecf20Sopenharmony_ci		return 0;
548c2ecf20Sopenharmony_ci	}
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	return 0;
578c2ecf20Sopenharmony_ci}
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci/* Called when leaving a state.  Do state clean up jobs here */
608c2ecf20Sopenharmony_cistatic void otg_leave_state(struct otg_fsm *fsm, enum usb_otg_state old_state)
618c2ecf20Sopenharmony_ci{
628c2ecf20Sopenharmony_ci	switch (old_state) {
638c2ecf20Sopenharmony_ci	case OTG_STATE_B_IDLE:
648c2ecf20Sopenharmony_ci		otg_del_timer(fsm, B_SE0_SRP);
658c2ecf20Sopenharmony_ci		fsm->b_se0_srp = 0;
668c2ecf20Sopenharmony_ci		fsm->adp_sns = 0;
678c2ecf20Sopenharmony_ci		fsm->adp_prb = 0;
688c2ecf20Sopenharmony_ci		break;
698c2ecf20Sopenharmony_ci	case OTG_STATE_B_SRP_INIT:
708c2ecf20Sopenharmony_ci		fsm->data_pulse = 0;
718c2ecf20Sopenharmony_ci		fsm->b_srp_done = 0;
728c2ecf20Sopenharmony_ci		break;
738c2ecf20Sopenharmony_ci	case OTG_STATE_B_PERIPHERAL:
748c2ecf20Sopenharmony_ci		if (fsm->otg->gadget)
758c2ecf20Sopenharmony_ci			fsm->otg->gadget->host_request_flag = 0;
768c2ecf20Sopenharmony_ci		break;
778c2ecf20Sopenharmony_ci	case OTG_STATE_B_WAIT_ACON:
788c2ecf20Sopenharmony_ci		otg_del_timer(fsm, B_ASE0_BRST);
798c2ecf20Sopenharmony_ci		fsm->b_ase0_brst_tmout = 0;
808c2ecf20Sopenharmony_ci		break;
818c2ecf20Sopenharmony_ci	case OTG_STATE_B_HOST:
828c2ecf20Sopenharmony_ci		break;
838c2ecf20Sopenharmony_ci	case OTG_STATE_A_IDLE:
848c2ecf20Sopenharmony_ci		fsm->adp_prb = 0;
858c2ecf20Sopenharmony_ci		break;
868c2ecf20Sopenharmony_ci	case OTG_STATE_A_WAIT_VRISE:
878c2ecf20Sopenharmony_ci		otg_del_timer(fsm, A_WAIT_VRISE);
888c2ecf20Sopenharmony_ci		fsm->a_wait_vrise_tmout = 0;
898c2ecf20Sopenharmony_ci		break;
908c2ecf20Sopenharmony_ci	case OTG_STATE_A_WAIT_BCON:
918c2ecf20Sopenharmony_ci		otg_del_timer(fsm, A_WAIT_BCON);
928c2ecf20Sopenharmony_ci		fsm->a_wait_bcon_tmout = 0;
938c2ecf20Sopenharmony_ci		break;
948c2ecf20Sopenharmony_ci	case OTG_STATE_A_HOST:
958c2ecf20Sopenharmony_ci		otg_del_timer(fsm, A_WAIT_ENUM);
968c2ecf20Sopenharmony_ci		break;
978c2ecf20Sopenharmony_ci	case OTG_STATE_A_SUSPEND:
988c2ecf20Sopenharmony_ci		otg_del_timer(fsm, A_AIDL_BDIS);
998c2ecf20Sopenharmony_ci		fsm->a_aidl_bdis_tmout = 0;
1008c2ecf20Sopenharmony_ci		fsm->a_suspend_req_inf = 0;
1018c2ecf20Sopenharmony_ci		break;
1028c2ecf20Sopenharmony_ci	case OTG_STATE_A_PERIPHERAL:
1038c2ecf20Sopenharmony_ci		otg_del_timer(fsm, A_BIDL_ADIS);
1048c2ecf20Sopenharmony_ci		fsm->a_bidl_adis_tmout = 0;
1058c2ecf20Sopenharmony_ci		if (fsm->otg->gadget)
1068c2ecf20Sopenharmony_ci			fsm->otg->gadget->host_request_flag = 0;
1078c2ecf20Sopenharmony_ci		break;
1088c2ecf20Sopenharmony_ci	case OTG_STATE_A_WAIT_VFALL:
1098c2ecf20Sopenharmony_ci		otg_del_timer(fsm, A_WAIT_VFALL);
1108c2ecf20Sopenharmony_ci		fsm->a_wait_vfall_tmout = 0;
1118c2ecf20Sopenharmony_ci		otg_del_timer(fsm, A_WAIT_VRISE);
1128c2ecf20Sopenharmony_ci		break;
1138c2ecf20Sopenharmony_ci	case OTG_STATE_A_VBUS_ERR:
1148c2ecf20Sopenharmony_ci		break;
1158c2ecf20Sopenharmony_ci	default:
1168c2ecf20Sopenharmony_ci		break;
1178c2ecf20Sopenharmony_ci	}
1188c2ecf20Sopenharmony_ci}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_cistatic void otg_hnp_polling_work(struct work_struct *work)
1218c2ecf20Sopenharmony_ci{
1228c2ecf20Sopenharmony_ci	struct otg_fsm *fsm = container_of(to_delayed_work(work),
1238c2ecf20Sopenharmony_ci				struct otg_fsm, hnp_polling_work);
1248c2ecf20Sopenharmony_ci	struct usb_device *udev;
1258c2ecf20Sopenharmony_ci	enum usb_otg_state state = fsm->otg->state;
1268c2ecf20Sopenharmony_ci	u8 flag;
1278c2ecf20Sopenharmony_ci	int retval;
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	if (state != OTG_STATE_A_HOST && state != OTG_STATE_B_HOST)
1308c2ecf20Sopenharmony_ci		return;
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	udev = usb_hub_find_child(fsm->otg->host->root_hub, 1);
1338c2ecf20Sopenharmony_ci	if (!udev) {
1348c2ecf20Sopenharmony_ci		dev_err(fsm->otg->host->controller,
1358c2ecf20Sopenharmony_ci			"no usb dev connected, can't start HNP polling\n");
1368c2ecf20Sopenharmony_ci		return;
1378c2ecf20Sopenharmony_ci	}
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	*fsm->host_req_flag = 0;
1408c2ecf20Sopenharmony_ci	/* Get host request flag from connected USB device */
1418c2ecf20Sopenharmony_ci	retval = usb_control_msg(udev,
1428c2ecf20Sopenharmony_ci				usb_rcvctrlpipe(udev, 0),
1438c2ecf20Sopenharmony_ci				USB_REQ_GET_STATUS,
1448c2ecf20Sopenharmony_ci				USB_DIR_IN | USB_RECIP_DEVICE,
1458c2ecf20Sopenharmony_ci				0,
1468c2ecf20Sopenharmony_ci				OTG_STS_SELECTOR,
1478c2ecf20Sopenharmony_ci				fsm->host_req_flag,
1488c2ecf20Sopenharmony_ci				1,
1498c2ecf20Sopenharmony_ci				USB_CTRL_GET_TIMEOUT);
1508c2ecf20Sopenharmony_ci	if (retval != 1) {
1518c2ecf20Sopenharmony_ci		dev_err(&udev->dev, "Get one byte OTG status failed\n");
1528c2ecf20Sopenharmony_ci		return;
1538c2ecf20Sopenharmony_ci	}
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	flag = *fsm->host_req_flag;
1568c2ecf20Sopenharmony_ci	if (flag == 0) {
1578c2ecf20Sopenharmony_ci		/* Continue HNP polling */
1588c2ecf20Sopenharmony_ci		schedule_delayed_work(&fsm->hnp_polling_work,
1598c2ecf20Sopenharmony_ci					msecs_to_jiffies(T_HOST_REQ_POLL));
1608c2ecf20Sopenharmony_ci		return;
1618c2ecf20Sopenharmony_ci	} else if (flag != HOST_REQUEST_FLAG) {
1628c2ecf20Sopenharmony_ci		dev_err(&udev->dev, "host request flag %d is invalid\n", flag);
1638c2ecf20Sopenharmony_ci		return;
1648c2ecf20Sopenharmony_ci	}
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	/* Host request flag is set */
1678c2ecf20Sopenharmony_ci	if (state == OTG_STATE_A_HOST) {
1688c2ecf20Sopenharmony_ci		/* Set b_hnp_enable */
1698c2ecf20Sopenharmony_ci		if (!fsm->otg->host->b_hnp_enable) {
1708c2ecf20Sopenharmony_ci			retval = usb_control_msg(udev,
1718c2ecf20Sopenharmony_ci					usb_sndctrlpipe(udev, 0),
1728c2ecf20Sopenharmony_ci					USB_REQ_SET_FEATURE, 0,
1738c2ecf20Sopenharmony_ci					USB_DEVICE_B_HNP_ENABLE,
1748c2ecf20Sopenharmony_ci					0, NULL, 0,
1758c2ecf20Sopenharmony_ci					USB_CTRL_SET_TIMEOUT);
1768c2ecf20Sopenharmony_ci			if (retval >= 0)
1778c2ecf20Sopenharmony_ci				fsm->otg->host->b_hnp_enable = 1;
1788c2ecf20Sopenharmony_ci		}
1798c2ecf20Sopenharmony_ci		fsm->a_bus_req = 0;
1808c2ecf20Sopenharmony_ci	} else if (state == OTG_STATE_B_HOST) {
1818c2ecf20Sopenharmony_ci		fsm->b_bus_req = 0;
1828c2ecf20Sopenharmony_ci	}
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	otg_statemachine(fsm);
1858c2ecf20Sopenharmony_ci}
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_cistatic void otg_start_hnp_polling(struct otg_fsm *fsm)
1888c2ecf20Sopenharmony_ci{
1898c2ecf20Sopenharmony_ci	/*
1908c2ecf20Sopenharmony_ci	 * The memory of host_req_flag should be allocated by
1918c2ecf20Sopenharmony_ci	 * controller driver, otherwise, hnp polling is not started.
1928c2ecf20Sopenharmony_ci	 */
1938c2ecf20Sopenharmony_ci	if (!fsm->host_req_flag)
1948c2ecf20Sopenharmony_ci		return;
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	if (!fsm->hnp_work_inited) {
1978c2ecf20Sopenharmony_ci		INIT_DELAYED_WORK(&fsm->hnp_polling_work, otg_hnp_polling_work);
1988c2ecf20Sopenharmony_ci		fsm->hnp_work_inited = true;
1998c2ecf20Sopenharmony_ci	}
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	schedule_delayed_work(&fsm->hnp_polling_work,
2028c2ecf20Sopenharmony_ci					msecs_to_jiffies(T_HOST_REQ_POLL));
2038c2ecf20Sopenharmony_ci}
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci/* Called when entering a state */
2068c2ecf20Sopenharmony_cistatic int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
2078c2ecf20Sopenharmony_ci{
2088c2ecf20Sopenharmony_ci	if (fsm->otg->state == new_state)
2098c2ecf20Sopenharmony_ci		return 0;
2108c2ecf20Sopenharmony_ci	VDBG("Set state: %s\n", usb_otg_state_string(new_state));
2118c2ecf20Sopenharmony_ci	otg_leave_state(fsm, fsm->otg->state);
2128c2ecf20Sopenharmony_ci	switch (new_state) {
2138c2ecf20Sopenharmony_ci	case OTG_STATE_B_IDLE:
2148c2ecf20Sopenharmony_ci		otg_drv_vbus(fsm, 0);
2158c2ecf20Sopenharmony_ci		otg_chrg_vbus(fsm, 0);
2168c2ecf20Sopenharmony_ci		otg_loc_conn(fsm, 0);
2178c2ecf20Sopenharmony_ci		otg_loc_sof(fsm, 0);
2188c2ecf20Sopenharmony_ci		/*
2198c2ecf20Sopenharmony_ci		 * Driver is responsible for starting ADP probing
2208c2ecf20Sopenharmony_ci		 * if ADP sensing times out.
2218c2ecf20Sopenharmony_ci		 */
2228c2ecf20Sopenharmony_ci		otg_start_adp_sns(fsm);
2238c2ecf20Sopenharmony_ci		otg_set_protocol(fsm, PROTO_UNDEF);
2248c2ecf20Sopenharmony_ci		otg_add_timer(fsm, B_SE0_SRP);
2258c2ecf20Sopenharmony_ci		break;
2268c2ecf20Sopenharmony_ci	case OTG_STATE_B_SRP_INIT:
2278c2ecf20Sopenharmony_ci		otg_start_pulse(fsm);
2288c2ecf20Sopenharmony_ci		otg_loc_sof(fsm, 0);
2298c2ecf20Sopenharmony_ci		otg_set_protocol(fsm, PROTO_UNDEF);
2308c2ecf20Sopenharmony_ci		otg_add_timer(fsm, B_SRP_FAIL);
2318c2ecf20Sopenharmony_ci		break;
2328c2ecf20Sopenharmony_ci	case OTG_STATE_B_PERIPHERAL:
2338c2ecf20Sopenharmony_ci		otg_chrg_vbus(fsm, 0);
2348c2ecf20Sopenharmony_ci		otg_loc_sof(fsm, 0);
2358c2ecf20Sopenharmony_ci		otg_set_protocol(fsm, PROTO_GADGET);
2368c2ecf20Sopenharmony_ci		otg_loc_conn(fsm, 1);
2378c2ecf20Sopenharmony_ci		break;
2388c2ecf20Sopenharmony_ci	case OTG_STATE_B_WAIT_ACON:
2398c2ecf20Sopenharmony_ci		otg_chrg_vbus(fsm, 0);
2408c2ecf20Sopenharmony_ci		otg_loc_conn(fsm, 0);
2418c2ecf20Sopenharmony_ci		otg_loc_sof(fsm, 0);
2428c2ecf20Sopenharmony_ci		otg_set_protocol(fsm, PROTO_HOST);
2438c2ecf20Sopenharmony_ci		otg_add_timer(fsm, B_ASE0_BRST);
2448c2ecf20Sopenharmony_ci		fsm->a_bus_suspend = 0;
2458c2ecf20Sopenharmony_ci		break;
2468c2ecf20Sopenharmony_ci	case OTG_STATE_B_HOST:
2478c2ecf20Sopenharmony_ci		otg_chrg_vbus(fsm, 0);
2488c2ecf20Sopenharmony_ci		otg_loc_conn(fsm, 0);
2498c2ecf20Sopenharmony_ci		otg_loc_sof(fsm, 1);
2508c2ecf20Sopenharmony_ci		otg_set_protocol(fsm, PROTO_HOST);
2518c2ecf20Sopenharmony_ci		usb_bus_start_enum(fsm->otg->host,
2528c2ecf20Sopenharmony_ci				fsm->otg->host->otg_port);
2538c2ecf20Sopenharmony_ci		otg_start_hnp_polling(fsm);
2548c2ecf20Sopenharmony_ci		break;
2558c2ecf20Sopenharmony_ci	case OTG_STATE_A_IDLE:
2568c2ecf20Sopenharmony_ci		otg_drv_vbus(fsm, 0);
2578c2ecf20Sopenharmony_ci		otg_chrg_vbus(fsm, 0);
2588c2ecf20Sopenharmony_ci		otg_loc_conn(fsm, 0);
2598c2ecf20Sopenharmony_ci		otg_loc_sof(fsm, 0);
2608c2ecf20Sopenharmony_ci		otg_start_adp_prb(fsm);
2618c2ecf20Sopenharmony_ci		otg_set_protocol(fsm, PROTO_HOST);
2628c2ecf20Sopenharmony_ci		break;
2638c2ecf20Sopenharmony_ci	case OTG_STATE_A_WAIT_VRISE:
2648c2ecf20Sopenharmony_ci		otg_drv_vbus(fsm, 1);
2658c2ecf20Sopenharmony_ci		otg_loc_conn(fsm, 0);
2668c2ecf20Sopenharmony_ci		otg_loc_sof(fsm, 0);
2678c2ecf20Sopenharmony_ci		otg_set_protocol(fsm, PROTO_HOST);
2688c2ecf20Sopenharmony_ci		otg_add_timer(fsm, A_WAIT_VRISE);
2698c2ecf20Sopenharmony_ci		break;
2708c2ecf20Sopenharmony_ci	case OTG_STATE_A_WAIT_BCON:
2718c2ecf20Sopenharmony_ci		otg_drv_vbus(fsm, 1);
2728c2ecf20Sopenharmony_ci		otg_loc_conn(fsm, 0);
2738c2ecf20Sopenharmony_ci		otg_loc_sof(fsm, 0);
2748c2ecf20Sopenharmony_ci		otg_set_protocol(fsm, PROTO_HOST);
2758c2ecf20Sopenharmony_ci		otg_add_timer(fsm, A_WAIT_BCON);
2768c2ecf20Sopenharmony_ci		break;
2778c2ecf20Sopenharmony_ci	case OTG_STATE_A_HOST:
2788c2ecf20Sopenharmony_ci		otg_drv_vbus(fsm, 1);
2798c2ecf20Sopenharmony_ci		otg_loc_conn(fsm, 0);
2808c2ecf20Sopenharmony_ci		otg_loc_sof(fsm, 1);
2818c2ecf20Sopenharmony_ci		otg_set_protocol(fsm, PROTO_HOST);
2828c2ecf20Sopenharmony_ci		/*
2838c2ecf20Sopenharmony_ci		 * When HNP is triggered while a_bus_req = 0, a_host will
2848c2ecf20Sopenharmony_ci		 * suspend too fast to complete a_set_b_hnp_en
2858c2ecf20Sopenharmony_ci		 */
2868c2ecf20Sopenharmony_ci		if (!fsm->a_bus_req || fsm->a_suspend_req_inf)
2878c2ecf20Sopenharmony_ci			otg_add_timer(fsm, A_WAIT_ENUM);
2888c2ecf20Sopenharmony_ci		otg_start_hnp_polling(fsm);
2898c2ecf20Sopenharmony_ci		break;
2908c2ecf20Sopenharmony_ci	case OTG_STATE_A_SUSPEND:
2918c2ecf20Sopenharmony_ci		otg_drv_vbus(fsm, 1);
2928c2ecf20Sopenharmony_ci		otg_loc_conn(fsm, 0);
2938c2ecf20Sopenharmony_ci		otg_loc_sof(fsm, 0);
2948c2ecf20Sopenharmony_ci		otg_set_protocol(fsm, PROTO_HOST);
2958c2ecf20Sopenharmony_ci		otg_add_timer(fsm, A_AIDL_BDIS);
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci		break;
2988c2ecf20Sopenharmony_ci	case OTG_STATE_A_PERIPHERAL:
2998c2ecf20Sopenharmony_ci		otg_loc_sof(fsm, 0);
3008c2ecf20Sopenharmony_ci		otg_set_protocol(fsm, PROTO_GADGET);
3018c2ecf20Sopenharmony_ci		otg_drv_vbus(fsm, 1);
3028c2ecf20Sopenharmony_ci		otg_loc_conn(fsm, 1);
3038c2ecf20Sopenharmony_ci		otg_add_timer(fsm, A_BIDL_ADIS);
3048c2ecf20Sopenharmony_ci		break;
3058c2ecf20Sopenharmony_ci	case OTG_STATE_A_WAIT_VFALL:
3068c2ecf20Sopenharmony_ci		otg_drv_vbus(fsm, 0);
3078c2ecf20Sopenharmony_ci		otg_loc_conn(fsm, 0);
3088c2ecf20Sopenharmony_ci		otg_loc_sof(fsm, 0);
3098c2ecf20Sopenharmony_ci		otg_set_protocol(fsm, PROTO_HOST);
3108c2ecf20Sopenharmony_ci		otg_add_timer(fsm, A_WAIT_VFALL);
3118c2ecf20Sopenharmony_ci		break;
3128c2ecf20Sopenharmony_ci	case OTG_STATE_A_VBUS_ERR:
3138c2ecf20Sopenharmony_ci		otg_drv_vbus(fsm, 0);
3148c2ecf20Sopenharmony_ci		otg_loc_conn(fsm, 0);
3158c2ecf20Sopenharmony_ci		otg_loc_sof(fsm, 0);
3168c2ecf20Sopenharmony_ci		otg_set_protocol(fsm, PROTO_UNDEF);
3178c2ecf20Sopenharmony_ci		break;
3188c2ecf20Sopenharmony_ci	default:
3198c2ecf20Sopenharmony_ci		break;
3208c2ecf20Sopenharmony_ci	}
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	fsm->otg->state = new_state;
3238c2ecf20Sopenharmony_ci	fsm->state_changed = 1;
3248c2ecf20Sopenharmony_ci	return 0;
3258c2ecf20Sopenharmony_ci}
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci/* State change judgement */
3288c2ecf20Sopenharmony_ciint otg_statemachine(struct otg_fsm *fsm)
3298c2ecf20Sopenharmony_ci{
3308c2ecf20Sopenharmony_ci	enum usb_otg_state state;
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	mutex_lock(&fsm->lock);
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	state = fsm->otg->state;
3358c2ecf20Sopenharmony_ci	fsm->state_changed = 0;
3368c2ecf20Sopenharmony_ci	/* State machine state change judgement */
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	switch (state) {
3398c2ecf20Sopenharmony_ci	case OTG_STATE_UNDEFINED:
3408c2ecf20Sopenharmony_ci		VDBG("fsm->id = %d\n", fsm->id);
3418c2ecf20Sopenharmony_ci		if (fsm->id)
3428c2ecf20Sopenharmony_ci			otg_set_state(fsm, OTG_STATE_B_IDLE);
3438c2ecf20Sopenharmony_ci		else
3448c2ecf20Sopenharmony_ci			otg_set_state(fsm, OTG_STATE_A_IDLE);
3458c2ecf20Sopenharmony_ci		break;
3468c2ecf20Sopenharmony_ci	case OTG_STATE_B_IDLE:
3478c2ecf20Sopenharmony_ci		if (!fsm->id)
3488c2ecf20Sopenharmony_ci			otg_set_state(fsm, OTG_STATE_A_IDLE);
3498c2ecf20Sopenharmony_ci		else if (fsm->b_sess_vld && fsm->otg->gadget)
3508c2ecf20Sopenharmony_ci			otg_set_state(fsm, OTG_STATE_B_PERIPHERAL);
3518c2ecf20Sopenharmony_ci		else if ((fsm->b_bus_req || fsm->adp_change || fsm->power_up) &&
3528c2ecf20Sopenharmony_ci				fsm->b_ssend_srp && fsm->b_se0_srp)
3538c2ecf20Sopenharmony_ci			otg_set_state(fsm, OTG_STATE_B_SRP_INIT);
3548c2ecf20Sopenharmony_ci		break;
3558c2ecf20Sopenharmony_ci	case OTG_STATE_B_SRP_INIT:
3568c2ecf20Sopenharmony_ci		if (!fsm->id || fsm->b_srp_done)
3578c2ecf20Sopenharmony_ci			otg_set_state(fsm, OTG_STATE_B_IDLE);
3588c2ecf20Sopenharmony_ci		break;
3598c2ecf20Sopenharmony_ci	case OTG_STATE_B_PERIPHERAL:
3608c2ecf20Sopenharmony_ci		if (!fsm->id || !fsm->b_sess_vld)
3618c2ecf20Sopenharmony_ci			otg_set_state(fsm, OTG_STATE_B_IDLE);
3628c2ecf20Sopenharmony_ci		else if (fsm->b_bus_req && fsm->otg->
3638c2ecf20Sopenharmony_ci				gadget->b_hnp_enable && fsm->a_bus_suspend)
3648c2ecf20Sopenharmony_ci			otg_set_state(fsm, OTG_STATE_B_WAIT_ACON);
3658c2ecf20Sopenharmony_ci		break;
3668c2ecf20Sopenharmony_ci	case OTG_STATE_B_WAIT_ACON:
3678c2ecf20Sopenharmony_ci		if (fsm->a_conn)
3688c2ecf20Sopenharmony_ci			otg_set_state(fsm, OTG_STATE_B_HOST);
3698c2ecf20Sopenharmony_ci		else if (!fsm->id || !fsm->b_sess_vld)
3708c2ecf20Sopenharmony_ci			otg_set_state(fsm, OTG_STATE_B_IDLE);
3718c2ecf20Sopenharmony_ci		else if (fsm->a_bus_resume || fsm->b_ase0_brst_tmout) {
3728c2ecf20Sopenharmony_ci			fsm->b_ase0_brst_tmout = 0;
3738c2ecf20Sopenharmony_ci			otg_set_state(fsm, OTG_STATE_B_PERIPHERAL);
3748c2ecf20Sopenharmony_ci		}
3758c2ecf20Sopenharmony_ci		break;
3768c2ecf20Sopenharmony_ci	case OTG_STATE_B_HOST:
3778c2ecf20Sopenharmony_ci		if (!fsm->id || !fsm->b_sess_vld)
3788c2ecf20Sopenharmony_ci			otg_set_state(fsm, OTG_STATE_B_IDLE);
3798c2ecf20Sopenharmony_ci		else if (!fsm->b_bus_req || !fsm->a_conn || fsm->test_device)
3808c2ecf20Sopenharmony_ci			otg_set_state(fsm, OTG_STATE_B_PERIPHERAL);
3818c2ecf20Sopenharmony_ci		break;
3828c2ecf20Sopenharmony_ci	case OTG_STATE_A_IDLE:
3838c2ecf20Sopenharmony_ci		if (fsm->id)
3848c2ecf20Sopenharmony_ci			otg_set_state(fsm, OTG_STATE_B_IDLE);
3858c2ecf20Sopenharmony_ci		else if (!fsm->a_bus_drop && (fsm->a_bus_req ||
3868c2ecf20Sopenharmony_ci			  fsm->a_srp_det || fsm->adp_change || fsm->power_up))
3878c2ecf20Sopenharmony_ci			otg_set_state(fsm, OTG_STATE_A_WAIT_VRISE);
3888c2ecf20Sopenharmony_ci		break;
3898c2ecf20Sopenharmony_ci	case OTG_STATE_A_WAIT_VRISE:
3908c2ecf20Sopenharmony_ci		if (fsm->a_vbus_vld)
3918c2ecf20Sopenharmony_ci			otg_set_state(fsm, OTG_STATE_A_WAIT_BCON);
3928c2ecf20Sopenharmony_ci		else if (fsm->id || fsm->a_bus_drop ||
3938c2ecf20Sopenharmony_ci				fsm->a_wait_vrise_tmout)
3948c2ecf20Sopenharmony_ci			otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL);
3958c2ecf20Sopenharmony_ci		break;
3968c2ecf20Sopenharmony_ci	case OTG_STATE_A_WAIT_BCON:
3978c2ecf20Sopenharmony_ci		if (!fsm->a_vbus_vld)
3988c2ecf20Sopenharmony_ci			otg_set_state(fsm, OTG_STATE_A_VBUS_ERR);
3998c2ecf20Sopenharmony_ci		else if (fsm->b_conn)
4008c2ecf20Sopenharmony_ci			otg_set_state(fsm, OTG_STATE_A_HOST);
4018c2ecf20Sopenharmony_ci		else if (fsm->id || fsm->a_bus_drop || fsm->a_wait_bcon_tmout)
4028c2ecf20Sopenharmony_ci			otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL);
4038c2ecf20Sopenharmony_ci		break;
4048c2ecf20Sopenharmony_ci	case OTG_STATE_A_HOST:
4058c2ecf20Sopenharmony_ci		if (fsm->id || fsm->a_bus_drop)
4068c2ecf20Sopenharmony_ci			otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL);
4078c2ecf20Sopenharmony_ci		else if ((!fsm->a_bus_req || fsm->a_suspend_req_inf) &&
4088c2ecf20Sopenharmony_ci				fsm->otg->host->b_hnp_enable)
4098c2ecf20Sopenharmony_ci			otg_set_state(fsm, OTG_STATE_A_SUSPEND);
4108c2ecf20Sopenharmony_ci		else if (!fsm->b_conn)
4118c2ecf20Sopenharmony_ci			otg_set_state(fsm, OTG_STATE_A_WAIT_BCON);
4128c2ecf20Sopenharmony_ci		else if (!fsm->a_vbus_vld)
4138c2ecf20Sopenharmony_ci			otg_set_state(fsm, OTG_STATE_A_VBUS_ERR);
4148c2ecf20Sopenharmony_ci		break;
4158c2ecf20Sopenharmony_ci	case OTG_STATE_A_SUSPEND:
4168c2ecf20Sopenharmony_ci		if (!fsm->b_conn && fsm->otg->host->b_hnp_enable)
4178c2ecf20Sopenharmony_ci			otg_set_state(fsm, OTG_STATE_A_PERIPHERAL);
4188c2ecf20Sopenharmony_ci		else if (!fsm->b_conn && !fsm->otg->host->b_hnp_enable)
4198c2ecf20Sopenharmony_ci			otg_set_state(fsm, OTG_STATE_A_WAIT_BCON);
4208c2ecf20Sopenharmony_ci		else if (fsm->a_bus_req || fsm->b_bus_resume)
4218c2ecf20Sopenharmony_ci			otg_set_state(fsm, OTG_STATE_A_HOST);
4228c2ecf20Sopenharmony_ci		else if (fsm->id || fsm->a_bus_drop || fsm->a_aidl_bdis_tmout)
4238c2ecf20Sopenharmony_ci			otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL);
4248c2ecf20Sopenharmony_ci		else if (!fsm->a_vbus_vld)
4258c2ecf20Sopenharmony_ci			otg_set_state(fsm, OTG_STATE_A_VBUS_ERR);
4268c2ecf20Sopenharmony_ci		break;
4278c2ecf20Sopenharmony_ci	case OTG_STATE_A_PERIPHERAL:
4288c2ecf20Sopenharmony_ci		if (fsm->id || fsm->a_bus_drop)
4298c2ecf20Sopenharmony_ci			otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL);
4308c2ecf20Sopenharmony_ci		else if (fsm->a_bidl_adis_tmout || fsm->b_bus_suspend)
4318c2ecf20Sopenharmony_ci			otg_set_state(fsm, OTG_STATE_A_WAIT_BCON);
4328c2ecf20Sopenharmony_ci		else if (!fsm->a_vbus_vld)
4338c2ecf20Sopenharmony_ci			otg_set_state(fsm, OTG_STATE_A_VBUS_ERR);
4348c2ecf20Sopenharmony_ci		break;
4358c2ecf20Sopenharmony_ci	case OTG_STATE_A_WAIT_VFALL:
4368c2ecf20Sopenharmony_ci		if (fsm->a_wait_vfall_tmout)
4378c2ecf20Sopenharmony_ci			otg_set_state(fsm, OTG_STATE_A_IDLE);
4388c2ecf20Sopenharmony_ci		break;
4398c2ecf20Sopenharmony_ci	case OTG_STATE_A_VBUS_ERR:
4408c2ecf20Sopenharmony_ci		if (fsm->id || fsm->a_bus_drop || fsm->a_clr_err)
4418c2ecf20Sopenharmony_ci			otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL);
4428c2ecf20Sopenharmony_ci		break;
4438c2ecf20Sopenharmony_ci	default:
4448c2ecf20Sopenharmony_ci		break;
4458c2ecf20Sopenharmony_ci	}
4468c2ecf20Sopenharmony_ci	mutex_unlock(&fsm->lock);
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	VDBG("quit statemachine, changed = %d\n", fsm->state_changed);
4498c2ecf20Sopenharmony_ci	return fsm->state_changed;
4508c2ecf20Sopenharmony_ci}
4518c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(otg_statemachine);
4528c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
453