Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ef302ddf authored by Ajay Agarwal's avatar Ajay Agarwal Committed by Sriharsha Allenki
Browse files

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: default avatarAjay Agarwal <ajaya@codeaurora.org>
Signed-off-by: default avatarSriharsha Allenki <sallenki@codeaurora.org>
parent f20188bc
Loading
Loading
Loading
Loading
+2 −0
Original line number Original line Diff line number Diff line
@@ -1125,6 +1125,7 @@ struct dwc3_scratchpad_array {
 * @bh_completion_time: time taken for taklet completion
 * @bh_completion_time: time taken for taklet completion
 * @bh_handled_evt_cnt: no. of events handled by tasklet per interrupt
 * @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
 * @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 dwc3 {
	struct work_struct	drd_work;
	struct work_struct	drd_work;
@@ -1359,6 +1360,7 @@ struct dwc3 {
	u32			gen2_tx_de_emph1;
	u32			gen2_tx_de_emph1;
	u32			gen2_tx_de_emph2;
	u32			gen2_tx_de_emph2;
	u32			gen2_tx_de_emph3;
	u32			gen2_tx_de_emph3;
	ktime_t			last_run_stop;
};
};


#define INCRX_BURST_MODE 0
#define INCRX_BURST_MODE 0
+12 −0
Original line number Original line Diff line number Diff line
@@ -2105,6 +2105,8 @@ static int dwc3_device_core_soft_reset(struct dwc3 *dwc)
	return 0;
	return 0;
}
}


#define MIN_RUN_STOP_DELAY_MS 50

static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend)
static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend)
{
{
	u32			reg, reg1;
	u32			reg, reg1;
@@ -2213,6 +2215,7 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
	struct dwc3		*dwc = gadget_to_dwc(g);
	struct dwc3		*dwc = gadget_to_dwc(g);
	unsigned long		flags;
	unsigned long		flags;
	int			ret;
	int			ret;
	ktime_t			diff;


	is_on = !!is_on;
	is_on = !!is_on;
	dwc->softconnect = is_on;
	dwc->softconnect = is_on;
@@ -2231,6 +2234,15 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
	dbg_event(0xFF, "Pullup gsync",
	dbg_event(0xFF, "Pullup gsync",
		atomic_read(&dwc->dev->power.usage_count));
		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
	 * 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.
	 * is still in process, complete it and get the core into setup phase.