diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index 9db35699f77a..ada2be4e1891 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -150,6 +150,9 @@ #define DWC3_GEVNTADRHI_EVNTADRHI_GSI_IDX(n) (n << 16) #define DWC3_GEVENT_TYPE_GSI 0x3 +/* BAM pipe mask */ +#define MSM_PIPE_ID_MASK (0x1F) + enum dbm_reg { DBM_EP_CFG, DBM_DATA_FIFO, @@ -3738,6 +3741,63 @@ static void dwc3_init_dbm(struct dwc3_msm *mdwc) "qcom,reset-ep-after-lpm-resume"); } +static void dwc3_start_stop_host(struct dwc3_msm *mdwc, bool start) +{ + struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); + + if (start) { + dbg_log_string("start host mode"); + mdwc->id_state = DWC3_ID_GROUND; + mdwc->vbus_active = false; + } else { + dbg_log_string("stop_host_mode started"); + mdwc->id_state = DWC3_ID_FLOAT; + mdwc->vbus_active = false; + } + + dwc3_ext_event_notify(mdwc); + dbg_event(0xFF, "flush_work", 0); + flush_work(&mdwc->resume_work); + drain_workqueue(mdwc->sm_usb_wq); + if (start) + dbg_log_string("host mode started"); + else + dbg_log_string("stop_host_mode completed"); +} + +int dwc3_msm_release_ss_lane(struct device *dev) +{ + struct dwc3_msm *mdwc = dev_get_drvdata(dev); + struct dwc3 *dwc = NULL; + + if (mdwc == NULL) { + dev_err(dev, "dwc3-msm is not initialized yet.\n"); + return -EAGAIN; + } + + dwc = platform_get_drvdata(mdwc->dwc3); + if (dwc == NULL) { + dev_err(dev, "dwc3 controller is not initialized yet.\n"); + return -EAGAIN; + } + + dbg_event(0xFF, "ss_lane_release", 0); + if (mdwc->id_state != DWC3_ID_GROUND) { + dbg_log_string("USB host mode is not active"); + return 0; + } + + /* stop USB host mode */ + dwc3_start_stop_host(mdwc, false); + + /* restart USB host mode into high speed */ + dwc->maximum_speed = USB_SPEED_HIGH; + dwc3_start_stop_host(mdwc, true); + + return 0; +} +EXPORT_SYMBOL(dwc3_msm_release_ss_lane); + static int dwc3_msm_probe(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node, *dwc3_node; diff --git a/include/linux/usb/dwc3-msm.h b/include/linux/usb/dwc3-msm.h index b978cdbed655..9880477d70b1 100644 --- a/include/linux/usb/dwc3-msm.h +++ b/include/linux/usb/dwc3-msm.h @@ -22,7 +22,6 @@ * These bit fields are set by function drivers that wish to queue * usb_requests with sps/bam parameters. */ -#define MSM_PIPE_ID_MASK (0x1F) #define MSM_TX_PIPE_ID_OFS (16) #define MSM_SPS_MODE BIT(5) #define MSM_IS_FINITE_TRANSFER BIT(6) @@ -121,6 +120,7 @@ int msm_data_fifo_config(struct usb_ep *ep, unsigned long addr, u32 size, u8 dst_pipe_idx); 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); #else static inline struct usb_ep *usb_ep_autoconfig_by_name( struct usb_gadget *gadget, struct usb_endpoint_descriptor *desc, @@ -146,6 +146,8 @@ static inline bool msm_dwc3_reset_ep_after_lpm(struct usb_gadget *gadget) { return false; } 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; } #endif #endif /* __LINUX_USB_DWC3_MSM_H */