From af88d5f829d013efda5f21c92b9985954fdfccdb Mon Sep 17 00:00:00 2001 From: Mayank Rana Date: Thu, 11 Jun 2020 14:19:22 -0700 Subject: [PATCH] dwc3: Add usb_get_remote_wakeup_status() API() USB composite device updates to host about its wakeup capability using bmAttribute, and USB host may support remote wakeup functionality using SET_FEATURE. UDC gadget ops supports wakeup() API which can be invoked by USB function driver to resume USB bus by signaling remote wakeup. With HW accelerated path IPA will need to know if host has enabled remote wakeup in order to decide whether to suspend or disconnect the GSI channels. Add an API to allow USB GSI driver to query the current remote wakeup enabled status. Change-Id: I09eb62714f9df90d68cce5c478dc19096477709e Signed-off-by: Mayank Rana --- drivers/usb/dwc3/core.h | 2 ++ drivers/usb/dwc3/dwc3-msm.c | 15 +++++++++++++++ drivers/usb/dwc3/ep0.c | 6 ++++++ drivers/usb/dwc3/gadget.c | 9 +++++++++ include/linux/usb/dwc3-msm.h | 3 +++ 5 files changed, 35 insertions(+) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 53b13d9e55fb..aec7ad30aebc 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -1150,6 +1150,7 @@ struct dwc3_scratchpad_array { * @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 + * @is_remote_wakeup_enabled: remote wakeup status from host perspective */ struct dwc3 { struct work_struct drd_work; @@ -1395,6 +1396,7 @@ struct dwc3 { u32 gen2_tx_de_emph2; u32 gen2_tx_de_emph3; ktime_t last_run_stop; + bool is_remote_wakeup_enabled; }; #define INCRX_BURST_MODE 0 diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index 893337090574..980eae30e933 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -1838,6 +1838,21 @@ int usb_gsi_ep_op(struct usb_ep *ep, void *op_data, enum gsi_ep_op op) } EXPORT_SYMBOL(usb_gsi_ep_op); +/* Return true if host is supporting remote wakeup functionality. */ +bool usb_get_remote_wakeup_status(struct usb_gadget *gadget) +{ + struct dwc3 *dwc = gadget_to_dwc(gadget); + unsigned long flags; + bool rw = false; + + spin_lock_irqsave(&dwc->lock, flags); + rw = dwc->is_remote_wakeup_enabled ? true : false; + spin_unlock_irqrestore(&dwc->lock, flags); + + return rw; +} +EXPORT_SYMBOL(usb_get_remote_wakeup_status); + /** * Configure a USB DBM ep to work in BAM mode. * diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 26dbbb9494db..bce34a0b6d0e 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -340,6 +340,9 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc, usb_status |= 1 << USB_DEV_STAT_U1_ENABLED; if (reg & DWC3_DCTL_INITU2ENA) usb_status |= 1 << USB_DEV_STAT_U2_ENABLED; + } else { + usb_status |= dwc->is_remote_wakeup_enabled << + USB_DEVICE_REMOTE_WAKEUP; } break; @@ -460,6 +463,9 @@ static int dwc3_ep0_handle_device(struct dwc3 *dwc, switch (wValue) { case USB_DEVICE_REMOTE_WAKEUP: + dbg_log_string("remote wakeup :%s", + (set ? "enabled" : "disabled")); + dwc->is_remote_wakeup_enabled = set; break; /* * 9.4.1 says only only for SS, in AddressState only for diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 33db59228a56..8db92f03d551 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1993,6 +1993,12 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g) int ret; spin_lock_irqsave(&dwc->lock, flags); + if (!dwc->is_remote_wakeup_enabled) { + spin_unlock_irqrestore(&dwc->lock, flags); + dbg_log_string("remote wakeup not supported\n"); + return -EINVAL; + } + ret = __dwc3_gadget_wakeup(dwc); spin_unlock_irqrestore(&dwc->lock, flags); @@ -2508,6 +2514,7 @@ static int dwc3_gadget_start(struct usb_gadget *g, } dwc->gadget_driver = driver; + dwc->is_remote_wakeup_enabled = false; /* * For DRD, this might get called by gadget driver during bootup @@ -2539,6 +2546,7 @@ static int dwc3_gadget_stop(struct usb_gadget *g) spin_lock_irqsave(&dwc->lock, flags); dwc->gadget_driver = NULL; + dwc->is_remote_wakeup_enabled = false; spin_unlock_irqrestore(&dwc->lock, flags); dbg_event(0xFF, "fwq_started", 0); @@ -3362,6 +3370,7 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) dwc->gadget.speed = USB_SPEED_UNKNOWN; dwc->link_state = DWC3_LINK_STATE_U0; + dwc->is_remote_wakeup_enabled = false; } static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) diff --git a/include/linux/usb/dwc3-msm.h b/include/linux/usb/dwc3-msm.h index 5cb818ce4809..6762da8c2c5f 100644 --- a/include/linux/usb/dwc3-msm.h +++ b/include/linux/usb/dwc3-msm.h @@ -136,6 +136,7 @@ int msm_data_fifo_config(struct usb_ep *ep, unsigned long addr, u32 size, bool msm_dwc3_reset_ep_after_lpm(struct usb_gadget *gadget); int msm_dwc3_reset_dbm_ep(struct usb_ep *ep); int dwc3_msm_release_ss_lane(struct device *dev); +bool usb_get_remote_wakeup_status(struct usb_gadget *gadget); #else static inline struct usb_ep *usb_ep_autoconfig_by_name( struct usb_gadget *gadget, struct usb_endpoint_descriptor *desc, @@ -163,6 +164,8 @@ static inline int msm_dwc3_reset_dbm_ep(struct usb_ep *ep) { return -ENODEV; } static inline int dwc3_msm_release_ss_lane(struct device *dev) { return -ENODEV; } +static bool __maybe_unused usb_get_remote_wakeup_status(struct usb_gadget *gadget) +{ return false; } #endif #endif /* __LINUX_USB_DWC3_MSM_H */