Loading Documentation/devicetree/bindings/usb/msm-ssusb.txt +3 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,9 @@ Optional properties : "hs_phy_irq" : Interrupt from HSPHY for asynchronous events in LPM. This is not used if wakeup events are received externally (e.g. PMIC) "pmic_id_irq" : Interrupt from PMIC for external ID pin notification. "pwr_event_irq" : Interrupt to controller for asynchronous events in LPM. Used for SS-USB power events. This is not used if wakeup events are received externally (e.g. PMIC) - qcom,otg-capability: If present then depend on PMIC for VBUS notifications, otherwise depend on PHY. - qcom,suspend_event_enable: If present then suspend interrupt event is enabled. Loading drivers/usb/dwc3/dwc3-msm.c +117 −3 Original line number Diff line number Diff line Loading @@ -113,6 +113,8 @@ MODULE_PARM_DESC(usb_lpm_override, "Override no_suspend_resume with USB"); #define PWR_EVNT_IRQ_MASK_REG (QSCRATCH_REG_OFFSET + 0x5C) #define HS_PHY_CTRL_COMMON_REG (QSCRATCH_REG_OFFSET + 0xEC) #define PWR_EVNT_LPM_OUT_L1_MASK BIT(13) /* TZ SCM parameters */ #define DWC3_MSM_RESTORE_SCM_CFG_CMD 0x2 struct dwc3_msm_scm_cmd_buf { Loading Loading @@ -210,6 +212,8 @@ struct dwc3_msm { unsigned int irq_to_affin; struct notifier_block dwc3_cpu_notifier; int pwr_event_irq; }; #define USB_HSPHY_3P3_VOL_MIN 3050000 /* uV */ Loading @@ -226,6 +230,8 @@ struct dwc3_msm { static struct usb_ext_notification *usb_ext; static void dwc3_pwr_event_handler(struct dwc3_msm *mdwc); /** * * Read register with debug info. Loading Loading @@ -1153,6 +1159,12 @@ static void dwc3_block_reset_usb_work(struct work_struct *w) reg |= DWC3_DEVTEN_SUSPEND; dwc3_msm_write_reg(mdwc->base, DWC3_DEVTEN, reg); /* Add power event if the dbm indicates coming out of L1 by interrupt */ if (mdwc->dbm && dbm_l1_lpm_interrupt(mdwc->dbm)) dwc3_msm_write_reg_field(mdwc->base, PWR_EVNT_IRQ_MASK_REG, PWR_EVNT_LPM_OUT_L1_MASK, 1); } static void dwc3_chg_enable_secondary_det(struct dwc3_msm *mdwc) Loading Loading @@ -1722,6 +1734,12 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc) dev_info(mdwc->dev, "DWC3 exited from low power mode\n"); /* * Handle other power events that could not have been handled during * Low Power Mode */ dwc3_pwr_event_handler(mdwc); return 0; } Loading @@ -1746,7 +1764,6 @@ static void dwc3_wait_for_ext_chg_done(struct dwc3_msm *mdwc) else dev_dbg(mdwc->dev, "ext chg wait done\n"); } } static void dwc3_resume_work(struct work_struct *w) Loading Loading @@ -1788,6 +1805,41 @@ static void dwc3_resume_work(struct work_struct *w) } } static void dwc3_pwr_event_handler(struct dwc3_msm *mdwc) { struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); u32 irq_stat, irq_clear = 0; irq_stat = dwc3_msm_read_reg(mdwc->base, PWR_EVNT_IRQ_STAT_REG); /* Handle exit from L1 events */ if (irq_stat & PWR_EVNT_LPM_OUT_L1_MASK) { dev_dbg(mdwc->dev, "%s: handling PWR_EVNT_LPM_OUT_L1_MASK\n", __func__); if (usb_gadget_wakeup(&dwc->gadget)) dev_err(mdwc->dev, "%s failed to take dwc out of L1\n", __func__); irq_stat &= ~PWR_EVNT_LPM_OUT_L1_MASK; irq_clear |= PWR_EVNT_LPM_OUT_L1_MASK; } /* Unhandled events */ if (irq_stat) dev_dbg(mdwc->dev, "%s: unexpected PWR_EVNT, irq_stat=%X\n", __func__, irq_stat); dwc3_msm_write_reg(mdwc->base, PWR_EVNT_IRQ_STAT_REG, irq_clear); } static irqreturn_t msm_dwc3_pwr_irq_thread(int irq, void *_mdwc) { struct dwc3_msm *mdwc = _mdwc; dev_dbg(mdwc->dev, "%s\n", __func__); dwc3_pwr_event_handler(mdwc); return IRQ_HANDLED; } static u32 debug_id = true, debug_bsv, debug_connect; static int dwc3_connect_show(struct seq_file *s, void *unused) Loading Loading @@ -1891,6 +1943,30 @@ static irqreturn_t msm_dwc3_irq(int irq, void *data) return IRQ_HANDLED; } static irqreturn_t msm_dwc3_pwr_irq(int irq, void *data) { struct dwc3_msm *mdwc = data; dev_dbg(mdwc->dev, "%s received\n", __func__); /* * When in Low Power Mode, can't read PWR_EVNT_IRQ_STAT_REG to acertain * which interrupts have been triggered, as the clocks are disabled. * After re-enabling the clocks, dwc3_msm_resume will call * dwc3_pwr_event_handler to handle all other power events */ if (atomic_read(&mdwc->in_lpm)) { /* bail out if system resume in process, else initiate RESUME */ if (atomic_read(&mdwc->pm_suspended)) mdwc->resume_pending = true; else pm_runtime_get(mdwc->dev); return IRQ_HANDLED; } return IRQ_WAKE_THREAD; } static int get_prop_usbin_voltage_now(struct dwc3_msm *mdwc) { Loading Loading @@ -2687,6 +2763,27 @@ static int dwc3_msm_probe(struct platform_device *pdev) } } /* * Some platforms have a special interrupt line for indicating resume * while in low power mode, when clocks are disabled. */ mdwc->pwr_event_irq = platform_get_irq_byname(pdev, "pwr_event_irq"); if (mdwc->pwr_event_irq < 0) { dev_dbg(&pdev->dev, "pget_irq for pwr_event_irq failed\n"); mdwc->pwr_event_irq = 0; } else { ret = devm_request_threaded_irq(&pdev->dev, mdwc->pwr_event_irq, msm_dwc3_pwr_irq, msm_dwc3_pwr_irq_thread, IRQF_TRIGGER_RISING, "msm_dwc3", mdwc); if (ret) { dev_err(&pdev->dev, "irqreq pwr_event_irq failed: %d\n", ret); goto disable_ref_clk; } } if (mdwc->ext_xceiv.otg_capability) { mdwc->pmic_id_irq = platform_get_irq_byname(pdev, "pmic_id_irq"); Loading Loading @@ -2766,6 +2863,21 @@ static int dwc3_msm_probe(struct platform_device *pdev) ret = -EPROBE_DEFER; goto disable_ref_clk; } /* * Add power event if the dbm indicates coming out of L1 * by interrupt */ if (dbm_l1_lpm_interrupt(mdwc->dbm)) { if (!mdwc->pwr_event_irq) { dev_err(&pdev->dev, "need pwr_event_irq exiting L1\n"); ret = -EINVAL; goto disable_ref_clk; } dwc3_msm_write_reg_field(mdwc->base, PWR_EVNT_IRQ_MASK_REG, PWR_EVNT_LPM_OUT_L1_MASK, 1); } } ret = of_property_read_u32(node, "qcom,restore-sec-cfg-for-scm-dev-id", Loading Loading @@ -3028,14 +3140,16 @@ static int dwc3_msm_remove(struct platform_device *pdev) power_supply_unregister(&mdwc->usb_psy); if (mdwc->hs_phy) mdwc->hs_phy->flags &= ~PHY_HOST_MODE; platform_device_put(mdwc->dwc3); device_for_each_child(&pdev->dev, NULL, dwc3_msm_remove_children); if (!IS_ERR_OR_NULL(mdwc->vbus_otg)) regulator_disable(mdwc->vbus_otg); if (mdwc->hs_phy_irq) disable_irq_wake(mdwc->hs_phy_irq); if (mdwc->pwr_event_irq) disable_irq(mdwc->pwr_event_irq); clk_disable_unprepare(mdwc->utmi_clk); clk_disable_unprepare(mdwc->core_clk); Loading drivers/usb/dwc3/gadget.c +9 −1 Original line number Diff line number Diff line Loading @@ -1515,6 +1515,7 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g) unsigned long timeout; unsigned long flags; bool link_recover_only = false; u32 reg; Loading @@ -1538,6 +1539,12 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g) case DWC3_LINK_STATE_RX_DET: /* in HS, means Early Suspend */ case DWC3_LINK_STATE_U3: /* in HS, means SUSPEND */ break; case DWC3_LINK_STATE_U1: if (dwc->gadget.speed != USB_SPEED_SUPER) { link_recover_only = true; break; } /* Intentional fallthrough */ default: dev_dbg(dwc->dev, "can't wakeup from link state %d\n", link_state); Loading Loading @@ -1584,6 +1591,7 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g) * the device is back at U0 state, it is required that * the resume sequence is initiated by SW. */ if (!link_recover_only) dwc3_gadget_wakeup_interrupt(dwc); out: spin_unlock_irqrestore(&dwc->lock, flags); Loading Loading
Documentation/devicetree/bindings/usb/msm-ssusb.txt +3 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,9 @@ Optional properties : "hs_phy_irq" : Interrupt from HSPHY for asynchronous events in LPM. This is not used if wakeup events are received externally (e.g. PMIC) "pmic_id_irq" : Interrupt from PMIC for external ID pin notification. "pwr_event_irq" : Interrupt to controller for asynchronous events in LPM. Used for SS-USB power events. This is not used if wakeup events are received externally (e.g. PMIC) - qcom,otg-capability: If present then depend on PMIC for VBUS notifications, otherwise depend on PHY. - qcom,suspend_event_enable: If present then suspend interrupt event is enabled. Loading
drivers/usb/dwc3/dwc3-msm.c +117 −3 Original line number Diff line number Diff line Loading @@ -113,6 +113,8 @@ MODULE_PARM_DESC(usb_lpm_override, "Override no_suspend_resume with USB"); #define PWR_EVNT_IRQ_MASK_REG (QSCRATCH_REG_OFFSET + 0x5C) #define HS_PHY_CTRL_COMMON_REG (QSCRATCH_REG_OFFSET + 0xEC) #define PWR_EVNT_LPM_OUT_L1_MASK BIT(13) /* TZ SCM parameters */ #define DWC3_MSM_RESTORE_SCM_CFG_CMD 0x2 struct dwc3_msm_scm_cmd_buf { Loading Loading @@ -210,6 +212,8 @@ struct dwc3_msm { unsigned int irq_to_affin; struct notifier_block dwc3_cpu_notifier; int pwr_event_irq; }; #define USB_HSPHY_3P3_VOL_MIN 3050000 /* uV */ Loading @@ -226,6 +230,8 @@ struct dwc3_msm { static struct usb_ext_notification *usb_ext; static void dwc3_pwr_event_handler(struct dwc3_msm *mdwc); /** * * Read register with debug info. Loading Loading @@ -1153,6 +1159,12 @@ static void dwc3_block_reset_usb_work(struct work_struct *w) reg |= DWC3_DEVTEN_SUSPEND; dwc3_msm_write_reg(mdwc->base, DWC3_DEVTEN, reg); /* Add power event if the dbm indicates coming out of L1 by interrupt */ if (mdwc->dbm && dbm_l1_lpm_interrupt(mdwc->dbm)) dwc3_msm_write_reg_field(mdwc->base, PWR_EVNT_IRQ_MASK_REG, PWR_EVNT_LPM_OUT_L1_MASK, 1); } static void dwc3_chg_enable_secondary_det(struct dwc3_msm *mdwc) Loading Loading @@ -1722,6 +1734,12 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc) dev_info(mdwc->dev, "DWC3 exited from low power mode\n"); /* * Handle other power events that could not have been handled during * Low Power Mode */ dwc3_pwr_event_handler(mdwc); return 0; } Loading @@ -1746,7 +1764,6 @@ static void dwc3_wait_for_ext_chg_done(struct dwc3_msm *mdwc) else dev_dbg(mdwc->dev, "ext chg wait done\n"); } } static void dwc3_resume_work(struct work_struct *w) Loading Loading @@ -1788,6 +1805,41 @@ static void dwc3_resume_work(struct work_struct *w) } } static void dwc3_pwr_event_handler(struct dwc3_msm *mdwc) { struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); u32 irq_stat, irq_clear = 0; irq_stat = dwc3_msm_read_reg(mdwc->base, PWR_EVNT_IRQ_STAT_REG); /* Handle exit from L1 events */ if (irq_stat & PWR_EVNT_LPM_OUT_L1_MASK) { dev_dbg(mdwc->dev, "%s: handling PWR_EVNT_LPM_OUT_L1_MASK\n", __func__); if (usb_gadget_wakeup(&dwc->gadget)) dev_err(mdwc->dev, "%s failed to take dwc out of L1\n", __func__); irq_stat &= ~PWR_EVNT_LPM_OUT_L1_MASK; irq_clear |= PWR_EVNT_LPM_OUT_L1_MASK; } /* Unhandled events */ if (irq_stat) dev_dbg(mdwc->dev, "%s: unexpected PWR_EVNT, irq_stat=%X\n", __func__, irq_stat); dwc3_msm_write_reg(mdwc->base, PWR_EVNT_IRQ_STAT_REG, irq_clear); } static irqreturn_t msm_dwc3_pwr_irq_thread(int irq, void *_mdwc) { struct dwc3_msm *mdwc = _mdwc; dev_dbg(mdwc->dev, "%s\n", __func__); dwc3_pwr_event_handler(mdwc); return IRQ_HANDLED; } static u32 debug_id = true, debug_bsv, debug_connect; static int dwc3_connect_show(struct seq_file *s, void *unused) Loading Loading @@ -1891,6 +1943,30 @@ static irqreturn_t msm_dwc3_irq(int irq, void *data) return IRQ_HANDLED; } static irqreturn_t msm_dwc3_pwr_irq(int irq, void *data) { struct dwc3_msm *mdwc = data; dev_dbg(mdwc->dev, "%s received\n", __func__); /* * When in Low Power Mode, can't read PWR_EVNT_IRQ_STAT_REG to acertain * which interrupts have been triggered, as the clocks are disabled. * After re-enabling the clocks, dwc3_msm_resume will call * dwc3_pwr_event_handler to handle all other power events */ if (atomic_read(&mdwc->in_lpm)) { /* bail out if system resume in process, else initiate RESUME */ if (atomic_read(&mdwc->pm_suspended)) mdwc->resume_pending = true; else pm_runtime_get(mdwc->dev); return IRQ_HANDLED; } return IRQ_WAKE_THREAD; } static int get_prop_usbin_voltage_now(struct dwc3_msm *mdwc) { Loading Loading @@ -2687,6 +2763,27 @@ static int dwc3_msm_probe(struct platform_device *pdev) } } /* * Some platforms have a special interrupt line for indicating resume * while in low power mode, when clocks are disabled. */ mdwc->pwr_event_irq = platform_get_irq_byname(pdev, "pwr_event_irq"); if (mdwc->pwr_event_irq < 0) { dev_dbg(&pdev->dev, "pget_irq for pwr_event_irq failed\n"); mdwc->pwr_event_irq = 0; } else { ret = devm_request_threaded_irq(&pdev->dev, mdwc->pwr_event_irq, msm_dwc3_pwr_irq, msm_dwc3_pwr_irq_thread, IRQF_TRIGGER_RISING, "msm_dwc3", mdwc); if (ret) { dev_err(&pdev->dev, "irqreq pwr_event_irq failed: %d\n", ret); goto disable_ref_clk; } } if (mdwc->ext_xceiv.otg_capability) { mdwc->pmic_id_irq = platform_get_irq_byname(pdev, "pmic_id_irq"); Loading Loading @@ -2766,6 +2863,21 @@ static int dwc3_msm_probe(struct platform_device *pdev) ret = -EPROBE_DEFER; goto disable_ref_clk; } /* * Add power event if the dbm indicates coming out of L1 * by interrupt */ if (dbm_l1_lpm_interrupt(mdwc->dbm)) { if (!mdwc->pwr_event_irq) { dev_err(&pdev->dev, "need pwr_event_irq exiting L1\n"); ret = -EINVAL; goto disable_ref_clk; } dwc3_msm_write_reg_field(mdwc->base, PWR_EVNT_IRQ_MASK_REG, PWR_EVNT_LPM_OUT_L1_MASK, 1); } } ret = of_property_read_u32(node, "qcom,restore-sec-cfg-for-scm-dev-id", Loading Loading @@ -3028,14 +3140,16 @@ static int dwc3_msm_remove(struct platform_device *pdev) power_supply_unregister(&mdwc->usb_psy); if (mdwc->hs_phy) mdwc->hs_phy->flags &= ~PHY_HOST_MODE; platform_device_put(mdwc->dwc3); device_for_each_child(&pdev->dev, NULL, dwc3_msm_remove_children); if (!IS_ERR_OR_NULL(mdwc->vbus_otg)) regulator_disable(mdwc->vbus_otg); if (mdwc->hs_phy_irq) disable_irq_wake(mdwc->hs_phy_irq); if (mdwc->pwr_event_irq) disable_irq(mdwc->pwr_event_irq); clk_disable_unprepare(mdwc->utmi_clk); clk_disable_unprepare(mdwc->core_clk); Loading
drivers/usb/dwc3/gadget.c +9 −1 Original line number Diff line number Diff line Loading @@ -1515,6 +1515,7 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g) unsigned long timeout; unsigned long flags; bool link_recover_only = false; u32 reg; Loading @@ -1538,6 +1539,12 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g) case DWC3_LINK_STATE_RX_DET: /* in HS, means Early Suspend */ case DWC3_LINK_STATE_U3: /* in HS, means SUSPEND */ break; case DWC3_LINK_STATE_U1: if (dwc->gadget.speed != USB_SPEED_SUPER) { link_recover_only = true; break; } /* Intentional fallthrough */ default: dev_dbg(dwc->dev, "can't wakeup from link state %d\n", link_state); Loading Loading @@ -1584,6 +1591,7 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g) * the device is back at U0 state, it is required that * the resume sequence is initiated by SW. */ if (!link_recover_only) dwc3_gadget_wakeup_interrupt(dwc); out: spin_unlock_irqrestore(&dwc->lock, flags); Loading