Re: usb: dwc2: Problem with remote wakeup implementation

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Maxim,

On 3/24/2022 2:24 AM, Maxim Devaev wrote:
> Hello. I'm trying to implement remote wakeup signalling for dwc2.
> The dwc3 driver in gadget mode has the ability to send a remote
> wakeup signal to the host by writing 1 to the srp file:
> 
> echo 1 > /sys/class/udc/XXX/srp
> 
> My naive implementation was able to wake up the host on 5.10 kernel,
> but it's not working anymore on 5.15, it's just does nothing now.
> I tried to roll back all the changes in drivers/usb/dwc2 to the 5.10,
> but it didn't help.
> 
> I don't have any DesignWare documentation, so I hope someone
> can help me to make it work in the right way.
> 

According databook RmtWkUpSig bit description below. You should also 
consider LPM state.

Remote Wakeup Signaling (RmtWkUpSig)
When the application sets this bit, the core initiates remote
signaling to wake up the USB host. The application must Set this bit
to instruct the core to exit the Suspend state. As specified in the
USB 2.0 specification, the application must clear this bit 1-15 ms
after setting it.
If LPM is enabled and the core is in the L1 (Sleep) state, when the
application sets this bit, the core initiates L1 remote signaling to
wake up the USB host. The application must set this bit to instruct
the core to exit the Sleep state. As specified in the LPM
specification, the hardware automatically clears this bit 50
microseconds (TL1DevDrvResume) after being set by the
application. The application must not set this bit when GLPMCFG
bRemoteWake from the previous LPM transaction is zero.

If it will not help, please check power status of core while resuming: 
hibernated, in partial power down, etc.

Thanks,
Minas

> I will be very grateful >
> 
> diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c
> index 3146df6e6510..c64e573af7ca 100644
> --- a/drivers/usb/dwc2/gadget.c
> +++ b/drivers/usb/dwc2/gadget.c
> @@ -4683,6 +4683,52 @@ static int dwc2_hsotg_vbus_draw(struct usb_gadget *gadget, unsigned int mA)
>   	return usb_phy_set_power(hsotg->uphy, mA);
>   }
>   
> +/**
> + * dwc2_hsotg_wakeup - send wakeup signal to the host
> + * @gadget: The usb gadget state
> + *
> + * If the gadget is in device mode and in the L1 or L2 state,
> + * it sends a wakeup signal to the host.
> + */
> +static int dwc2_hsotg_wakeup(struct usb_gadget *gadget)
> +{
> +	struct dwc2_hsotg *hsotg = to_hsotg(gadget);
> +	int ret = -1;
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&hsotg->lock, flags);
> +
> +	if (!hsotg->remote_wakeup_allowed) {
> +		dev_dbg(hsotg->dev,
> +			"wakeup signalling skipped: is not allowed by host\n");
> +		goto skip;
> +	}
> +	if (hsotg->lx_state != DWC2_L1 && hsotg->lx_state != DWC2_L2) {
> +		dev_dbg(hsotg->dev,
> +			"wakeup signalling skipped: gadget not in L1/L2 state\n");
> +		goto skip;
> +	}
> +	if (!dwc2_is_device_mode(hsotg)) {
> +		dev_dbg(hsotg->dev,
> +			"wakeup signalling skipped: gadget not in device mode\n");
> +		goto skip;
> +	}
> +
> +	dev_dbg(hsotg->dev, "sending wakeup signal to the host");
> +
> +	dwc2_set_bit(hsotg, DCTL, DCTL_RMTWKUPSIG);
> +	mdelay(10);
> +	dwc2_clear_bit(hsotg, DCTL, DCTL_RMTWKUPSIG);
> +
> +	/* After the signalling, the USB core wakes up to L0 */
> +	hsotg->lx_state = DWC2_L0;
> +
> +	ret = 0;
> +skip:
> +	spin_unlock_irqrestore(&hsotg->lock, flags);
> +	return ret;
> +}
> +
>   static const struct usb_gadget_ops dwc2_hsotg_gadget_ops = {
>   	.get_frame	= dwc2_hsotg_gadget_getframe,
>   	.set_selfpowered	= dwc2_hsotg_set_selfpowered,
> @@ -4691,6 +4737,7 @@ static const struct usb_gadget_ops dwc2_hsotg_gadget_ops = {
>   	.pullup                 = dwc2_hsotg_pullup,
>   	.vbus_session		= dwc2_hsotg_vbus_session,
>   	.vbus_draw		= dwc2_hsotg_vbus_draw,
> +	.wakeup			= dwc2_hsotg_wakeup,
>   };
>   
>   /**
> 
> 





[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux