usb: dwc3: gadget: Ensure minimum delay between run/stop

Some controller hardware, such as DWC3, need a minimum delay
between removing and re-applying the pullups in order for the
host to properly detect a soft disconnect and for subsequent
re-enumeration to succeed. Keep track of the last time run_stop
was updated and delay if necessary so that enough time will
have elapsed before calling run_stop clear/set again.

Change-Id: I8ca13304edf4c9fcc3093a063a6004bd8b76ed44
Signed-off-by: Ajay Agarwal <ajaya@codeaurora.org>
Signed-off-by: Sriharsha Allenki <sallenki@codeaurora.org>
This commit is contained in:
Ajay Agarwal 2020-02-13 20:44:09 +05:30 • committed by Udipto Goswami
commit 2e6a2a5f93
2 changed files with 14 additions and 0 deletions

View file

@ -1149,6 +1149,7 @@ struct dwc3_scratchpad_array {
* @bh_completion_time: time taken for taklet completion
* @bh_handled_evt_cnt: no. of events handled by tasklet per interrupt
* @bh_dbg_index: index for capturing bh_completion_time and bh_handled_evt_cnt
* @last_run_stop: timestamp denoting the last run_stop update
*/
struct dwc3 {
struct work_struct drd_work;
@ -1393,6 +1394,7 @@ struct dwc3 {
u32 gen2_tx_de_emph1;
u32 gen2_tx_de_emph2;
u32 gen2_tx_de_emph3;
ktime_t last_run_stop;
};
#define INCRX_BURST_MODE 0

View file

@ -2047,6 +2047,8 @@ done:
return 0;
}
#define MIN_RUN_STOP_DELAY_MS 50
static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend)
{
u32 reg, reg1;
@ -2156,6 +2158,7 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
struct dwc3 *dwc = gadget_to_dwc(g);
unsigned long flags;
int ret;
ktime_t diff;
is_on = !!is_on;
dwc->softconnect = is_on;
@ -2174,6 +2177,15 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
dbg_event(0xFF, "Pullup gsync",
atomic_read(&dwc->dev->power.usage_count));
diff = ktime_sub(ktime_get(), dwc->last_run_stop);
if (ktime_to_ms(diff) < MIN_RUN_STOP_DELAY_MS) {
dbg_event(0xFF, "waitBefRun_Stop",
MIN_RUN_STOP_DELAY_MS - ktime_to_ms(diff));
msleep(MIN_RUN_STOP_DELAY_MS - ktime_to_ms(diff));
}
dwc->last_run_stop = ktime_get();
/*
* Per databook, when we want to stop the gadget, if a control transfer
* is still in process, complete it and get the core into setup phase.