Loading drivers/usb/dwc3/core.c +12 −1 Original line number Diff line number Diff line Loading @@ -1853,8 +1853,18 @@ static int dwc3_resume(struct device *dev) int ret; /* Check if platform glue driver handling PM, if not then handle here */ if (!dwc3_notify_event(dwc, DWC3_CORE_PM_RESUME_EVENT, 0)) if (!dwc3_notify_event(dwc, DWC3_CORE_PM_RESUME_EVENT, 0)) { /* * If the core was in host mode during suspend, then set the * runtime PM state as active to reflect actual state of device * which is now out of LPM. This allows runtime_suspend later. */ if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_HOST && dwc->host_poweroff_in_pm_suspend) goto runtime_set_active; return 0; } pinctrl_pm_select_default_state(dev); Loading @@ -1862,6 +1872,7 @@ static int dwc3_resume(struct device *dev) if (ret) return ret; runtime_set_active: pm_runtime_disable(dev); pm_runtime_set_active(dev); pm_runtime_enable(dev); Loading drivers/usb/dwc3/core.h +6 −0 Original line number Diff line number Diff line Loading @@ -1334,6 +1334,12 @@ struct dwc3 { unsigned int vbus_active:1; /* Indicate if software connect was issued by the usb_gadget_driver */ unsigned int softconnect:1; /* * If true, PM suspend allowed irrespective of host runtimePM state * and core will power collapse. This also leads to reset-resume of * connected devices on PM resume. */ bool host_poweroff_in_pm_suspend; }; #define INCRX_BURST_MODE 0 Loading drivers/usb/dwc3/debug.h +4 −0 Original line number Diff line number Diff line Loading @@ -35,6 +35,10 @@ #define dbg_setup(ep_num, req) \ dwc3_dbg_setup(dwc, ep_num, req) #define dbg_log_string(fmt, ...) \ ipc_log_string(dwc->dwc_ipc_log_ctxt,\ "%s: " fmt, __func__, ##__VA_ARGS__) /** * dwc3_gadget_ep_cmd_string - returns endpoint command string * @cmd: command code Loading drivers/usb/dwc3/dwc3-msm.c +130 −44 Original line number Diff line number Diff line Loading @@ -173,6 +173,13 @@ static const struct usb_irq usb_irq_info[USB_MAX_IRQ] = { {"ss_phy_irq", 0}, }; static const char * const gsi_op_strings[] = { "EP_CONFIG", "START_XFER", "STORE_DBL_INFO", "ENABLE_GSI", "UPDATE_XFER", "RING_DB", "END_XFER", "GET_CH_INFO", "PREPARE_TRBS", "FREE_TRBS", "SET_CLR_BLOCK_DBL", "CHECK_FOR_SUSP", "EP_DISABLE" }; struct dwc3_msm; struct extcon_nb { Loading Loading @@ -230,6 +237,7 @@ struct dwc3_msm { struct work_struct restart_usb_work; bool in_restart; struct workqueue_struct *dwc3_wq; struct workqueue_struct *sm_usb_wq; struct delayed_work sm_work; unsigned long inputs; unsigned int max_power; Loading Loading @@ -1368,6 +1376,13 @@ static bool gsi_check_ready_to_suspend(struct usb_ep *ep, bool f_suspend) return true; } static inline const char *gsi_op_to_string(unsigned int op) { if (op < ARRAY_SIZE(gsi_op_strings)) return gsi_op_strings[op]; return "Invalid"; } /** * Performs GSI operations or GSI EP related operations. Loading @@ -1391,41 +1406,36 @@ static int dwc3_msm_gsi_ep_op(struct usb_ep *ep, bool block_db, f_suspend; unsigned long flags; dbg_log_string("%s(%d):%s", ep->name, ep->ep_num, gsi_op_to_string(op)); switch (op) { case GSI_EP_OP_PREPARE_TRBS: request = (struct usb_gsi_request *)op_data; dev_dbg(mdwc->dev, "EP_OP_PREPARE_TRBS for %s\n", ep->name); ret = gsi_prepare_trbs(ep, request); break; case GSI_EP_OP_FREE_TRBS: dev_dbg(mdwc->dev, "EP_OP_FREE_TRBS for %s\n", ep->name); request = (struct usb_gsi_request *)op_data; gsi_free_trbs(ep, request); break; case GSI_EP_OP_CONFIG: request = (struct usb_gsi_request *)op_data; dev_dbg(mdwc->dev, "EP_OP_CONFIG for %s\n", ep->name); spin_lock_irqsave(&dwc->lock, flags); gsi_configure_ep(ep, request); spin_unlock_irqrestore(&dwc->lock, flags); break; case GSI_EP_OP_STARTXFER: dev_dbg(mdwc->dev, "EP_OP_STARTXFER for %s\n", ep->name); spin_lock_irqsave(&dwc->lock, flags); ret = gsi_startxfer_for_ep(ep); spin_unlock_irqrestore(&dwc->lock, flags); break; case GSI_EP_OP_GET_XFER_IDX: dev_dbg(mdwc->dev, "EP_OP_GET_XFER_IDX for %s\n", ep->name); ret = gsi_get_xfer_index(ep); break; case GSI_EP_OP_STORE_DBL_INFO: dev_dbg(mdwc->dev, "EP_OP_STORE_DBL_INFO\n"); request = (struct usb_gsi_request *)op_data; gsi_store_ringbase_dbl_info(ep, request); break; case GSI_EP_OP_ENABLE_GSI: dev_dbg(mdwc->dev, "EP_OP_ENABLE_GSI\n"); gsi_enable(ep); break; case GSI_EP_OP_GET_CH_INFO: Loading @@ -1434,36 +1444,29 @@ static int dwc3_msm_gsi_ep_op(struct usb_ep *ep, break; case GSI_EP_OP_RING_DB: request = (struct usb_gsi_request *)op_data; dbg_print(0xFF, "RING_DB", 0, ep->name); gsi_ring_db(ep, request); break; case GSI_EP_OP_UPDATEXFER: request = (struct usb_gsi_request *)op_data; dev_dbg(mdwc->dev, "EP_OP_UPDATEXFER\n"); spin_lock_irqsave(&dwc->lock, flags); ret = gsi_updatexfer_for_ep(ep, request); spin_unlock_irqrestore(&dwc->lock, flags); break; case GSI_EP_OP_ENDXFER: request = (struct usb_gsi_request *)op_data; dev_dbg(mdwc->dev, "EP_OP_ENDXFER for %s\n", ep->name); spin_lock_irqsave(&dwc->lock, flags); gsi_endxfer_for_ep(ep); spin_unlock_irqrestore(&dwc->lock, flags); break; case GSI_EP_OP_SET_CLR_BLOCK_DBL: block_db = *((bool *)op_data); dev_dbg(mdwc->dev, "EP_OP_SET_CLR_BLOCK_DBL %d\n", block_db); gsi_set_clear_dbell(ep, block_db); break; case GSI_EP_OP_CHECK_FOR_SUSPEND: dev_dbg(mdwc->dev, "EP_OP_CHECK_FOR_SUSPEND\n"); f_suspend = *((bool *)op_data); ret = gsi_check_ready_to_suspend(ep, f_suspend); break; case GSI_EP_OP_DISABLE: dev_dbg(mdwc->dev, "EP_OP_DISABLE\n"); ret = ep->ops->disable(ep); break; default: Loading Loading @@ -1695,7 +1698,7 @@ static int msm_dwc3_usbdev_notify(struct notifier_block *self, } mdwc->hc_died = true; schedule_delayed_work(&mdwc->sm_work, 0); queue_delayed_work(mdwc->sm_usb_wq, &mdwc->sm_work, 0); return 0; } Loading Loading @@ -2056,15 +2059,34 @@ static void dwc3_msm_power_collapse_por(struct dwc3_msm *mdwc) if (ret) dev_err(mdwc->dev, "%s: dwc3_core init failed (%d)\n", __func__, ret); /* Get initial P3 status and enable IN_P3 event */ if (dwc3_is_usb31(dwc)) val = dwc3_msm_read_reg_field(mdwc->base, DWC31_LINK_GDBGLTSSM, DWC3_GDBGLTSSM_LINKSTATE_MASK); else val = dwc3_msm_read_reg_field(mdwc->base, DWC3_GDBGLTSSM, DWC3_GDBGLTSSM_LINKSTATE_MASK); atomic_set(&mdwc->in_p3, val == DWC3_LINK_STATE_U3); dwc3_msm_write_reg_field(mdwc->base, PWR_EVNT_IRQ_MASK_REG, PWR_EVNT_POWERDOWN_IN_P3_MASK, 1); /* Set the core in host mode if it was in host mode during pm_suspend */ if (mdwc->in_host_mode) { dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST); dwc3_en_sleep_mode(dwc); } } static int dwc3_msm_prepare_suspend(struct dwc3_msm *mdwc) static int dwc3_msm_prepare_suspend(struct dwc3_msm *mdwc, bool ignore_p3_state) { unsigned long timeout; u32 reg = 0; if ((mdwc->in_host_mode || mdwc->in_device_mode) && dwc3_msm_is_superspeed(mdwc) && !mdwc->in_restart) { if (!ignore_p3_state && ((mdwc->in_host_mode || mdwc->in_device_mode) && dwc3_msm_is_superspeed(mdwc) && !mdwc->in_restart)) { if (!atomic_read(&mdwc->in_p3)) { dev_err(mdwc->dev, "Not in P3,aborting LPM sequence\n"); return -EBUSY; Loading Loading @@ -2263,7 +2285,7 @@ static int dwc3_msm_update_bus_bw(struct dwc3_msm *mdwc, enum bus_vote bv) return ret; } static int dwc3_msm_suspend(struct dwc3_msm *mdwc) static int dwc3_msm_suspend(struct dwc3_msm *mdwc, bool force_power_collapse) { int ret; struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); Loading Loading @@ -2325,7 +2347,7 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc) return -EBUSY; } ret = dwc3_msm_prepare_suspend(mdwc); ret = dwc3_msm_prepare_suspend(mdwc, force_power_collapse); if (ret) { mutex_unlock(&mdwc->suspend_resume_mutex); return ret; Loading Loading @@ -2403,8 +2425,8 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc) clk_disable_unprepare(mdwc->xo_clk); /* Perform controller power collapse */ if (!mdwc->in_host_mode && (!mdwc->in_device_mode || mdwc->in_restart)) { if (!(mdwc->in_host_mode || mdwc->in_device_mode) || mdwc->in_restart || force_power_collapse) { mdwc->lpm_flags |= MDWC3_POWER_COLLAPSE; dev_dbg(mdwc->dev, "%s: power collapse\n", __func__); dwc3_msm_config_gdsc(mdwc, 0); Loading Loading @@ -2564,8 +2586,6 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc) /* Recover from controller power collapse */ if (mdwc->lpm_flags & MDWC3_POWER_COLLAPSE) { u32 tmp; if (mdwc->iommu_map) { ret = __depr_arm_iommu_attach_device(mdwc->dev, mdwc->iommu_map); Loading @@ -2580,18 +2600,6 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc) dwc3_msm_power_collapse_por(mdwc); /* Get initial P3 status and enable IN_P3 event */ if (dwc3_is_usb31(dwc)) tmp = dwc3_msm_read_reg_field(mdwc->base, DWC31_LINK_GDBGLTSSM, DWC3_GDBGLTSSM_LINKSTATE_MASK); else tmp = dwc3_msm_read_reg_field(mdwc->base, DWC3_GDBGLTSSM, DWC3_GDBGLTSSM_LINKSTATE_MASK); atomic_set(&mdwc->in_p3, tmp == DWC3_LINK_STATE_U3); dwc3_msm_write_reg_field(mdwc->base, PWR_EVNT_IRQ_MASK_REG, PWR_EVNT_POWERDOWN_IN_P3_MASK, 1); mdwc->lpm_flags &= ~MDWC3_POWER_COLLAPSE; } Loading Loading @@ -2674,7 +2682,7 @@ static void dwc3_ext_event_notify(struct dwc3_msm *mdwc) clear_bit(B_SUSPEND, &mdwc->inputs); } schedule_delayed_work(&mdwc->sm_work, 0); queue_delayed_work(mdwc->sm_usb_wq, &mdwc->sm_work, 0); } static void dwc3_resume_work(struct work_struct *w) Loading Loading @@ -2727,6 +2735,13 @@ static void dwc3_resume_work(struct work_struct *w) ORIENTATION_CC2 : ORIENTATION_CC1; dbg_event(0xFF, "cc_state", mdwc->typec_orientation); ret = extcon_get_property(edev, extcon_id, EXTCON_PROP_USB_TYPEC_MED_HIGH_CURRENT, &val); if (!ret) dwc->gadget.is_selfpowered = val.intval; else dwc->gadget.is_selfpowered = 0; } /* Loading Loading @@ -3372,6 +3387,18 @@ static int dwc3_msm_probe(struct platform_device *pdev) return -ENOMEM; } /* * Create freezable workqueue for sm_work so that it gets scheduled only * after pm_resume has happened completely. This helps in avoiding race * conditions between xhci_plat_resume and xhci_runtime_resume; and also * between hcd disconnect and xhci_resume. */ mdwc->sm_usb_wq = create_freezable_workqueue("k_sm_usb"); if (!mdwc->sm_usb_wq) { destroy_workqueue(mdwc->dwc3_wq); return -ENOMEM; } /* Get all clks and gdsc reference */ ret = dwc3_msm_get_clk_gdsc(mdwc); if (ret) { Loading Loading @@ -3623,6 +3650,12 @@ static int dwc3_msm_probe(struct platform_device *pdev) mdwc->pm_qos_latency = 0; } if (of_property_read_bool(node, "qcom,host-poweroff-in-pm-suspend")) { dwc->host_poweroff_in_pm_suspend = true; dev_dbg(mdwc->dev, "%s: Core power collapse on host PM suspend\n", __func__); } mutex_init(&mdwc->suspend_resume_mutex); if (of_property_read_bool(node, "extcon")) { Loading Loading @@ -3661,6 +3694,7 @@ static int dwc3_msm_probe(struct platform_device *pdev) } of_platform_depopulate(&pdev->dev); err: destroy_workqueue(mdwc->sm_usb_wq); destroy_workqueue(mdwc->dwc3_wq); return ret; } Loading Loading @@ -3741,6 +3775,9 @@ static int dwc3_msm_remove(struct platform_device *pdev) __depr_arm_iommu_release_mapping(mdwc->iommu_map); } destroy_workqueue(mdwc->sm_usb_wq); destroy_workqueue(mdwc->dwc3_wq); return 0; } Loading Loading @@ -4372,7 +4409,7 @@ static void dwc3_otg_sm_work(struct work_struct *w) } if (work) schedule_delayed_work(&mdwc->sm_work, delay); queue_delayed_work(mdwc->sm_usb_wq, &mdwc->sm_work, delay); ret: return; Loading @@ -4381,6 +4418,7 @@ static void dwc3_otg_sm_work(struct work_struct *w) #ifdef CONFIG_PM_SLEEP static int dwc3_msm_pm_suspend(struct device *dev) { int ret = 0; struct dwc3_msm *mdwc = dev_get_drvdata(dev); struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); Loading @@ -4388,6 +4426,12 @@ static int dwc3_msm_pm_suspend(struct device *dev) dbg_event(0xFF, "PM Sus", 0); flush_workqueue(mdwc->dwc3_wq); /* * Check if pm_suspend can proceed irrespective of runtimePM state of * host. */ if (!dwc->host_poweroff_in_pm_suspend || !mdwc->in_host_mode) { if (!atomic_read(&dwc->in_lpm)) { dev_err(mdwc->dev, "Abort PM suspend!! (USB is outside LPM)\n"); return -EBUSY; Loading @@ -4398,6 +4442,26 @@ static int dwc3_msm_pm_suspend(struct device *dev) return 0; } /* * PHYs also need to be power collapsed, so call notify_disconnect * before suspend to ensure it. */ usb_phy_notify_disconnect(mdwc->hs_phy, USB_SPEED_HIGH); mdwc->hs_phy->flags &= ~PHY_HOST_MODE; usb_phy_notify_disconnect(mdwc->ss_phy, USB_SPEED_SUPER); mdwc->ss_phy->flags &= ~PHY_HOST_MODE; /* * Power collapse the core. Hence call dwc3_msm_suspend with * 'force_power_collapse' set to 'true'. */ ret = dwc3_msm_suspend(mdwc, true); if (!ret) atomic_set(&mdwc->pm_suspended, 1); return ret; } static int dwc3_msm_pm_resume(struct device *dev) { struct dwc3_msm *mdwc = dev_get_drvdata(dev); Loading @@ -4410,6 +4474,28 @@ static int dwc3_msm_pm_resume(struct device *dev) flush_workqueue(mdwc->dwc3_wq); atomic_set(&mdwc->pm_suspended, 0); if (!dwc->host_poweroff_in_pm_suspend || !mdwc->in_host_mode) { /* kick in otg state machine */ queue_work(mdwc->dwc3_wq, &mdwc->resume_work); return 0; } /* Resume dwc to avoid unclocked access by xhci_plat_resume */ dwc3_msm_resume(mdwc); pm_runtime_disable(dev); pm_runtime_set_active(dev); pm_runtime_enable(dev); /* Restore PHY flags if hibernated in host mode */ mdwc->hs_phy->flags |= PHY_HOST_MODE; usb_phy_notify_connect(mdwc->hs_phy, USB_SPEED_HIGH); if (dwc->maximum_speed >= USB_SPEED_SUPER) { mdwc->ss_phy->flags |= PHY_HOST_MODE; usb_phy_notify_connect(mdwc->ss_phy, USB_SPEED_SUPER); } /* kick in otg state machine */ queue_work(mdwc->dwc3_wq, &mdwc->resume_work); Loading Loading @@ -4437,7 +4523,7 @@ static int dwc3_msm_runtime_suspend(struct device *dev) dev_dbg(dev, "DWC3-msm runtime suspend\n"); dbg_event(0xFF, "RT Sus", 0); return dwc3_msm_suspend(mdwc); return dwc3_msm_suspend(mdwc, false); } static int dwc3_msm_runtime_resume(struct device *dev) Loading drivers/usb/dwc3/gadget.c +6 −0 Original line number Diff line number Diff line Loading @@ -824,6 +824,7 @@ static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep) { struct dwc3_request *req; dbg_log_string("START for %s(%d)", dep->name, dep->number); dwc3_stop_active_transfer(dwc, dep->number, true); /* - giveback all requests to gadget driver */ Loading @@ -838,12 +839,14 @@ static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep) dwc3_gadget_giveback(dep, req, -ESHUTDOWN); } dbg_log_string("DONE for %s(%d)", dep->name, dep->number); } static void dwc3_stop_active_transfers(struct dwc3 *dwc) { u32 epnum; dbg_log_string("START"); for (epnum = 2; epnum < DWC3_ENDPOINTS_NUM; epnum++) { struct dwc3_ep *dep; Loading @@ -860,6 +863,7 @@ static void dwc3_stop_active_transfers(struct dwc3 *dwc) dwc3_remove_requests(dwc, dep); } dbg_log_string("DONE"); } /** Loading Loading @@ -3073,6 +3077,8 @@ void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force) dep->flags |= DWC3_EP_END_TRANSFER_PENDING; udelay(100); } dbg_log_string("%s(%d): endxfer ret:%d)", dep->name, dep->number, ret); } static void dwc3_clear_stall_all_ep(struct dwc3 *dwc) Loading Loading
drivers/usb/dwc3/core.c +12 −1 Original line number Diff line number Diff line Loading @@ -1853,8 +1853,18 @@ static int dwc3_resume(struct device *dev) int ret; /* Check if platform glue driver handling PM, if not then handle here */ if (!dwc3_notify_event(dwc, DWC3_CORE_PM_RESUME_EVENT, 0)) if (!dwc3_notify_event(dwc, DWC3_CORE_PM_RESUME_EVENT, 0)) { /* * If the core was in host mode during suspend, then set the * runtime PM state as active to reflect actual state of device * which is now out of LPM. This allows runtime_suspend later. */ if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_HOST && dwc->host_poweroff_in_pm_suspend) goto runtime_set_active; return 0; } pinctrl_pm_select_default_state(dev); Loading @@ -1862,6 +1872,7 @@ static int dwc3_resume(struct device *dev) if (ret) return ret; runtime_set_active: pm_runtime_disable(dev); pm_runtime_set_active(dev); pm_runtime_enable(dev); Loading
drivers/usb/dwc3/core.h +6 −0 Original line number Diff line number Diff line Loading @@ -1334,6 +1334,12 @@ struct dwc3 { unsigned int vbus_active:1; /* Indicate if software connect was issued by the usb_gadget_driver */ unsigned int softconnect:1; /* * If true, PM suspend allowed irrespective of host runtimePM state * and core will power collapse. This also leads to reset-resume of * connected devices on PM resume. */ bool host_poweroff_in_pm_suspend; }; #define INCRX_BURST_MODE 0 Loading
drivers/usb/dwc3/debug.h +4 −0 Original line number Diff line number Diff line Loading @@ -35,6 +35,10 @@ #define dbg_setup(ep_num, req) \ dwc3_dbg_setup(dwc, ep_num, req) #define dbg_log_string(fmt, ...) \ ipc_log_string(dwc->dwc_ipc_log_ctxt,\ "%s: " fmt, __func__, ##__VA_ARGS__) /** * dwc3_gadget_ep_cmd_string - returns endpoint command string * @cmd: command code Loading
drivers/usb/dwc3/dwc3-msm.c +130 −44 Original line number Diff line number Diff line Loading @@ -173,6 +173,13 @@ static const struct usb_irq usb_irq_info[USB_MAX_IRQ] = { {"ss_phy_irq", 0}, }; static const char * const gsi_op_strings[] = { "EP_CONFIG", "START_XFER", "STORE_DBL_INFO", "ENABLE_GSI", "UPDATE_XFER", "RING_DB", "END_XFER", "GET_CH_INFO", "PREPARE_TRBS", "FREE_TRBS", "SET_CLR_BLOCK_DBL", "CHECK_FOR_SUSP", "EP_DISABLE" }; struct dwc3_msm; struct extcon_nb { Loading Loading @@ -230,6 +237,7 @@ struct dwc3_msm { struct work_struct restart_usb_work; bool in_restart; struct workqueue_struct *dwc3_wq; struct workqueue_struct *sm_usb_wq; struct delayed_work sm_work; unsigned long inputs; unsigned int max_power; Loading Loading @@ -1368,6 +1376,13 @@ static bool gsi_check_ready_to_suspend(struct usb_ep *ep, bool f_suspend) return true; } static inline const char *gsi_op_to_string(unsigned int op) { if (op < ARRAY_SIZE(gsi_op_strings)) return gsi_op_strings[op]; return "Invalid"; } /** * Performs GSI operations or GSI EP related operations. Loading @@ -1391,41 +1406,36 @@ static int dwc3_msm_gsi_ep_op(struct usb_ep *ep, bool block_db, f_suspend; unsigned long flags; dbg_log_string("%s(%d):%s", ep->name, ep->ep_num, gsi_op_to_string(op)); switch (op) { case GSI_EP_OP_PREPARE_TRBS: request = (struct usb_gsi_request *)op_data; dev_dbg(mdwc->dev, "EP_OP_PREPARE_TRBS for %s\n", ep->name); ret = gsi_prepare_trbs(ep, request); break; case GSI_EP_OP_FREE_TRBS: dev_dbg(mdwc->dev, "EP_OP_FREE_TRBS for %s\n", ep->name); request = (struct usb_gsi_request *)op_data; gsi_free_trbs(ep, request); break; case GSI_EP_OP_CONFIG: request = (struct usb_gsi_request *)op_data; dev_dbg(mdwc->dev, "EP_OP_CONFIG for %s\n", ep->name); spin_lock_irqsave(&dwc->lock, flags); gsi_configure_ep(ep, request); spin_unlock_irqrestore(&dwc->lock, flags); break; case GSI_EP_OP_STARTXFER: dev_dbg(mdwc->dev, "EP_OP_STARTXFER for %s\n", ep->name); spin_lock_irqsave(&dwc->lock, flags); ret = gsi_startxfer_for_ep(ep); spin_unlock_irqrestore(&dwc->lock, flags); break; case GSI_EP_OP_GET_XFER_IDX: dev_dbg(mdwc->dev, "EP_OP_GET_XFER_IDX for %s\n", ep->name); ret = gsi_get_xfer_index(ep); break; case GSI_EP_OP_STORE_DBL_INFO: dev_dbg(mdwc->dev, "EP_OP_STORE_DBL_INFO\n"); request = (struct usb_gsi_request *)op_data; gsi_store_ringbase_dbl_info(ep, request); break; case GSI_EP_OP_ENABLE_GSI: dev_dbg(mdwc->dev, "EP_OP_ENABLE_GSI\n"); gsi_enable(ep); break; case GSI_EP_OP_GET_CH_INFO: Loading @@ -1434,36 +1444,29 @@ static int dwc3_msm_gsi_ep_op(struct usb_ep *ep, break; case GSI_EP_OP_RING_DB: request = (struct usb_gsi_request *)op_data; dbg_print(0xFF, "RING_DB", 0, ep->name); gsi_ring_db(ep, request); break; case GSI_EP_OP_UPDATEXFER: request = (struct usb_gsi_request *)op_data; dev_dbg(mdwc->dev, "EP_OP_UPDATEXFER\n"); spin_lock_irqsave(&dwc->lock, flags); ret = gsi_updatexfer_for_ep(ep, request); spin_unlock_irqrestore(&dwc->lock, flags); break; case GSI_EP_OP_ENDXFER: request = (struct usb_gsi_request *)op_data; dev_dbg(mdwc->dev, "EP_OP_ENDXFER for %s\n", ep->name); spin_lock_irqsave(&dwc->lock, flags); gsi_endxfer_for_ep(ep); spin_unlock_irqrestore(&dwc->lock, flags); break; case GSI_EP_OP_SET_CLR_BLOCK_DBL: block_db = *((bool *)op_data); dev_dbg(mdwc->dev, "EP_OP_SET_CLR_BLOCK_DBL %d\n", block_db); gsi_set_clear_dbell(ep, block_db); break; case GSI_EP_OP_CHECK_FOR_SUSPEND: dev_dbg(mdwc->dev, "EP_OP_CHECK_FOR_SUSPEND\n"); f_suspend = *((bool *)op_data); ret = gsi_check_ready_to_suspend(ep, f_suspend); break; case GSI_EP_OP_DISABLE: dev_dbg(mdwc->dev, "EP_OP_DISABLE\n"); ret = ep->ops->disable(ep); break; default: Loading Loading @@ -1695,7 +1698,7 @@ static int msm_dwc3_usbdev_notify(struct notifier_block *self, } mdwc->hc_died = true; schedule_delayed_work(&mdwc->sm_work, 0); queue_delayed_work(mdwc->sm_usb_wq, &mdwc->sm_work, 0); return 0; } Loading Loading @@ -2056,15 +2059,34 @@ static void dwc3_msm_power_collapse_por(struct dwc3_msm *mdwc) if (ret) dev_err(mdwc->dev, "%s: dwc3_core init failed (%d)\n", __func__, ret); /* Get initial P3 status and enable IN_P3 event */ if (dwc3_is_usb31(dwc)) val = dwc3_msm_read_reg_field(mdwc->base, DWC31_LINK_GDBGLTSSM, DWC3_GDBGLTSSM_LINKSTATE_MASK); else val = dwc3_msm_read_reg_field(mdwc->base, DWC3_GDBGLTSSM, DWC3_GDBGLTSSM_LINKSTATE_MASK); atomic_set(&mdwc->in_p3, val == DWC3_LINK_STATE_U3); dwc3_msm_write_reg_field(mdwc->base, PWR_EVNT_IRQ_MASK_REG, PWR_EVNT_POWERDOWN_IN_P3_MASK, 1); /* Set the core in host mode if it was in host mode during pm_suspend */ if (mdwc->in_host_mode) { dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST); dwc3_en_sleep_mode(dwc); } } static int dwc3_msm_prepare_suspend(struct dwc3_msm *mdwc) static int dwc3_msm_prepare_suspend(struct dwc3_msm *mdwc, bool ignore_p3_state) { unsigned long timeout; u32 reg = 0; if ((mdwc->in_host_mode || mdwc->in_device_mode) && dwc3_msm_is_superspeed(mdwc) && !mdwc->in_restart) { if (!ignore_p3_state && ((mdwc->in_host_mode || mdwc->in_device_mode) && dwc3_msm_is_superspeed(mdwc) && !mdwc->in_restart)) { if (!atomic_read(&mdwc->in_p3)) { dev_err(mdwc->dev, "Not in P3,aborting LPM sequence\n"); return -EBUSY; Loading Loading @@ -2263,7 +2285,7 @@ static int dwc3_msm_update_bus_bw(struct dwc3_msm *mdwc, enum bus_vote bv) return ret; } static int dwc3_msm_suspend(struct dwc3_msm *mdwc) static int dwc3_msm_suspend(struct dwc3_msm *mdwc, bool force_power_collapse) { int ret; struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); Loading Loading @@ -2325,7 +2347,7 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc) return -EBUSY; } ret = dwc3_msm_prepare_suspend(mdwc); ret = dwc3_msm_prepare_suspend(mdwc, force_power_collapse); if (ret) { mutex_unlock(&mdwc->suspend_resume_mutex); return ret; Loading Loading @@ -2403,8 +2425,8 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc) clk_disable_unprepare(mdwc->xo_clk); /* Perform controller power collapse */ if (!mdwc->in_host_mode && (!mdwc->in_device_mode || mdwc->in_restart)) { if (!(mdwc->in_host_mode || mdwc->in_device_mode) || mdwc->in_restart || force_power_collapse) { mdwc->lpm_flags |= MDWC3_POWER_COLLAPSE; dev_dbg(mdwc->dev, "%s: power collapse\n", __func__); dwc3_msm_config_gdsc(mdwc, 0); Loading Loading @@ -2564,8 +2586,6 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc) /* Recover from controller power collapse */ if (mdwc->lpm_flags & MDWC3_POWER_COLLAPSE) { u32 tmp; if (mdwc->iommu_map) { ret = __depr_arm_iommu_attach_device(mdwc->dev, mdwc->iommu_map); Loading @@ -2580,18 +2600,6 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc) dwc3_msm_power_collapse_por(mdwc); /* Get initial P3 status and enable IN_P3 event */ if (dwc3_is_usb31(dwc)) tmp = dwc3_msm_read_reg_field(mdwc->base, DWC31_LINK_GDBGLTSSM, DWC3_GDBGLTSSM_LINKSTATE_MASK); else tmp = dwc3_msm_read_reg_field(mdwc->base, DWC3_GDBGLTSSM, DWC3_GDBGLTSSM_LINKSTATE_MASK); atomic_set(&mdwc->in_p3, tmp == DWC3_LINK_STATE_U3); dwc3_msm_write_reg_field(mdwc->base, PWR_EVNT_IRQ_MASK_REG, PWR_EVNT_POWERDOWN_IN_P3_MASK, 1); mdwc->lpm_flags &= ~MDWC3_POWER_COLLAPSE; } Loading Loading @@ -2674,7 +2682,7 @@ static void dwc3_ext_event_notify(struct dwc3_msm *mdwc) clear_bit(B_SUSPEND, &mdwc->inputs); } schedule_delayed_work(&mdwc->sm_work, 0); queue_delayed_work(mdwc->sm_usb_wq, &mdwc->sm_work, 0); } static void dwc3_resume_work(struct work_struct *w) Loading Loading @@ -2727,6 +2735,13 @@ static void dwc3_resume_work(struct work_struct *w) ORIENTATION_CC2 : ORIENTATION_CC1; dbg_event(0xFF, "cc_state", mdwc->typec_orientation); ret = extcon_get_property(edev, extcon_id, EXTCON_PROP_USB_TYPEC_MED_HIGH_CURRENT, &val); if (!ret) dwc->gadget.is_selfpowered = val.intval; else dwc->gadget.is_selfpowered = 0; } /* Loading Loading @@ -3372,6 +3387,18 @@ static int dwc3_msm_probe(struct platform_device *pdev) return -ENOMEM; } /* * Create freezable workqueue for sm_work so that it gets scheduled only * after pm_resume has happened completely. This helps in avoiding race * conditions between xhci_plat_resume and xhci_runtime_resume; and also * between hcd disconnect and xhci_resume. */ mdwc->sm_usb_wq = create_freezable_workqueue("k_sm_usb"); if (!mdwc->sm_usb_wq) { destroy_workqueue(mdwc->dwc3_wq); return -ENOMEM; } /* Get all clks and gdsc reference */ ret = dwc3_msm_get_clk_gdsc(mdwc); if (ret) { Loading Loading @@ -3623,6 +3650,12 @@ static int dwc3_msm_probe(struct platform_device *pdev) mdwc->pm_qos_latency = 0; } if (of_property_read_bool(node, "qcom,host-poweroff-in-pm-suspend")) { dwc->host_poweroff_in_pm_suspend = true; dev_dbg(mdwc->dev, "%s: Core power collapse on host PM suspend\n", __func__); } mutex_init(&mdwc->suspend_resume_mutex); if (of_property_read_bool(node, "extcon")) { Loading Loading @@ -3661,6 +3694,7 @@ static int dwc3_msm_probe(struct platform_device *pdev) } of_platform_depopulate(&pdev->dev); err: destroy_workqueue(mdwc->sm_usb_wq); destroy_workqueue(mdwc->dwc3_wq); return ret; } Loading Loading @@ -3741,6 +3775,9 @@ static int dwc3_msm_remove(struct platform_device *pdev) __depr_arm_iommu_release_mapping(mdwc->iommu_map); } destroy_workqueue(mdwc->sm_usb_wq); destroy_workqueue(mdwc->dwc3_wq); return 0; } Loading Loading @@ -4372,7 +4409,7 @@ static void dwc3_otg_sm_work(struct work_struct *w) } if (work) schedule_delayed_work(&mdwc->sm_work, delay); queue_delayed_work(mdwc->sm_usb_wq, &mdwc->sm_work, delay); ret: return; Loading @@ -4381,6 +4418,7 @@ static void dwc3_otg_sm_work(struct work_struct *w) #ifdef CONFIG_PM_SLEEP static int dwc3_msm_pm_suspend(struct device *dev) { int ret = 0; struct dwc3_msm *mdwc = dev_get_drvdata(dev); struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); Loading @@ -4388,6 +4426,12 @@ static int dwc3_msm_pm_suspend(struct device *dev) dbg_event(0xFF, "PM Sus", 0); flush_workqueue(mdwc->dwc3_wq); /* * Check if pm_suspend can proceed irrespective of runtimePM state of * host. */ if (!dwc->host_poweroff_in_pm_suspend || !mdwc->in_host_mode) { if (!atomic_read(&dwc->in_lpm)) { dev_err(mdwc->dev, "Abort PM suspend!! (USB is outside LPM)\n"); return -EBUSY; Loading @@ -4398,6 +4442,26 @@ static int dwc3_msm_pm_suspend(struct device *dev) return 0; } /* * PHYs also need to be power collapsed, so call notify_disconnect * before suspend to ensure it. */ usb_phy_notify_disconnect(mdwc->hs_phy, USB_SPEED_HIGH); mdwc->hs_phy->flags &= ~PHY_HOST_MODE; usb_phy_notify_disconnect(mdwc->ss_phy, USB_SPEED_SUPER); mdwc->ss_phy->flags &= ~PHY_HOST_MODE; /* * Power collapse the core. Hence call dwc3_msm_suspend with * 'force_power_collapse' set to 'true'. */ ret = dwc3_msm_suspend(mdwc, true); if (!ret) atomic_set(&mdwc->pm_suspended, 1); return ret; } static int dwc3_msm_pm_resume(struct device *dev) { struct dwc3_msm *mdwc = dev_get_drvdata(dev); Loading @@ -4410,6 +4474,28 @@ static int dwc3_msm_pm_resume(struct device *dev) flush_workqueue(mdwc->dwc3_wq); atomic_set(&mdwc->pm_suspended, 0); if (!dwc->host_poweroff_in_pm_suspend || !mdwc->in_host_mode) { /* kick in otg state machine */ queue_work(mdwc->dwc3_wq, &mdwc->resume_work); return 0; } /* Resume dwc to avoid unclocked access by xhci_plat_resume */ dwc3_msm_resume(mdwc); pm_runtime_disable(dev); pm_runtime_set_active(dev); pm_runtime_enable(dev); /* Restore PHY flags if hibernated in host mode */ mdwc->hs_phy->flags |= PHY_HOST_MODE; usb_phy_notify_connect(mdwc->hs_phy, USB_SPEED_HIGH); if (dwc->maximum_speed >= USB_SPEED_SUPER) { mdwc->ss_phy->flags |= PHY_HOST_MODE; usb_phy_notify_connect(mdwc->ss_phy, USB_SPEED_SUPER); } /* kick in otg state machine */ queue_work(mdwc->dwc3_wq, &mdwc->resume_work); Loading Loading @@ -4437,7 +4523,7 @@ static int dwc3_msm_runtime_suspend(struct device *dev) dev_dbg(dev, "DWC3-msm runtime suspend\n"); dbg_event(0xFF, "RT Sus", 0); return dwc3_msm_suspend(mdwc); return dwc3_msm_suspend(mdwc, false); } static int dwc3_msm_runtime_resume(struct device *dev) Loading
drivers/usb/dwc3/gadget.c +6 −0 Original line number Diff line number Diff line Loading @@ -824,6 +824,7 @@ static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep) { struct dwc3_request *req; dbg_log_string("START for %s(%d)", dep->name, dep->number); dwc3_stop_active_transfer(dwc, dep->number, true); /* - giveback all requests to gadget driver */ Loading @@ -838,12 +839,14 @@ static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep) dwc3_gadget_giveback(dep, req, -ESHUTDOWN); } dbg_log_string("DONE for %s(%d)", dep->name, dep->number); } static void dwc3_stop_active_transfers(struct dwc3 *dwc) { u32 epnum; dbg_log_string("START"); for (epnum = 2; epnum < DWC3_ENDPOINTS_NUM; epnum++) { struct dwc3_ep *dep; Loading @@ -860,6 +863,7 @@ static void dwc3_stop_active_transfers(struct dwc3 *dwc) dwc3_remove_requests(dwc, dep); } dbg_log_string("DONE"); } /** Loading Loading @@ -3073,6 +3077,8 @@ void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force) dep->flags |= DWC3_EP_END_TRANSFER_PENDING; udelay(100); } dbg_log_string("%s(%d): endxfer ret:%d)", dep->name, dep->number, ret); } static void dwc3_clear_stall_all_ep(struct dwc3 *dwc) Loading