From: Li Jun <b47624@xxxxxxxxxxxxx> Add a dedicataed normal timer for HNP polling since it's cyclical, while in peripheral mode, change a/b_bus_req to be 1 will make it response to host request flag with 1, then role switch will be started. Signed-off-by: Li Jun <jun.li@xxxxxxxxxxxxx> --- drivers/usb/chipidea/ci.h | 4 ++++ drivers/usb/chipidea/otg_fsm.c | 49 +++++++++++++++++++++++++++++++++++++--- drivers/usb/chipidea/otg_fsm.h | 2 ++ 3 files changed, 52 insertions(+), 3 deletions(-) diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h index aeec5f0..3192a44 100644 --- a/drivers/usb/chipidea/ci.h +++ b/drivers/usb/chipidea/ci.h @@ -166,6 +166,8 @@ struct hw_bank { * @hr_timeouts: time out list for active otg fsm timers * @enabled_otg_timer_bits: bits of enabled otg timers * @next_otg_timer: next nearest enabled timer to be expired + * @hnp_polling_timer: cyclical timer for hnp polling + * @hnp_polling_req: indicates there is hnp polling request * @work: work for role changing * @wq: workqueue thread * @qh_pool: allocation pool for queue heads @@ -212,6 +214,8 @@ struct ci_hdrc { ktime_t hr_timeouts[NUM_OTG_FSM_TIMERS]; unsigned enabled_otg_timer_bits; enum otg_fsm_timer next_otg_timer; + struct timer_list hnp_polling_timer; + bool hnp_polling_req; struct work_struct work; struct workqueue_struct *wq; diff --git a/drivers/usb/chipidea/otg_fsm.c b/drivers/usb/chipidea/otg_fsm.c index 083acf4..ed79ae7 100644 --- a/drivers/usb/chipidea/otg_fsm.c +++ b/drivers/usb/chipidea/otg_fsm.c @@ -66,6 +66,11 @@ set_a_bus_req(struct device *dev, struct device_attribute *attr, return count; } ci->fsm.a_bus_req = 1; + if (ci->fsm.otg->state == OTG_STATE_A_PERIPHERAL) { + ci->gadget.host_request_flag = 1; + mutex_unlock(&ci->fsm.lock); + return count; + } } ci_otg_queue_work(ci); @@ -144,8 +149,14 @@ set_b_bus_req(struct device *dev, struct device_attribute *attr, mutex_lock(&ci->fsm.lock); if (buf[0] == '0') ci->fsm.b_bus_req = 0; - else if (buf[0] == '1') + else if (buf[0] == '1') { ci->fsm.b_bus_req = 1; + if (ci->fsm.otg->state == OTG_STATE_B_PERIPHERAL) { + ci->gadget.host_request_flag = 1; + mutex_unlock(&ci->fsm.lock); + return count; + } + } ci_otg_queue_work(ci); mutex_unlock(&ci->fsm.lock); @@ -203,6 +214,7 @@ static unsigned otg_timer_ms[] = { 0, TB_DATA_PLS, TB_SSEND_SRP, + 0, }; /* @@ -358,6 +370,7 @@ static int (*otg_timer_handlers[])(struct ci_hdrc *) = { NULL, /* A_WAIT_ENUM */ b_data_pls_tmout, /* B_DATA_PLS */ b_ssend_srp_tmout, /* B_SSEND_SRP */ + NULL, /* HNP_POLLING */ }; /* @@ -404,15 +417,32 @@ static enum hrtimer_restart ci_otg_hrtimer_func(struct hrtimer *t) return HRTIMER_NORESTART; } +static void hnp_polling_timer_work(unsigned long arg) +{ + struct ci_hdrc *ci = (struct ci_hdrc *)arg; + + ci->hnp_polling_req = true; + ci_otg_queue_work(ci); +} + /* Initialize timers */ static int ci_otg_init_timers(struct ci_hdrc *ci) { hrtimer_init(&ci->otg_fsm_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); ci->otg_fsm_hrtimer.function = ci_otg_hrtimer_func; + setup_timer(&ci->hnp_polling_timer, hnp_polling_timer_work, + (unsigned long)ci); + return 0; } +static void ci_otg_add_hnp_polling_timer(struct ci_hdrc *ci) +{ + mod_timer(&ci->hnp_polling_timer, + jiffies + msecs_to_jiffies(T_HOST_REQ_POLL)); +} + /* -------------------------------------------------------------*/ /* Operations that will be called from OTG Finite State Machine */ /* -------------------------------------------------------------*/ @@ -420,8 +450,12 @@ static void ci_otg_fsm_add_timer(struct otg_fsm *fsm, enum otg_fsm_timer t) { struct ci_hdrc *ci = container_of(fsm, struct ci_hdrc, fsm); - if (t < NUM_OTG_FSM_TIMERS) - ci_otg_add_timer(ci, t); + if (t < NUM_OTG_FSM_TIMERS) { + if (t == HNP_POLLING) + ci_otg_add_hnp_polling_timer(ci); + else + ci_otg_add_timer(ci, t); + } return; } @@ -569,6 +603,14 @@ int ci_otg_fsm_work(struct ci_hdrc *ci) return 0; pm_runtime_get_sync(ci->dev); + if (ci->hnp_polling_req) { + ci->hnp_polling_req = false; + if (otg_hnp_polling(&ci->fsm) != HOST_REQUEST_FLAG) { + pm_runtime_put_sync(ci->dev); + return 0; + } + } + if (otg_statemachine(&ci->fsm)) { if (ci->fsm.otg->state == OTG_STATE_A_IDLE) { /* @@ -817,4 +859,5 @@ int ci_hdrc_otg_fsm_init(struct ci_hdrc *ci) void ci_hdrc_otg_fsm_remove(struct ci_hdrc *ci) { sysfs_remove_group(&ci->dev->kobj, &inputs_attr_group); + del_timer_sync(&ci->hnp_polling_timer); } diff --git a/drivers/usb/chipidea/otg_fsm.h b/drivers/usb/chipidea/otg_fsm.h index 2689375..fbd6dc7 100644 --- a/drivers/usb/chipidea/otg_fsm.h +++ b/drivers/usb/chipidea/otg_fsm.h @@ -62,6 +62,8 @@ /* SSEND time before SRP */ #define TB_SSEND_SRP (1500) /* minimum 1.5 sec, section:5.1.2 */ +#define T_HOST_REQ_POLL (1500) /* HNP polling interval 1s~2s */ + #ifdef CONFIG_USB_OTG_FSM int ci_hdrc_otg_fsm_init(struct ci_hdrc *ci); -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html