18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * otg_fsm.c - ChipIdea USB IP core OTG FSM driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2014 Freescale Semiconductor, Inc. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author: Jun Li 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci/* 118c2ecf20Sopenharmony_ci * This file mainly handles OTG fsm, it includes OTG fsm operations 128c2ecf20Sopenharmony_ci * for HNP and SRP. 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * TODO List 158c2ecf20Sopenharmony_ci * - ADP 168c2ecf20Sopenharmony_ci * - OTG test device 178c2ecf20Sopenharmony_ci */ 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include <linux/usb/otg.h> 208c2ecf20Sopenharmony_ci#include <linux/usb/gadget.h> 218c2ecf20Sopenharmony_ci#include <linux/usb/hcd.h> 228c2ecf20Sopenharmony_ci#include <linux/usb/chipidea.h> 238c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include "ci.h" 268c2ecf20Sopenharmony_ci#include "bits.h" 278c2ecf20Sopenharmony_ci#include "otg.h" 288c2ecf20Sopenharmony_ci#include "otg_fsm.h" 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci/* Add for otg: interact with user space app */ 318c2ecf20Sopenharmony_cistatic ssize_t 328c2ecf20Sopenharmony_cia_bus_req_show(struct device *dev, struct device_attribute *attr, char *buf) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci char *next; 358c2ecf20Sopenharmony_ci unsigned size, t; 368c2ecf20Sopenharmony_ci struct ci_hdrc *ci = dev_get_drvdata(dev); 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci next = buf; 398c2ecf20Sopenharmony_ci size = PAGE_SIZE; 408c2ecf20Sopenharmony_ci t = scnprintf(next, size, "%d\n", ci->fsm.a_bus_req); 418c2ecf20Sopenharmony_ci size -= t; 428c2ecf20Sopenharmony_ci next += t; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci return PAGE_SIZE - size; 458c2ecf20Sopenharmony_ci} 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistatic ssize_t 488c2ecf20Sopenharmony_cia_bus_req_store(struct device *dev, struct device_attribute *attr, 498c2ecf20Sopenharmony_ci const char *buf, size_t count) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci struct ci_hdrc *ci = dev_get_drvdata(dev); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci if (count > 2) 548c2ecf20Sopenharmony_ci return -1; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci mutex_lock(&ci->fsm.lock); 578c2ecf20Sopenharmony_ci if (buf[0] == '0') { 588c2ecf20Sopenharmony_ci ci->fsm.a_bus_req = 0; 598c2ecf20Sopenharmony_ci } else if (buf[0] == '1') { 608c2ecf20Sopenharmony_ci /* If a_bus_drop is TRUE, a_bus_req can't be set */ 618c2ecf20Sopenharmony_ci if (ci->fsm.a_bus_drop) { 628c2ecf20Sopenharmony_ci mutex_unlock(&ci->fsm.lock); 638c2ecf20Sopenharmony_ci return count; 648c2ecf20Sopenharmony_ci } 658c2ecf20Sopenharmony_ci ci->fsm.a_bus_req = 1; 668c2ecf20Sopenharmony_ci if (ci->fsm.otg->state == OTG_STATE_A_PERIPHERAL) { 678c2ecf20Sopenharmony_ci ci->gadget.host_request_flag = 1; 688c2ecf20Sopenharmony_ci mutex_unlock(&ci->fsm.lock); 698c2ecf20Sopenharmony_ci return count; 708c2ecf20Sopenharmony_ci } 718c2ecf20Sopenharmony_ci } 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci ci_otg_queue_work(ci); 748c2ecf20Sopenharmony_ci mutex_unlock(&ci->fsm.lock); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci return count; 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(a_bus_req); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistatic ssize_t 818c2ecf20Sopenharmony_cia_bus_drop_show(struct device *dev, struct device_attribute *attr, char *buf) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci char *next; 848c2ecf20Sopenharmony_ci unsigned size, t; 858c2ecf20Sopenharmony_ci struct ci_hdrc *ci = dev_get_drvdata(dev); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci next = buf; 888c2ecf20Sopenharmony_ci size = PAGE_SIZE; 898c2ecf20Sopenharmony_ci t = scnprintf(next, size, "%d\n", ci->fsm.a_bus_drop); 908c2ecf20Sopenharmony_ci size -= t; 918c2ecf20Sopenharmony_ci next += t; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci return PAGE_SIZE - size; 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistatic ssize_t 978c2ecf20Sopenharmony_cia_bus_drop_store(struct device *dev, struct device_attribute *attr, 988c2ecf20Sopenharmony_ci const char *buf, size_t count) 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci struct ci_hdrc *ci = dev_get_drvdata(dev); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci if (count > 2) 1038c2ecf20Sopenharmony_ci return -1; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci mutex_lock(&ci->fsm.lock); 1068c2ecf20Sopenharmony_ci if (buf[0] == '0') { 1078c2ecf20Sopenharmony_ci ci->fsm.a_bus_drop = 0; 1088c2ecf20Sopenharmony_ci } else if (buf[0] == '1') { 1098c2ecf20Sopenharmony_ci ci->fsm.a_bus_drop = 1; 1108c2ecf20Sopenharmony_ci ci->fsm.a_bus_req = 0; 1118c2ecf20Sopenharmony_ci } 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci ci_otg_queue_work(ci); 1148c2ecf20Sopenharmony_ci mutex_unlock(&ci->fsm.lock); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci return count; 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(a_bus_drop); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic ssize_t 1218c2ecf20Sopenharmony_cib_bus_req_show(struct device *dev, struct device_attribute *attr, char *buf) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci char *next; 1248c2ecf20Sopenharmony_ci unsigned size, t; 1258c2ecf20Sopenharmony_ci struct ci_hdrc *ci = dev_get_drvdata(dev); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci next = buf; 1288c2ecf20Sopenharmony_ci size = PAGE_SIZE; 1298c2ecf20Sopenharmony_ci t = scnprintf(next, size, "%d\n", ci->fsm.b_bus_req); 1308c2ecf20Sopenharmony_ci size -= t; 1318c2ecf20Sopenharmony_ci next += t; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci return PAGE_SIZE - size; 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cistatic ssize_t 1378c2ecf20Sopenharmony_cib_bus_req_store(struct device *dev, struct device_attribute *attr, 1388c2ecf20Sopenharmony_ci const char *buf, size_t count) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci struct ci_hdrc *ci = dev_get_drvdata(dev); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci if (count > 2) 1438c2ecf20Sopenharmony_ci return -1; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci mutex_lock(&ci->fsm.lock); 1468c2ecf20Sopenharmony_ci if (buf[0] == '0') 1478c2ecf20Sopenharmony_ci ci->fsm.b_bus_req = 0; 1488c2ecf20Sopenharmony_ci else if (buf[0] == '1') { 1498c2ecf20Sopenharmony_ci ci->fsm.b_bus_req = 1; 1508c2ecf20Sopenharmony_ci if (ci->fsm.otg->state == OTG_STATE_B_PERIPHERAL) { 1518c2ecf20Sopenharmony_ci ci->gadget.host_request_flag = 1; 1528c2ecf20Sopenharmony_ci mutex_unlock(&ci->fsm.lock); 1538c2ecf20Sopenharmony_ci return count; 1548c2ecf20Sopenharmony_ci } 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci ci_otg_queue_work(ci); 1588c2ecf20Sopenharmony_ci mutex_unlock(&ci->fsm.lock); 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci return count; 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(b_bus_req); 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic ssize_t 1658c2ecf20Sopenharmony_cia_clr_err_store(struct device *dev, struct device_attribute *attr, 1668c2ecf20Sopenharmony_ci const char *buf, size_t count) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci struct ci_hdrc *ci = dev_get_drvdata(dev); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci if (count > 2) 1718c2ecf20Sopenharmony_ci return -1; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci mutex_lock(&ci->fsm.lock); 1748c2ecf20Sopenharmony_ci if (buf[0] == '1') 1758c2ecf20Sopenharmony_ci ci->fsm.a_clr_err = 1; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci ci_otg_queue_work(ci); 1788c2ecf20Sopenharmony_ci mutex_unlock(&ci->fsm.lock); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci return count; 1818c2ecf20Sopenharmony_ci} 1828c2ecf20Sopenharmony_cistatic DEVICE_ATTR_WO(a_clr_err); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cistatic struct attribute *inputs_attrs[] = { 1858c2ecf20Sopenharmony_ci &dev_attr_a_bus_req.attr, 1868c2ecf20Sopenharmony_ci &dev_attr_a_bus_drop.attr, 1878c2ecf20Sopenharmony_ci &dev_attr_b_bus_req.attr, 1888c2ecf20Sopenharmony_ci &dev_attr_a_clr_err.attr, 1898c2ecf20Sopenharmony_ci NULL, 1908c2ecf20Sopenharmony_ci}; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_cistatic const struct attribute_group inputs_attr_group = { 1938c2ecf20Sopenharmony_ci .name = "inputs", 1948c2ecf20Sopenharmony_ci .attrs = inputs_attrs, 1958c2ecf20Sopenharmony_ci}; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci/* 1988c2ecf20Sopenharmony_ci * Keep this list in the same order as timers indexed 1998c2ecf20Sopenharmony_ci * by enum otg_fsm_timer in include/linux/usb/otg-fsm.h 2008c2ecf20Sopenharmony_ci */ 2018c2ecf20Sopenharmony_cistatic unsigned otg_timer_ms[] = { 2028c2ecf20Sopenharmony_ci TA_WAIT_VRISE, 2038c2ecf20Sopenharmony_ci TA_WAIT_VFALL, 2048c2ecf20Sopenharmony_ci TA_WAIT_BCON, 2058c2ecf20Sopenharmony_ci TA_AIDL_BDIS, 2068c2ecf20Sopenharmony_ci TB_ASE0_BRST, 2078c2ecf20Sopenharmony_ci TA_BIDL_ADIS, 2088c2ecf20Sopenharmony_ci TB_AIDL_BDIS, 2098c2ecf20Sopenharmony_ci TB_SE0_SRP, 2108c2ecf20Sopenharmony_ci TB_SRP_FAIL, 2118c2ecf20Sopenharmony_ci 0, 2128c2ecf20Sopenharmony_ci TB_DATA_PLS, 2138c2ecf20Sopenharmony_ci TB_SSEND_SRP, 2148c2ecf20Sopenharmony_ci}; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci/* 2178c2ecf20Sopenharmony_ci * Add timer to active timer list 2188c2ecf20Sopenharmony_ci */ 2198c2ecf20Sopenharmony_cistatic void ci_otg_add_timer(struct ci_hdrc *ci, enum otg_fsm_timer t) 2208c2ecf20Sopenharmony_ci{ 2218c2ecf20Sopenharmony_ci unsigned long flags, timer_sec, timer_nsec; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci if (t >= NUM_OTG_FSM_TIMERS) 2248c2ecf20Sopenharmony_ci return; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci spin_lock_irqsave(&ci->lock, flags); 2278c2ecf20Sopenharmony_ci timer_sec = otg_timer_ms[t] / MSEC_PER_SEC; 2288c2ecf20Sopenharmony_ci timer_nsec = (otg_timer_ms[t] % MSEC_PER_SEC) * NSEC_PER_MSEC; 2298c2ecf20Sopenharmony_ci ci->hr_timeouts[t] = ktime_add(ktime_get(), 2308c2ecf20Sopenharmony_ci ktime_set(timer_sec, timer_nsec)); 2318c2ecf20Sopenharmony_ci ci->enabled_otg_timer_bits |= (1 << t); 2328c2ecf20Sopenharmony_ci if ((ci->next_otg_timer == NUM_OTG_FSM_TIMERS) || 2338c2ecf20Sopenharmony_ci ktime_after(ci->hr_timeouts[ci->next_otg_timer], 2348c2ecf20Sopenharmony_ci ci->hr_timeouts[t])) { 2358c2ecf20Sopenharmony_ci ci->next_otg_timer = t; 2368c2ecf20Sopenharmony_ci hrtimer_start_range_ns(&ci->otg_fsm_hrtimer, 2378c2ecf20Sopenharmony_ci ci->hr_timeouts[t], NSEC_PER_MSEC, 2388c2ecf20Sopenharmony_ci HRTIMER_MODE_ABS); 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ci->lock, flags); 2418c2ecf20Sopenharmony_ci} 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci/* 2448c2ecf20Sopenharmony_ci * Remove timer from active timer list 2458c2ecf20Sopenharmony_ci */ 2468c2ecf20Sopenharmony_cistatic void ci_otg_del_timer(struct ci_hdrc *ci, enum otg_fsm_timer t) 2478c2ecf20Sopenharmony_ci{ 2488c2ecf20Sopenharmony_ci unsigned long flags, enabled_timer_bits; 2498c2ecf20Sopenharmony_ci enum otg_fsm_timer cur_timer, next_timer = NUM_OTG_FSM_TIMERS; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci if ((t >= NUM_OTG_FSM_TIMERS) || 2528c2ecf20Sopenharmony_ci !(ci->enabled_otg_timer_bits & (1 << t))) 2538c2ecf20Sopenharmony_ci return; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci spin_lock_irqsave(&ci->lock, flags); 2568c2ecf20Sopenharmony_ci ci->enabled_otg_timer_bits &= ~(1 << t); 2578c2ecf20Sopenharmony_ci if (ci->next_otg_timer == t) { 2588c2ecf20Sopenharmony_ci if (ci->enabled_otg_timer_bits == 0) { 2598c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ci->lock, flags); 2608c2ecf20Sopenharmony_ci /* No enabled timers after delete it */ 2618c2ecf20Sopenharmony_ci hrtimer_cancel(&ci->otg_fsm_hrtimer); 2628c2ecf20Sopenharmony_ci spin_lock_irqsave(&ci->lock, flags); 2638c2ecf20Sopenharmony_ci ci->next_otg_timer = NUM_OTG_FSM_TIMERS; 2648c2ecf20Sopenharmony_ci } else { 2658c2ecf20Sopenharmony_ci /* Find the next timer */ 2668c2ecf20Sopenharmony_ci enabled_timer_bits = ci->enabled_otg_timer_bits; 2678c2ecf20Sopenharmony_ci for_each_set_bit(cur_timer, &enabled_timer_bits, 2688c2ecf20Sopenharmony_ci NUM_OTG_FSM_TIMERS) { 2698c2ecf20Sopenharmony_ci if ((next_timer == NUM_OTG_FSM_TIMERS) || 2708c2ecf20Sopenharmony_ci ktime_before(ci->hr_timeouts[next_timer], 2718c2ecf20Sopenharmony_ci ci->hr_timeouts[cur_timer])) 2728c2ecf20Sopenharmony_ci next_timer = cur_timer; 2738c2ecf20Sopenharmony_ci } 2748c2ecf20Sopenharmony_ci } 2758c2ecf20Sopenharmony_ci } 2768c2ecf20Sopenharmony_ci if (next_timer != NUM_OTG_FSM_TIMERS) { 2778c2ecf20Sopenharmony_ci ci->next_otg_timer = next_timer; 2788c2ecf20Sopenharmony_ci hrtimer_start_range_ns(&ci->otg_fsm_hrtimer, 2798c2ecf20Sopenharmony_ci ci->hr_timeouts[next_timer], NSEC_PER_MSEC, 2808c2ecf20Sopenharmony_ci HRTIMER_MODE_ABS); 2818c2ecf20Sopenharmony_ci } 2828c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ci->lock, flags); 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci/* OTG FSM timer handlers */ 2868c2ecf20Sopenharmony_cistatic int a_wait_vrise_tmout(struct ci_hdrc *ci) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci ci->fsm.a_wait_vrise_tmout = 1; 2898c2ecf20Sopenharmony_ci return 0; 2908c2ecf20Sopenharmony_ci} 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_cistatic int a_wait_vfall_tmout(struct ci_hdrc *ci) 2938c2ecf20Sopenharmony_ci{ 2948c2ecf20Sopenharmony_ci ci->fsm.a_wait_vfall_tmout = 1; 2958c2ecf20Sopenharmony_ci return 0; 2968c2ecf20Sopenharmony_ci} 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_cistatic int a_wait_bcon_tmout(struct ci_hdrc *ci) 2998c2ecf20Sopenharmony_ci{ 3008c2ecf20Sopenharmony_ci ci->fsm.a_wait_bcon_tmout = 1; 3018c2ecf20Sopenharmony_ci return 0; 3028c2ecf20Sopenharmony_ci} 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_cistatic int a_aidl_bdis_tmout(struct ci_hdrc *ci) 3058c2ecf20Sopenharmony_ci{ 3068c2ecf20Sopenharmony_ci ci->fsm.a_aidl_bdis_tmout = 1; 3078c2ecf20Sopenharmony_ci return 0; 3088c2ecf20Sopenharmony_ci} 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_cistatic int b_ase0_brst_tmout(struct ci_hdrc *ci) 3118c2ecf20Sopenharmony_ci{ 3128c2ecf20Sopenharmony_ci ci->fsm.b_ase0_brst_tmout = 1; 3138c2ecf20Sopenharmony_ci return 0; 3148c2ecf20Sopenharmony_ci} 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_cistatic int a_bidl_adis_tmout(struct ci_hdrc *ci) 3178c2ecf20Sopenharmony_ci{ 3188c2ecf20Sopenharmony_ci ci->fsm.a_bidl_adis_tmout = 1; 3198c2ecf20Sopenharmony_ci return 0; 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_cistatic int b_aidl_bdis_tmout(struct ci_hdrc *ci) 3238c2ecf20Sopenharmony_ci{ 3248c2ecf20Sopenharmony_ci ci->fsm.a_bus_suspend = 1; 3258c2ecf20Sopenharmony_ci return 0; 3268c2ecf20Sopenharmony_ci} 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_cistatic int b_se0_srp_tmout(struct ci_hdrc *ci) 3298c2ecf20Sopenharmony_ci{ 3308c2ecf20Sopenharmony_ci ci->fsm.b_se0_srp = 1; 3318c2ecf20Sopenharmony_ci return 0; 3328c2ecf20Sopenharmony_ci} 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_cistatic int b_srp_fail_tmout(struct ci_hdrc *ci) 3358c2ecf20Sopenharmony_ci{ 3368c2ecf20Sopenharmony_ci ci->fsm.b_srp_done = 1; 3378c2ecf20Sopenharmony_ci return 1; 3388c2ecf20Sopenharmony_ci} 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_cistatic int b_data_pls_tmout(struct ci_hdrc *ci) 3418c2ecf20Sopenharmony_ci{ 3428c2ecf20Sopenharmony_ci ci->fsm.b_srp_done = 1; 3438c2ecf20Sopenharmony_ci ci->fsm.b_bus_req = 0; 3448c2ecf20Sopenharmony_ci if (ci->fsm.power_up) 3458c2ecf20Sopenharmony_ci ci->fsm.power_up = 0; 3468c2ecf20Sopenharmony_ci hw_write_otgsc(ci, OTGSC_HABA, 0); 3478c2ecf20Sopenharmony_ci pm_runtime_put(ci->dev); 3488c2ecf20Sopenharmony_ci return 0; 3498c2ecf20Sopenharmony_ci} 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_cistatic int b_ssend_srp_tmout(struct ci_hdrc *ci) 3528c2ecf20Sopenharmony_ci{ 3538c2ecf20Sopenharmony_ci ci->fsm.b_ssend_srp = 1; 3548c2ecf20Sopenharmony_ci /* only vbus fall below B_sess_vld in b_idle state */ 3558c2ecf20Sopenharmony_ci if (ci->fsm.otg->state == OTG_STATE_B_IDLE) 3568c2ecf20Sopenharmony_ci return 0; 3578c2ecf20Sopenharmony_ci else 3588c2ecf20Sopenharmony_ci return 1; 3598c2ecf20Sopenharmony_ci} 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci/* 3628c2ecf20Sopenharmony_ci * Keep this list in the same order as timers indexed 3638c2ecf20Sopenharmony_ci * by enum otg_fsm_timer in include/linux/usb/otg-fsm.h 3648c2ecf20Sopenharmony_ci */ 3658c2ecf20Sopenharmony_cistatic int (*otg_timer_handlers[])(struct ci_hdrc *) = { 3668c2ecf20Sopenharmony_ci a_wait_vrise_tmout, /* A_WAIT_VRISE */ 3678c2ecf20Sopenharmony_ci a_wait_vfall_tmout, /* A_WAIT_VFALL */ 3688c2ecf20Sopenharmony_ci a_wait_bcon_tmout, /* A_WAIT_BCON */ 3698c2ecf20Sopenharmony_ci a_aidl_bdis_tmout, /* A_AIDL_BDIS */ 3708c2ecf20Sopenharmony_ci b_ase0_brst_tmout, /* B_ASE0_BRST */ 3718c2ecf20Sopenharmony_ci a_bidl_adis_tmout, /* A_BIDL_ADIS */ 3728c2ecf20Sopenharmony_ci b_aidl_bdis_tmout, /* B_AIDL_BDIS */ 3738c2ecf20Sopenharmony_ci b_se0_srp_tmout, /* B_SE0_SRP */ 3748c2ecf20Sopenharmony_ci b_srp_fail_tmout, /* B_SRP_FAIL */ 3758c2ecf20Sopenharmony_ci NULL, /* A_WAIT_ENUM */ 3768c2ecf20Sopenharmony_ci b_data_pls_tmout, /* B_DATA_PLS */ 3778c2ecf20Sopenharmony_ci b_ssend_srp_tmout, /* B_SSEND_SRP */ 3788c2ecf20Sopenharmony_ci}; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci/* 3818c2ecf20Sopenharmony_ci * Enable the next nearest enabled timer if have 3828c2ecf20Sopenharmony_ci */ 3838c2ecf20Sopenharmony_cistatic enum hrtimer_restart ci_otg_hrtimer_func(struct hrtimer *t) 3848c2ecf20Sopenharmony_ci{ 3858c2ecf20Sopenharmony_ci struct ci_hdrc *ci = container_of(t, struct ci_hdrc, otg_fsm_hrtimer); 3868c2ecf20Sopenharmony_ci ktime_t now, *timeout; 3878c2ecf20Sopenharmony_ci unsigned long enabled_timer_bits; 3888c2ecf20Sopenharmony_ci unsigned long flags; 3898c2ecf20Sopenharmony_ci enum otg_fsm_timer cur_timer, next_timer = NUM_OTG_FSM_TIMERS; 3908c2ecf20Sopenharmony_ci int ret = -EINVAL; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci spin_lock_irqsave(&ci->lock, flags); 3938c2ecf20Sopenharmony_ci enabled_timer_bits = ci->enabled_otg_timer_bits; 3948c2ecf20Sopenharmony_ci ci->next_otg_timer = NUM_OTG_FSM_TIMERS; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci now = ktime_get(); 3978c2ecf20Sopenharmony_ci for_each_set_bit(cur_timer, &enabled_timer_bits, NUM_OTG_FSM_TIMERS) { 3988c2ecf20Sopenharmony_ci if (ktime_compare(now, ci->hr_timeouts[cur_timer]) >= 0) { 3998c2ecf20Sopenharmony_ci ci->enabled_otg_timer_bits &= ~(1 << cur_timer); 4008c2ecf20Sopenharmony_ci if (otg_timer_handlers[cur_timer]) 4018c2ecf20Sopenharmony_ci ret = otg_timer_handlers[cur_timer](ci); 4028c2ecf20Sopenharmony_ci } else { 4038c2ecf20Sopenharmony_ci if ((next_timer == NUM_OTG_FSM_TIMERS) || 4048c2ecf20Sopenharmony_ci ktime_before(ci->hr_timeouts[cur_timer], 4058c2ecf20Sopenharmony_ci ci->hr_timeouts[next_timer])) 4068c2ecf20Sopenharmony_ci next_timer = cur_timer; 4078c2ecf20Sopenharmony_ci } 4088c2ecf20Sopenharmony_ci } 4098c2ecf20Sopenharmony_ci /* Enable the next nearest timer */ 4108c2ecf20Sopenharmony_ci if (next_timer < NUM_OTG_FSM_TIMERS) { 4118c2ecf20Sopenharmony_ci timeout = &ci->hr_timeouts[next_timer]; 4128c2ecf20Sopenharmony_ci hrtimer_start_range_ns(&ci->otg_fsm_hrtimer, *timeout, 4138c2ecf20Sopenharmony_ci NSEC_PER_MSEC, HRTIMER_MODE_ABS); 4148c2ecf20Sopenharmony_ci ci->next_otg_timer = next_timer; 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ci->lock, flags); 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci if (!ret) 4198c2ecf20Sopenharmony_ci ci_otg_queue_work(ci); 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci return HRTIMER_NORESTART; 4228c2ecf20Sopenharmony_ci} 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci/* Initialize timers */ 4258c2ecf20Sopenharmony_cistatic int ci_otg_init_timers(struct ci_hdrc *ci) 4268c2ecf20Sopenharmony_ci{ 4278c2ecf20Sopenharmony_ci hrtimer_init(&ci->otg_fsm_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); 4288c2ecf20Sopenharmony_ci ci->otg_fsm_hrtimer.function = ci_otg_hrtimer_func; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci return 0; 4318c2ecf20Sopenharmony_ci} 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci/* -------------------------------------------------------------*/ 4348c2ecf20Sopenharmony_ci/* Operations that will be called from OTG Finite State Machine */ 4358c2ecf20Sopenharmony_ci/* -------------------------------------------------------------*/ 4368c2ecf20Sopenharmony_cistatic void ci_otg_fsm_add_timer(struct otg_fsm *fsm, enum otg_fsm_timer t) 4378c2ecf20Sopenharmony_ci{ 4388c2ecf20Sopenharmony_ci struct ci_hdrc *ci = container_of(fsm, struct ci_hdrc, fsm); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci if (t < NUM_OTG_FSM_TIMERS) 4418c2ecf20Sopenharmony_ci ci_otg_add_timer(ci, t); 4428c2ecf20Sopenharmony_ci return; 4438c2ecf20Sopenharmony_ci} 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_cistatic void ci_otg_fsm_del_timer(struct otg_fsm *fsm, enum otg_fsm_timer t) 4468c2ecf20Sopenharmony_ci{ 4478c2ecf20Sopenharmony_ci struct ci_hdrc *ci = container_of(fsm, struct ci_hdrc, fsm); 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci if (t < NUM_OTG_FSM_TIMERS) 4508c2ecf20Sopenharmony_ci ci_otg_del_timer(ci, t); 4518c2ecf20Sopenharmony_ci return; 4528c2ecf20Sopenharmony_ci} 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci/* 4558c2ecf20Sopenharmony_ci * A-device drive vbus: turn on vbus regulator and enable port power 4568c2ecf20Sopenharmony_ci * Data pulse irq should be disabled while vbus is on. 4578c2ecf20Sopenharmony_ci */ 4588c2ecf20Sopenharmony_cistatic void ci_otg_drv_vbus(struct otg_fsm *fsm, int on) 4598c2ecf20Sopenharmony_ci{ 4608c2ecf20Sopenharmony_ci int ret; 4618c2ecf20Sopenharmony_ci struct ci_hdrc *ci = container_of(fsm, struct ci_hdrc, fsm); 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci if (on) { 4648c2ecf20Sopenharmony_ci /* Enable power power */ 4658c2ecf20Sopenharmony_ci hw_write(ci, OP_PORTSC, PORTSC_W1C_BITS | PORTSC_PP, 4668c2ecf20Sopenharmony_ci PORTSC_PP); 4678c2ecf20Sopenharmony_ci if (ci->platdata->reg_vbus) { 4688c2ecf20Sopenharmony_ci ret = regulator_enable(ci->platdata->reg_vbus); 4698c2ecf20Sopenharmony_ci if (ret) { 4708c2ecf20Sopenharmony_ci dev_err(ci->dev, 4718c2ecf20Sopenharmony_ci "Failed to enable vbus regulator, ret=%d\n", 4728c2ecf20Sopenharmony_ci ret); 4738c2ecf20Sopenharmony_ci return; 4748c2ecf20Sopenharmony_ci } 4758c2ecf20Sopenharmony_ci } 4768c2ecf20Sopenharmony_ci /* Disable data pulse irq */ 4778c2ecf20Sopenharmony_ci hw_write_otgsc(ci, OTGSC_DPIE, 0); 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci fsm->a_srp_det = 0; 4808c2ecf20Sopenharmony_ci fsm->power_up = 0; 4818c2ecf20Sopenharmony_ci } else { 4828c2ecf20Sopenharmony_ci if (ci->platdata->reg_vbus) 4838c2ecf20Sopenharmony_ci regulator_disable(ci->platdata->reg_vbus); 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci fsm->a_bus_drop = 1; 4868c2ecf20Sopenharmony_ci fsm->a_bus_req = 0; 4878c2ecf20Sopenharmony_ci } 4888c2ecf20Sopenharmony_ci} 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci/* 4918c2ecf20Sopenharmony_ci * Control data line by Run Stop bit. 4928c2ecf20Sopenharmony_ci */ 4938c2ecf20Sopenharmony_cistatic void ci_otg_loc_conn(struct otg_fsm *fsm, int on) 4948c2ecf20Sopenharmony_ci{ 4958c2ecf20Sopenharmony_ci struct ci_hdrc *ci = container_of(fsm, struct ci_hdrc, fsm); 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci if (on) 4988c2ecf20Sopenharmony_ci hw_write(ci, OP_USBCMD, USBCMD_RS, USBCMD_RS); 4998c2ecf20Sopenharmony_ci else 5008c2ecf20Sopenharmony_ci hw_write(ci, OP_USBCMD, USBCMD_RS, 0); 5018c2ecf20Sopenharmony_ci} 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci/* 5048c2ecf20Sopenharmony_ci * Generate SOF by host. 5058c2ecf20Sopenharmony_ci * In host mode, controller will automatically send SOF. 5068c2ecf20Sopenharmony_ci * Suspend will block the data on the port. 5078c2ecf20Sopenharmony_ci * 5088c2ecf20Sopenharmony_ci * This is controlled through usbcore by usb autosuspend, 5098c2ecf20Sopenharmony_ci * so the usb device class driver need support autosuspend, 5108c2ecf20Sopenharmony_ci * otherwise the bus suspend will not happen. 5118c2ecf20Sopenharmony_ci */ 5128c2ecf20Sopenharmony_cistatic void ci_otg_loc_sof(struct otg_fsm *fsm, int on) 5138c2ecf20Sopenharmony_ci{ 5148c2ecf20Sopenharmony_ci struct usb_device *udev; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci if (!fsm->otg->host) 5178c2ecf20Sopenharmony_ci return; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci udev = usb_hub_find_child(fsm->otg->host->root_hub, 1); 5208c2ecf20Sopenharmony_ci if (!udev) 5218c2ecf20Sopenharmony_ci return; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci if (on) { 5248c2ecf20Sopenharmony_ci usb_disable_autosuspend(udev); 5258c2ecf20Sopenharmony_ci } else { 5268c2ecf20Sopenharmony_ci pm_runtime_set_autosuspend_delay(&udev->dev, 0); 5278c2ecf20Sopenharmony_ci usb_enable_autosuspend(udev); 5288c2ecf20Sopenharmony_ci } 5298c2ecf20Sopenharmony_ci} 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci/* 5328c2ecf20Sopenharmony_ci * Start SRP pulsing by data-line pulsing, 5338c2ecf20Sopenharmony_ci * no v-bus pulsing followed 5348c2ecf20Sopenharmony_ci */ 5358c2ecf20Sopenharmony_cistatic void ci_otg_start_pulse(struct otg_fsm *fsm) 5368c2ecf20Sopenharmony_ci{ 5378c2ecf20Sopenharmony_ci struct ci_hdrc *ci = container_of(fsm, struct ci_hdrc, fsm); 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci /* Hardware Assistant Data pulse */ 5408c2ecf20Sopenharmony_ci hw_write_otgsc(ci, OTGSC_HADP, OTGSC_HADP); 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci pm_runtime_get(ci->dev); 5438c2ecf20Sopenharmony_ci ci_otg_add_timer(ci, B_DATA_PLS); 5448c2ecf20Sopenharmony_ci} 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_cistatic int ci_otg_start_host(struct otg_fsm *fsm, int on) 5478c2ecf20Sopenharmony_ci{ 5488c2ecf20Sopenharmony_ci struct ci_hdrc *ci = container_of(fsm, struct ci_hdrc, fsm); 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci if (on) { 5518c2ecf20Sopenharmony_ci ci_role_stop(ci); 5528c2ecf20Sopenharmony_ci ci_role_start(ci, CI_ROLE_HOST); 5538c2ecf20Sopenharmony_ci } else { 5548c2ecf20Sopenharmony_ci ci_role_stop(ci); 5558c2ecf20Sopenharmony_ci ci_role_start(ci, CI_ROLE_GADGET); 5568c2ecf20Sopenharmony_ci } 5578c2ecf20Sopenharmony_ci return 0; 5588c2ecf20Sopenharmony_ci} 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_cistatic int ci_otg_start_gadget(struct otg_fsm *fsm, int on) 5618c2ecf20Sopenharmony_ci{ 5628c2ecf20Sopenharmony_ci struct ci_hdrc *ci = container_of(fsm, struct ci_hdrc, fsm); 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci if (on) 5658c2ecf20Sopenharmony_ci usb_gadget_vbus_connect(&ci->gadget); 5668c2ecf20Sopenharmony_ci else 5678c2ecf20Sopenharmony_ci usb_gadget_vbus_disconnect(&ci->gadget); 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci return 0; 5708c2ecf20Sopenharmony_ci} 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_cistatic struct otg_fsm_ops ci_otg_ops = { 5738c2ecf20Sopenharmony_ci .drv_vbus = ci_otg_drv_vbus, 5748c2ecf20Sopenharmony_ci .loc_conn = ci_otg_loc_conn, 5758c2ecf20Sopenharmony_ci .loc_sof = ci_otg_loc_sof, 5768c2ecf20Sopenharmony_ci .start_pulse = ci_otg_start_pulse, 5778c2ecf20Sopenharmony_ci .add_timer = ci_otg_fsm_add_timer, 5788c2ecf20Sopenharmony_ci .del_timer = ci_otg_fsm_del_timer, 5798c2ecf20Sopenharmony_ci .start_host = ci_otg_start_host, 5808c2ecf20Sopenharmony_ci .start_gadget = ci_otg_start_gadget, 5818c2ecf20Sopenharmony_ci}; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ciint ci_otg_fsm_work(struct ci_hdrc *ci) 5848c2ecf20Sopenharmony_ci{ 5858c2ecf20Sopenharmony_ci /* 5868c2ecf20Sopenharmony_ci * Don't do fsm transition for B device 5878c2ecf20Sopenharmony_ci * when there is no gadget class driver 5888c2ecf20Sopenharmony_ci */ 5898c2ecf20Sopenharmony_ci if (ci->fsm.id && !(ci->driver) && 5908c2ecf20Sopenharmony_ci ci->fsm.otg->state < OTG_STATE_A_IDLE) 5918c2ecf20Sopenharmony_ci return 0; 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci pm_runtime_get_sync(ci->dev); 5948c2ecf20Sopenharmony_ci if (otg_statemachine(&ci->fsm)) { 5958c2ecf20Sopenharmony_ci if (ci->fsm.otg->state == OTG_STATE_A_IDLE) { 5968c2ecf20Sopenharmony_ci /* 5978c2ecf20Sopenharmony_ci * Further state change for cases: 5988c2ecf20Sopenharmony_ci * a_idle to b_idle; or 5998c2ecf20Sopenharmony_ci * a_idle to a_wait_vrise due to ID change(1->0), so 6008c2ecf20Sopenharmony_ci * B-dev becomes A-dev can try to start new session 6018c2ecf20Sopenharmony_ci * consequently; or 6028c2ecf20Sopenharmony_ci * a_idle to a_wait_vrise when power up 6038c2ecf20Sopenharmony_ci */ 6048c2ecf20Sopenharmony_ci if ((ci->fsm.id) || (ci->id_event) || 6058c2ecf20Sopenharmony_ci (ci->fsm.power_up)) { 6068c2ecf20Sopenharmony_ci ci_otg_queue_work(ci); 6078c2ecf20Sopenharmony_ci } else { 6088c2ecf20Sopenharmony_ci /* Enable data pulse irq */ 6098c2ecf20Sopenharmony_ci hw_write(ci, OP_PORTSC, PORTSC_W1C_BITS | 6108c2ecf20Sopenharmony_ci PORTSC_PP, 0); 6118c2ecf20Sopenharmony_ci hw_write_otgsc(ci, OTGSC_DPIS, OTGSC_DPIS); 6128c2ecf20Sopenharmony_ci hw_write_otgsc(ci, OTGSC_DPIE, OTGSC_DPIE); 6138c2ecf20Sopenharmony_ci } 6148c2ecf20Sopenharmony_ci if (ci->id_event) 6158c2ecf20Sopenharmony_ci ci->id_event = false; 6168c2ecf20Sopenharmony_ci } else if (ci->fsm.otg->state == OTG_STATE_B_IDLE) { 6178c2ecf20Sopenharmony_ci if (ci->fsm.b_sess_vld) { 6188c2ecf20Sopenharmony_ci ci->fsm.power_up = 0; 6198c2ecf20Sopenharmony_ci /* 6208c2ecf20Sopenharmony_ci * Further transite to b_periphearl state 6218c2ecf20Sopenharmony_ci * when register gadget driver with vbus on 6228c2ecf20Sopenharmony_ci */ 6238c2ecf20Sopenharmony_ci ci_otg_queue_work(ci); 6248c2ecf20Sopenharmony_ci } 6258c2ecf20Sopenharmony_ci } else if (ci->fsm.otg->state == OTG_STATE_A_HOST) { 6268c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(ci->dev); 6278c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(ci->dev); 6288c2ecf20Sopenharmony_ci return 0; 6298c2ecf20Sopenharmony_ci } 6308c2ecf20Sopenharmony_ci } 6318c2ecf20Sopenharmony_ci pm_runtime_put_sync(ci->dev); 6328c2ecf20Sopenharmony_ci return 0; 6338c2ecf20Sopenharmony_ci} 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci/* 6368c2ecf20Sopenharmony_ci * Update fsm variables in each state if catching expected interrupts, 6378c2ecf20Sopenharmony_ci * called by otg fsm isr. 6388c2ecf20Sopenharmony_ci */ 6398c2ecf20Sopenharmony_cistatic void ci_otg_fsm_event(struct ci_hdrc *ci) 6408c2ecf20Sopenharmony_ci{ 6418c2ecf20Sopenharmony_ci u32 intr_sts, otg_bsess_vld, port_conn; 6428c2ecf20Sopenharmony_ci struct otg_fsm *fsm = &ci->fsm; 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci intr_sts = hw_read_intr_status(ci); 6458c2ecf20Sopenharmony_ci otg_bsess_vld = hw_read_otgsc(ci, OTGSC_BSV); 6468c2ecf20Sopenharmony_ci port_conn = hw_read(ci, OP_PORTSC, PORTSC_CCS); 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci switch (ci->fsm.otg->state) { 6498c2ecf20Sopenharmony_ci case OTG_STATE_A_WAIT_BCON: 6508c2ecf20Sopenharmony_ci if (port_conn) { 6518c2ecf20Sopenharmony_ci fsm->b_conn = 1; 6528c2ecf20Sopenharmony_ci fsm->a_bus_req = 1; 6538c2ecf20Sopenharmony_ci ci_otg_queue_work(ci); 6548c2ecf20Sopenharmony_ci } 6558c2ecf20Sopenharmony_ci break; 6568c2ecf20Sopenharmony_ci case OTG_STATE_B_IDLE: 6578c2ecf20Sopenharmony_ci if (otg_bsess_vld && (intr_sts & USBi_PCI) && port_conn) { 6588c2ecf20Sopenharmony_ci fsm->b_sess_vld = 1; 6598c2ecf20Sopenharmony_ci ci_otg_queue_work(ci); 6608c2ecf20Sopenharmony_ci } 6618c2ecf20Sopenharmony_ci break; 6628c2ecf20Sopenharmony_ci case OTG_STATE_B_PERIPHERAL: 6638c2ecf20Sopenharmony_ci if ((intr_sts & USBi_SLI) && port_conn && otg_bsess_vld) { 6648c2ecf20Sopenharmony_ci ci_otg_add_timer(ci, B_AIDL_BDIS); 6658c2ecf20Sopenharmony_ci } else if (intr_sts & USBi_PCI) { 6668c2ecf20Sopenharmony_ci ci_otg_del_timer(ci, B_AIDL_BDIS); 6678c2ecf20Sopenharmony_ci if (fsm->a_bus_suspend == 1) 6688c2ecf20Sopenharmony_ci fsm->a_bus_suspend = 0; 6698c2ecf20Sopenharmony_ci } 6708c2ecf20Sopenharmony_ci break; 6718c2ecf20Sopenharmony_ci case OTG_STATE_B_HOST: 6728c2ecf20Sopenharmony_ci if ((intr_sts & USBi_PCI) && !port_conn) { 6738c2ecf20Sopenharmony_ci fsm->a_conn = 0; 6748c2ecf20Sopenharmony_ci fsm->b_bus_req = 0; 6758c2ecf20Sopenharmony_ci ci_otg_queue_work(ci); 6768c2ecf20Sopenharmony_ci } 6778c2ecf20Sopenharmony_ci break; 6788c2ecf20Sopenharmony_ci case OTG_STATE_A_PERIPHERAL: 6798c2ecf20Sopenharmony_ci if (intr_sts & USBi_SLI) { 6808c2ecf20Sopenharmony_ci fsm->b_bus_suspend = 1; 6818c2ecf20Sopenharmony_ci /* 6828c2ecf20Sopenharmony_ci * Init a timer to know how long this suspend 6838c2ecf20Sopenharmony_ci * will continue, if time out, indicates B no longer 6848c2ecf20Sopenharmony_ci * wants to be host role 6858c2ecf20Sopenharmony_ci */ 6868c2ecf20Sopenharmony_ci ci_otg_add_timer(ci, A_BIDL_ADIS); 6878c2ecf20Sopenharmony_ci } 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci if (intr_sts & USBi_URI) 6908c2ecf20Sopenharmony_ci ci_otg_del_timer(ci, A_BIDL_ADIS); 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci if (intr_sts & USBi_PCI) { 6938c2ecf20Sopenharmony_ci if (fsm->b_bus_suspend == 1) { 6948c2ecf20Sopenharmony_ci ci_otg_del_timer(ci, A_BIDL_ADIS); 6958c2ecf20Sopenharmony_ci fsm->b_bus_suspend = 0; 6968c2ecf20Sopenharmony_ci } 6978c2ecf20Sopenharmony_ci } 6988c2ecf20Sopenharmony_ci break; 6998c2ecf20Sopenharmony_ci case OTG_STATE_A_SUSPEND: 7008c2ecf20Sopenharmony_ci if ((intr_sts & USBi_PCI) && !port_conn) { 7018c2ecf20Sopenharmony_ci fsm->b_conn = 0; 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci /* if gadget driver is binded */ 7048c2ecf20Sopenharmony_ci if (ci->driver) { 7058c2ecf20Sopenharmony_ci /* A device to be peripheral mode */ 7068c2ecf20Sopenharmony_ci ci->gadget.is_a_peripheral = 1; 7078c2ecf20Sopenharmony_ci } 7088c2ecf20Sopenharmony_ci ci_otg_queue_work(ci); 7098c2ecf20Sopenharmony_ci } 7108c2ecf20Sopenharmony_ci break; 7118c2ecf20Sopenharmony_ci case OTG_STATE_A_HOST: 7128c2ecf20Sopenharmony_ci if ((intr_sts & USBi_PCI) && !port_conn) { 7138c2ecf20Sopenharmony_ci fsm->b_conn = 0; 7148c2ecf20Sopenharmony_ci ci_otg_queue_work(ci); 7158c2ecf20Sopenharmony_ci } 7168c2ecf20Sopenharmony_ci break; 7178c2ecf20Sopenharmony_ci case OTG_STATE_B_WAIT_ACON: 7188c2ecf20Sopenharmony_ci if ((intr_sts & USBi_PCI) && port_conn) { 7198c2ecf20Sopenharmony_ci fsm->a_conn = 1; 7208c2ecf20Sopenharmony_ci ci_otg_queue_work(ci); 7218c2ecf20Sopenharmony_ci } 7228c2ecf20Sopenharmony_ci break; 7238c2ecf20Sopenharmony_ci default: 7248c2ecf20Sopenharmony_ci break; 7258c2ecf20Sopenharmony_ci } 7268c2ecf20Sopenharmony_ci} 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci/* 7298c2ecf20Sopenharmony_ci * ci_otg_irq - otg fsm related irq handling 7308c2ecf20Sopenharmony_ci * and also update otg fsm variable by monitoring usb host and udc 7318c2ecf20Sopenharmony_ci * state change interrupts. 7328c2ecf20Sopenharmony_ci * @ci: ci_hdrc 7338c2ecf20Sopenharmony_ci */ 7348c2ecf20Sopenharmony_ciirqreturn_t ci_otg_fsm_irq(struct ci_hdrc *ci) 7358c2ecf20Sopenharmony_ci{ 7368c2ecf20Sopenharmony_ci irqreturn_t retval = IRQ_NONE; 7378c2ecf20Sopenharmony_ci u32 otgsc, otg_int_src = 0; 7388c2ecf20Sopenharmony_ci struct otg_fsm *fsm = &ci->fsm; 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci otgsc = hw_read_otgsc(ci, ~0); 7418c2ecf20Sopenharmony_ci otg_int_src = otgsc & OTGSC_INT_STATUS_BITS & (otgsc >> 8); 7428c2ecf20Sopenharmony_ci fsm->id = (otgsc & OTGSC_ID) ? 1 : 0; 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci if (otg_int_src) { 7458c2ecf20Sopenharmony_ci if (otg_int_src & OTGSC_DPIS) { 7468c2ecf20Sopenharmony_ci hw_write_otgsc(ci, OTGSC_DPIS, OTGSC_DPIS); 7478c2ecf20Sopenharmony_ci fsm->a_srp_det = 1; 7488c2ecf20Sopenharmony_ci fsm->a_bus_drop = 0; 7498c2ecf20Sopenharmony_ci } else if (otg_int_src & OTGSC_IDIS) { 7508c2ecf20Sopenharmony_ci hw_write_otgsc(ci, OTGSC_IDIS, OTGSC_IDIS); 7518c2ecf20Sopenharmony_ci if (fsm->id == 0) { 7528c2ecf20Sopenharmony_ci fsm->a_bus_drop = 0; 7538c2ecf20Sopenharmony_ci fsm->a_bus_req = 1; 7548c2ecf20Sopenharmony_ci ci->id_event = true; 7558c2ecf20Sopenharmony_ci } 7568c2ecf20Sopenharmony_ci } else if (otg_int_src & OTGSC_BSVIS) { 7578c2ecf20Sopenharmony_ci hw_write_otgsc(ci, OTGSC_BSVIS, OTGSC_BSVIS); 7588c2ecf20Sopenharmony_ci if (otgsc & OTGSC_BSV) { 7598c2ecf20Sopenharmony_ci fsm->b_sess_vld = 1; 7608c2ecf20Sopenharmony_ci ci_otg_del_timer(ci, B_SSEND_SRP); 7618c2ecf20Sopenharmony_ci ci_otg_del_timer(ci, B_SRP_FAIL); 7628c2ecf20Sopenharmony_ci fsm->b_ssend_srp = 0; 7638c2ecf20Sopenharmony_ci } else { 7648c2ecf20Sopenharmony_ci fsm->b_sess_vld = 0; 7658c2ecf20Sopenharmony_ci if (fsm->id) 7668c2ecf20Sopenharmony_ci ci_otg_add_timer(ci, B_SSEND_SRP); 7678c2ecf20Sopenharmony_ci } 7688c2ecf20Sopenharmony_ci } else if (otg_int_src & OTGSC_AVVIS) { 7698c2ecf20Sopenharmony_ci hw_write_otgsc(ci, OTGSC_AVVIS, OTGSC_AVVIS); 7708c2ecf20Sopenharmony_ci if (otgsc & OTGSC_AVV) { 7718c2ecf20Sopenharmony_ci fsm->a_vbus_vld = 1; 7728c2ecf20Sopenharmony_ci } else { 7738c2ecf20Sopenharmony_ci fsm->a_vbus_vld = 0; 7748c2ecf20Sopenharmony_ci fsm->b_conn = 0; 7758c2ecf20Sopenharmony_ci } 7768c2ecf20Sopenharmony_ci } 7778c2ecf20Sopenharmony_ci ci_otg_queue_work(ci); 7788c2ecf20Sopenharmony_ci return IRQ_HANDLED; 7798c2ecf20Sopenharmony_ci } 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci ci_otg_fsm_event(ci); 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci return retval; 7848c2ecf20Sopenharmony_ci} 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_civoid ci_hdrc_otg_fsm_start(struct ci_hdrc *ci) 7878c2ecf20Sopenharmony_ci{ 7888c2ecf20Sopenharmony_ci ci_otg_queue_work(ci); 7898c2ecf20Sopenharmony_ci} 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ciint ci_hdrc_otg_fsm_init(struct ci_hdrc *ci) 7928c2ecf20Sopenharmony_ci{ 7938c2ecf20Sopenharmony_ci int retval = 0; 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci if (ci->phy) 7968c2ecf20Sopenharmony_ci ci->otg.phy = ci->phy; 7978c2ecf20Sopenharmony_ci else 7988c2ecf20Sopenharmony_ci ci->otg.usb_phy = ci->usb_phy; 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci ci->otg.gadget = &ci->gadget; 8018c2ecf20Sopenharmony_ci ci->fsm.otg = &ci->otg; 8028c2ecf20Sopenharmony_ci ci->fsm.power_up = 1; 8038c2ecf20Sopenharmony_ci ci->fsm.id = hw_read_otgsc(ci, OTGSC_ID) ? 1 : 0; 8048c2ecf20Sopenharmony_ci ci->fsm.otg->state = OTG_STATE_UNDEFINED; 8058c2ecf20Sopenharmony_ci ci->fsm.ops = &ci_otg_ops; 8068c2ecf20Sopenharmony_ci ci->gadget.hnp_polling_support = 1; 8078c2ecf20Sopenharmony_ci ci->fsm.host_req_flag = devm_kzalloc(ci->dev, 1, GFP_KERNEL); 8088c2ecf20Sopenharmony_ci if (!ci->fsm.host_req_flag) 8098c2ecf20Sopenharmony_ci return -ENOMEM; 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci mutex_init(&ci->fsm.lock); 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci retval = ci_otg_init_timers(ci); 8148c2ecf20Sopenharmony_ci if (retval) { 8158c2ecf20Sopenharmony_ci dev_err(ci->dev, "Couldn't init OTG timers\n"); 8168c2ecf20Sopenharmony_ci return retval; 8178c2ecf20Sopenharmony_ci } 8188c2ecf20Sopenharmony_ci ci->enabled_otg_timer_bits = 0; 8198c2ecf20Sopenharmony_ci ci->next_otg_timer = NUM_OTG_FSM_TIMERS; 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci retval = sysfs_create_group(&ci->dev->kobj, &inputs_attr_group); 8228c2ecf20Sopenharmony_ci if (retval < 0) { 8238c2ecf20Sopenharmony_ci dev_dbg(ci->dev, 8248c2ecf20Sopenharmony_ci "Can't register sysfs attr group: %d\n", retval); 8258c2ecf20Sopenharmony_ci return retval; 8268c2ecf20Sopenharmony_ci } 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci /* Enable A vbus valid irq */ 8298c2ecf20Sopenharmony_ci hw_write_otgsc(ci, OTGSC_AVVIE, OTGSC_AVVIE); 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci if (ci->fsm.id) { 8328c2ecf20Sopenharmony_ci ci->fsm.b_ssend_srp = 8338c2ecf20Sopenharmony_ci hw_read_otgsc(ci, OTGSC_BSV) ? 0 : 1; 8348c2ecf20Sopenharmony_ci ci->fsm.b_sess_vld = 8358c2ecf20Sopenharmony_ci hw_read_otgsc(ci, OTGSC_BSV) ? 1 : 0; 8368c2ecf20Sopenharmony_ci /* Enable BSV irq */ 8378c2ecf20Sopenharmony_ci hw_write_otgsc(ci, OTGSC_BSVIE, OTGSC_BSVIE); 8388c2ecf20Sopenharmony_ci } 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci return 0; 8418c2ecf20Sopenharmony_ci} 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_civoid ci_hdrc_otg_fsm_remove(struct ci_hdrc *ci) 8448c2ecf20Sopenharmony_ci{ 8458c2ecf20Sopenharmony_ci sysfs_remove_group(&ci->dev->kobj, &inputs_attr_group); 8468c2ecf20Sopenharmony_ci} 847