Loading Documentation/devicetree/bindings/usb/msm-ssusb.txt +2 −0 Original line number Diff line number Diff line Loading @@ -46,6 +46,8 @@ Optional properties : - vbus_dwc3-supply: phandle to the 5V VBUS supply regulator used for host mode. - USB3_GDSC-supply : phandle to the globally distributed switch controller regulator node to the USB controller. - dpdm-supply: phandle to dpdm supply which will be used to drive dp/dm lines in high-z state. - qcom,dwc-usb3-msm-tx-fifo-size: If present, represents RAM size available for TX fifo allocation in bytes - qcom,lpm-to-suspend-delay-ms: Indicates timeout (in milliseconds) to release wakeup source Loading arch/arm64/boot/dts/qcom/qcs405-usb.dtsi +1 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ interrupts = <0 25 0>, <0 319 0>; interrupt-names = "pwr_event_irq", "hs_phy_irq"; dpdm-supply = <&usb2_phy0>; clocks = <&clock_gcc GCC_USB30_MASTER_CLK>, <&clock_gcc GCC_SYS_NOC_USB3_CLK>, <&clock_gcc GCC_USB30_SLEEP_CLK>, Loading arch/arm64/boot/dts/qcom/sm8150-usb.dtsi +1 −0 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ qcom,use-pdc-interrupts; USB3_GDSC-supply = <&usb30_prim_gdsc>; dpdm-supply = <&usb2_phy0>; clocks = <&clock_gcc GCC_USB30_PRIM_MASTER_CLK>, <&clock_gcc GCC_CFG_NOC_USB3_PRIM_AXI_CLK>, <&clock_gcc GCC_AGGRE_USB3_PRIM_AXI_CLK>, Loading drivers/usb/dwc3/dwc3-msm.c +76 −1 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ #include <linux/usb/gadget.h> #include <linux/usb/of.h> #include <linux/regulator/consumer.h> #include <linux/regulator/driver.h> #include <linux/pm_wakeup.h> #include <linux/power_supply.h> #include <linux/cdev.h> Loading Loading @@ -150,6 +151,7 @@ enum dwc3_drd_state { }; static const char *const state_names[] = { [DRD_STATE_UNDEFINED] = "undefined", [DRD_STATE_IDLE] = "idle", [DRD_STATE_PERIPHERAL] = "peripheral", [DRD_STATE_PERIPHERAL_SUSPEND] = "peripheral_suspend", Loading @@ -160,7 +162,7 @@ static const char *const state_names[] = { const char *dwc3_drd_state_string(enum dwc3_drd_state state) { if (state < 0 || state >= ARRAY_SIZE(state_names)) return "UNDEFINED"; return "UNKNOWN"; return state_names[state]; } Loading Loading @@ -320,6 +322,10 @@ struct dwc3_msm { enum usb_device_speed override_usb_speed; u32 *gsi_reg; int gsi_reg_offset_cnt; struct notifier_block dpdm_nb; struct regulator *dpdm_reg; }; #define USB_HSPHY_3P3_VOL_MIN 3050000 /* uV */ Loading Loading @@ -2769,6 +2775,17 @@ static void dwc3_resume_work(struct work_struct *w) dwc->gadget.is_selfpowered = 0; } /* * Skip scheduling sm work if no work is pending. When boot-up * with USB cable connected, usb state m/c is skipped to avoid * any changes to dp/dm lines. As PM supsend and resume can * happen while charger is connected, scheduling sm work during * pm resume will reset the controller and phy which might impact * dp/dm lines (and charging voltage). */ if (mdwc->drd_state == DRD_STATE_UNDEFINED && !edev && !mdwc->resume_pending) return; /* * exit LPM first to meet resume timeline from device side. * resume_pending flag would prevent calling Loading Loading @@ -3382,6 +3399,29 @@ static ssize_t bus_vote_store(struct device *dev, } static DEVICE_ATTR_RW(bus_vote); static int dwc_dpdm_cb(struct notifier_block *nb, unsigned long evt, void *p) { struct dwc3_msm *mdwc = container_of(nb, struct dwc3_msm, dpdm_nb); switch (evt) { case REGULATOR_EVENT_ENABLE: dev_dbg(mdwc->dev, "%s: enable state:%s\n", __func__, dwc3_drd_state_string(mdwc->drd_state)); break; case REGULATOR_EVENT_DISABLE: dev_dbg(mdwc->dev, "%s: disable state:%s\n", __func__, dwc3_drd_state_string(mdwc->drd_state)); if (mdwc->drd_state == DRD_STATE_UNDEFINED) schedule_delayed_work(&mdwc->sm_work, 0); break; default: dev_dbg(mdwc->dev, "%s: unknown event state:%s\n", __func__, dwc3_drd_state_string(mdwc->drd_state)); break; } return NOTIFY_OK; } static int dwc3_msm_probe(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node, *dwc3_node; Loading Loading @@ -3689,6 +3729,29 @@ static int dwc3_msm_probe(struct platform_device *pdev) ret = dwc3_msm_extcon_register(mdwc); if (ret) goto put_dwc3; /* * dpdm regulator will be turned on to perform apsd * (automatic power source detection). dpdm regulator is * used to float (or high-z) dp/dm lines. Do not reset * controller/phy if regulator is turned on. * if dpdm is not present controller can be reset * as this controller may not be used for charger detection. */ mdwc->dpdm_reg = devm_regulator_get(&pdev->dev, "dpdm"); if (IS_ERR(mdwc->dpdm_reg)) { dev_dbg(mdwc->dev, "assume cable is not connected\n"); mdwc->dpdm_reg = NULL; } if (!mdwc->vbus_active && mdwc->dpdm_reg && regulator_is_enabled(mdwc->dpdm_reg)) { mdwc->dpdm_nb.notifier_call = dwc_dpdm_cb; regulator_register_notifier(mdwc->dpdm_reg, &mdwc->dpdm_nb); } else { queue_delayed_work(mdwc->sm_usb_wq, &mdwc->sm_work, 0); } } else { if ((dwc->dr_mode == USB_DR_MODE_OTG && !of_property_read_bool(node, "qcom,default-mode-host")) || Loading Loading @@ -3736,6 +3799,12 @@ static int dwc3_msm_remove(struct platform_device *pdev) int ret_pm; device_remove_file(&pdev->dev, &dev_attr_mode); if (mdwc->dpdm_nb.notifier_call) { regulator_unregister_notifier(mdwc->dpdm_reg, &mdwc->dpdm_nb); mdwc->dpdm_nb.notifier_call = NULL; } if (mdwc->usb_psy) power_supply_put(mdwc->usb_psy); Loading Loading @@ -4298,6 +4367,12 @@ static void dwc3_otg_sm_work(struct work_struct *w) /* Check OTG state */ switch (mdwc->drd_state) { case DRD_STATE_UNDEFINED: if (mdwc->dpdm_nb.notifier_call) { regulator_unregister_notifier(mdwc->dpdm_reg, &mdwc->dpdm_nb); mdwc->dpdm_nb.notifier_call = NULL; } /* put controller and phy in suspend if no cable connected */ if (test_bit(ID, &mdwc->inputs) && !test_bit(B_SESS_VLD, &mdwc->inputs)) { Loading Loading
Documentation/devicetree/bindings/usb/msm-ssusb.txt +2 −0 Original line number Diff line number Diff line Loading @@ -46,6 +46,8 @@ Optional properties : - vbus_dwc3-supply: phandle to the 5V VBUS supply regulator used for host mode. - USB3_GDSC-supply : phandle to the globally distributed switch controller regulator node to the USB controller. - dpdm-supply: phandle to dpdm supply which will be used to drive dp/dm lines in high-z state. - qcom,dwc-usb3-msm-tx-fifo-size: If present, represents RAM size available for TX fifo allocation in bytes - qcom,lpm-to-suspend-delay-ms: Indicates timeout (in milliseconds) to release wakeup source Loading
arch/arm64/boot/dts/qcom/qcs405-usb.dtsi +1 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ interrupts = <0 25 0>, <0 319 0>; interrupt-names = "pwr_event_irq", "hs_phy_irq"; dpdm-supply = <&usb2_phy0>; clocks = <&clock_gcc GCC_USB30_MASTER_CLK>, <&clock_gcc GCC_SYS_NOC_USB3_CLK>, <&clock_gcc GCC_USB30_SLEEP_CLK>, Loading
arch/arm64/boot/dts/qcom/sm8150-usb.dtsi +1 −0 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ qcom,use-pdc-interrupts; USB3_GDSC-supply = <&usb30_prim_gdsc>; dpdm-supply = <&usb2_phy0>; clocks = <&clock_gcc GCC_USB30_PRIM_MASTER_CLK>, <&clock_gcc GCC_CFG_NOC_USB3_PRIM_AXI_CLK>, <&clock_gcc GCC_AGGRE_USB3_PRIM_AXI_CLK>, Loading
drivers/usb/dwc3/dwc3-msm.c +76 −1 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ #include <linux/usb/gadget.h> #include <linux/usb/of.h> #include <linux/regulator/consumer.h> #include <linux/regulator/driver.h> #include <linux/pm_wakeup.h> #include <linux/power_supply.h> #include <linux/cdev.h> Loading Loading @@ -150,6 +151,7 @@ enum dwc3_drd_state { }; static const char *const state_names[] = { [DRD_STATE_UNDEFINED] = "undefined", [DRD_STATE_IDLE] = "idle", [DRD_STATE_PERIPHERAL] = "peripheral", [DRD_STATE_PERIPHERAL_SUSPEND] = "peripheral_suspend", Loading @@ -160,7 +162,7 @@ static const char *const state_names[] = { const char *dwc3_drd_state_string(enum dwc3_drd_state state) { if (state < 0 || state >= ARRAY_SIZE(state_names)) return "UNDEFINED"; return "UNKNOWN"; return state_names[state]; } Loading Loading @@ -320,6 +322,10 @@ struct dwc3_msm { enum usb_device_speed override_usb_speed; u32 *gsi_reg; int gsi_reg_offset_cnt; struct notifier_block dpdm_nb; struct regulator *dpdm_reg; }; #define USB_HSPHY_3P3_VOL_MIN 3050000 /* uV */ Loading Loading @@ -2769,6 +2775,17 @@ static void dwc3_resume_work(struct work_struct *w) dwc->gadget.is_selfpowered = 0; } /* * Skip scheduling sm work if no work is pending. When boot-up * with USB cable connected, usb state m/c is skipped to avoid * any changes to dp/dm lines. As PM supsend and resume can * happen while charger is connected, scheduling sm work during * pm resume will reset the controller and phy which might impact * dp/dm lines (and charging voltage). */ if (mdwc->drd_state == DRD_STATE_UNDEFINED && !edev && !mdwc->resume_pending) return; /* * exit LPM first to meet resume timeline from device side. * resume_pending flag would prevent calling Loading Loading @@ -3382,6 +3399,29 @@ static ssize_t bus_vote_store(struct device *dev, } static DEVICE_ATTR_RW(bus_vote); static int dwc_dpdm_cb(struct notifier_block *nb, unsigned long evt, void *p) { struct dwc3_msm *mdwc = container_of(nb, struct dwc3_msm, dpdm_nb); switch (evt) { case REGULATOR_EVENT_ENABLE: dev_dbg(mdwc->dev, "%s: enable state:%s\n", __func__, dwc3_drd_state_string(mdwc->drd_state)); break; case REGULATOR_EVENT_DISABLE: dev_dbg(mdwc->dev, "%s: disable state:%s\n", __func__, dwc3_drd_state_string(mdwc->drd_state)); if (mdwc->drd_state == DRD_STATE_UNDEFINED) schedule_delayed_work(&mdwc->sm_work, 0); break; default: dev_dbg(mdwc->dev, "%s: unknown event state:%s\n", __func__, dwc3_drd_state_string(mdwc->drd_state)); break; } return NOTIFY_OK; } static int dwc3_msm_probe(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node, *dwc3_node; Loading Loading @@ -3689,6 +3729,29 @@ static int dwc3_msm_probe(struct platform_device *pdev) ret = dwc3_msm_extcon_register(mdwc); if (ret) goto put_dwc3; /* * dpdm regulator will be turned on to perform apsd * (automatic power source detection). dpdm regulator is * used to float (or high-z) dp/dm lines. Do not reset * controller/phy if regulator is turned on. * if dpdm is not present controller can be reset * as this controller may not be used for charger detection. */ mdwc->dpdm_reg = devm_regulator_get(&pdev->dev, "dpdm"); if (IS_ERR(mdwc->dpdm_reg)) { dev_dbg(mdwc->dev, "assume cable is not connected\n"); mdwc->dpdm_reg = NULL; } if (!mdwc->vbus_active && mdwc->dpdm_reg && regulator_is_enabled(mdwc->dpdm_reg)) { mdwc->dpdm_nb.notifier_call = dwc_dpdm_cb; regulator_register_notifier(mdwc->dpdm_reg, &mdwc->dpdm_nb); } else { queue_delayed_work(mdwc->sm_usb_wq, &mdwc->sm_work, 0); } } else { if ((dwc->dr_mode == USB_DR_MODE_OTG && !of_property_read_bool(node, "qcom,default-mode-host")) || Loading Loading @@ -3736,6 +3799,12 @@ static int dwc3_msm_remove(struct platform_device *pdev) int ret_pm; device_remove_file(&pdev->dev, &dev_attr_mode); if (mdwc->dpdm_nb.notifier_call) { regulator_unregister_notifier(mdwc->dpdm_reg, &mdwc->dpdm_nb); mdwc->dpdm_nb.notifier_call = NULL; } if (mdwc->usb_psy) power_supply_put(mdwc->usb_psy); Loading Loading @@ -4298,6 +4367,12 @@ static void dwc3_otg_sm_work(struct work_struct *w) /* Check OTG state */ switch (mdwc->drd_state) { case DRD_STATE_UNDEFINED: if (mdwc->dpdm_nb.notifier_call) { regulator_unregister_notifier(mdwc->dpdm_reg, &mdwc->dpdm_nb); mdwc->dpdm_nb.notifier_call = NULL; } /* put controller and phy in suspend if no cable connected */ if (test_bit(ID, &mdwc->inputs) && !test_bit(B_SESS_VLD, &mdwc->inputs)) { Loading