Loading drivers/usb/dwc3/dwc3-msm.c +10 −0 Original line number Diff line number Diff line Loading @@ -3041,6 +3041,7 @@ static irqreturn_t msm_dwc3_pwr_irq(int irq, void *data) } static void dwc3_otg_sm_work(struct work_struct *w); static int get_psy_type(struct dwc3_msm *mdwc); static int dwc3_msm_get_clk_gdsc(struct dwc3_msm *mdwc) { Loading Loading @@ -3207,6 +3208,8 @@ static void check_for_sdp_connection(struct work_struct *w) } } #define DP_PULSE_WIDTH_MSEC 200 static int dwc3_msm_vbus_notifier(struct notifier_block *nb, unsigned long event, void *ptr) { Loading @@ -3230,6 +3233,13 @@ static int dwc3_msm_vbus_notifier(struct notifier_block *nb, dev_dbg(mdwc->dev, "vbus:%ld event received\n", event); mdwc->vbus_active = event; if (get_psy_type(mdwc) == POWER_SUPPLY_TYPE_USB_CDP && mdwc->vbus_active) { dev_dbg(mdwc->dev, "Connected to CDP, pull DP up\n"); usb_phy_drive_dp_pulse(mdwc->hs_phy, DP_PULSE_WIDTH_MSEC); } if ((dwc->dr_mode == USB_DR_MODE_OTG) && !mdwc->in_restart) queue_work(mdwc->dwc3_wq, &mdwc->resume_work); Loading drivers/usb/phy/phy-msm-qusb.c +93 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,17 @@ #include <linux/usb/phy.h> #include <linux/reset.h> #define QUSB2PHY_PLL_PWR_CTL 0x18 #define REF_BUF_EN BIT(0) #define REXT_EN BIT(1) #define PLL_BYPASSNL BIT(2) #define REXT_TRIM_0 BIT(4) #define QUSB2PHY_PLL_AUTOPGM_CTL1 0x1C #define PLL_RESET_N_CNT_5 0x5 #define PLL_RESET_N BIT(4) #define PLL_AUTOPGM_EN BIT(7) #define QUSB2PHY_PLL_STATUS 0x38 #define QUSB2PHY_PLL_LOCK BIT(5) Loading Loading @@ -55,6 +66,7 @@ #define CORE_READY_STATUS BIT(0) #define QUSB2PHY_PORT_UTMI_CTRL1 0xC0 #define SUSPEND_N BIT(5) #define TERM_SELECT BIT(4) #define XCVR_SELECT_FS BIT(2) #define OP_MODE_NON_DRIVE BIT(0) Loading Loading @@ -781,6 +793,86 @@ static int qusb_phy_notify_disconnect(struct usb_phy *phy, return 0; } static int qusb_phy_drive_dp_pulse(struct usb_phy *phy, unsigned int pulse_width) { struct qusb_phy *qphy = container_of(phy, struct qusb_phy, phy); int ret; dev_dbg(qphy->phy.dev, "connected to a CDP, drive DP up\n"); ret = qusb_phy_enable_power(qphy, true); if (ret < 0) { dev_dbg(qphy->phy.dev, "dpdm regulator enable failed:%d\n", ret); return ret; } qusb_phy_gdsc(qphy, true); qusb_phy_enable_clocks(qphy, true); ret = reset_control_assert(qphy->phy_reset); if (ret) dev_err(qphy->phy.dev, "phyassert failed\n"); usleep_range(100, 150); ret = reset_control_deassert(qphy->phy_reset); if (ret) dev_err(qphy->phy.dev, "deassert failed\n"); /* Configure PHY to enable control on DP/DM lines */ writel_relaxed(CLAMP_N_EN | FREEZIO_N | POWER_DOWN, qphy->base + QUSB2PHY_PORT_POWERDOWN); writel_relaxed(TERM_SELECT | XCVR_SELECT_FS | OP_MODE_NON_DRIVE | SUSPEND_N, qphy->base + QUSB2PHY_PORT_UTMI_CTRL1); writel_relaxed(UTMI_ULPI_SEL | UTMI_TEST_MUX_SEL, qphy->base + QUSB2PHY_PORT_UTMI_CTRL2); writel_relaxed(PLL_RESET_N_CNT_5, qphy->base + QUSB2PHY_PLL_AUTOPGM_CTL1); writel_relaxed(CLAMP_N_EN | FREEZIO_N, qphy->base + QUSB2PHY_PORT_POWERDOWN); writel_relaxed(REF_BUF_EN | REXT_EN | PLL_BYPASSNL | REXT_TRIM_0, qphy->base + QUSB2PHY_PLL_PWR_CTL); usleep_range(5, 10); writel_relaxed(0x15, qphy->base + QUSB2PHY_PLL_AUTOPGM_CTL1); writel_relaxed(PLL_RESET_N | PLL_RESET_N_CNT_5, qphy->base + QUSB2PHY_PLL_AUTOPGM_CTL1); writel_relaxed(0x00, qphy->base + QUSB2PHY_PORT_QC1); writel_relaxed(0x00, qphy->base + QUSB2PHY_PORT_QC2); usleep_range(50, 60); /* Enable Rdp_en to pull DP up to 3V */ writel_relaxed(RDP_UP_EN, qphy->base + QUSB2PHY_PORT_QC2); msleep(pulse_width); /* Put the PHY and DP back to normal state */ writel_relaxed(CLAMP_N_EN | FREEZIO_N | POWER_DOWN, qphy->base + QUSB2PHY_PORT_POWERDOWN); /* 23 */ writel_relaxed(PLL_AUTOPGM_EN | PLL_RESET_N | PLL_RESET_N_CNT_5, qphy->base + QUSB2PHY_PLL_AUTOPGM_CTL1); writel_relaxed(UTMI_ULPI_SEL, qphy->base + QUSB2PHY_PORT_UTMI_CTRL2); writel_relaxed(TERM_SELECT, qphy->base + QUSB2PHY_PORT_UTMI_CTRL1); qusb_phy_enable_clocks(qphy, false); qusb_phy_gdsc(qphy, false); ret = qusb_phy_enable_power(qphy, false); if (ret < 0) { dev_dbg(qphy->phy.dev, "dpdm regulator disable failed:%d\n", ret); return ret; } return 0; } static int qusb_phy_dpdm_regulator_enable(struct regulator_dev *rdev) { int ret = 0; Loading Loading @@ -1239,6 +1331,7 @@ static int qusb_phy_probe(struct platform_device *pdev) qphy->phy.type = USB_PHY_TYPE_USB2; qphy->phy.notify_connect = qusb_phy_notify_connect; qphy->phy.notify_disconnect = qusb_phy_notify_disconnect; qphy->phy.drive_dp_pulse = qusb_phy_drive_dp_pulse; /* * On some platforms multiple QUSB PHYs are available. If QUSB PHY is Loading include/linux/usb/phy.h +11 −0 Original line number Diff line number Diff line Loading @@ -176,6 +176,8 @@ struct usb_phy { /* reset the PHY clocks */ int (*reset)(struct usb_phy *x); int (*drive_dp_pulse)(struct usb_phy *x, unsigned int pulse_width); }; /** Loading Loading @@ -259,6 +261,15 @@ usb_phy_reset(struct usb_phy *x) return 0; } static inline int usb_phy_drive_dp_pulse(struct usb_phy *x, unsigned int pulse_width) { if (x && x->drive_dp_pulse) return x->drive_dp_pulse(x, pulse_width); return 0; } /* for usb host and peripheral controller drivers */ #if IS_ENABLED(CONFIG_USB_PHY) extern struct usb_phy *usb_get_phy(enum usb_phy_type type); Loading Loading
drivers/usb/dwc3/dwc3-msm.c +10 −0 Original line number Diff line number Diff line Loading @@ -3041,6 +3041,7 @@ static irqreturn_t msm_dwc3_pwr_irq(int irq, void *data) } static void dwc3_otg_sm_work(struct work_struct *w); static int get_psy_type(struct dwc3_msm *mdwc); static int dwc3_msm_get_clk_gdsc(struct dwc3_msm *mdwc) { Loading Loading @@ -3207,6 +3208,8 @@ static void check_for_sdp_connection(struct work_struct *w) } } #define DP_PULSE_WIDTH_MSEC 200 static int dwc3_msm_vbus_notifier(struct notifier_block *nb, unsigned long event, void *ptr) { Loading @@ -3230,6 +3233,13 @@ static int dwc3_msm_vbus_notifier(struct notifier_block *nb, dev_dbg(mdwc->dev, "vbus:%ld event received\n", event); mdwc->vbus_active = event; if (get_psy_type(mdwc) == POWER_SUPPLY_TYPE_USB_CDP && mdwc->vbus_active) { dev_dbg(mdwc->dev, "Connected to CDP, pull DP up\n"); usb_phy_drive_dp_pulse(mdwc->hs_phy, DP_PULSE_WIDTH_MSEC); } if ((dwc->dr_mode == USB_DR_MODE_OTG) && !mdwc->in_restart) queue_work(mdwc->dwc3_wq, &mdwc->resume_work); Loading
drivers/usb/phy/phy-msm-qusb.c +93 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,17 @@ #include <linux/usb/phy.h> #include <linux/reset.h> #define QUSB2PHY_PLL_PWR_CTL 0x18 #define REF_BUF_EN BIT(0) #define REXT_EN BIT(1) #define PLL_BYPASSNL BIT(2) #define REXT_TRIM_0 BIT(4) #define QUSB2PHY_PLL_AUTOPGM_CTL1 0x1C #define PLL_RESET_N_CNT_5 0x5 #define PLL_RESET_N BIT(4) #define PLL_AUTOPGM_EN BIT(7) #define QUSB2PHY_PLL_STATUS 0x38 #define QUSB2PHY_PLL_LOCK BIT(5) Loading Loading @@ -55,6 +66,7 @@ #define CORE_READY_STATUS BIT(0) #define QUSB2PHY_PORT_UTMI_CTRL1 0xC0 #define SUSPEND_N BIT(5) #define TERM_SELECT BIT(4) #define XCVR_SELECT_FS BIT(2) #define OP_MODE_NON_DRIVE BIT(0) Loading Loading @@ -781,6 +793,86 @@ static int qusb_phy_notify_disconnect(struct usb_phy *phy, return 0; } static int qusb_phy_drive_dp_pulse(struct usb_phy *phy, unsigned int pulse_width) { struct qusb_phy *qphy = container_of(phy, struct qusb_phy, phy); int ret; dev_dbg(qphy->phy.dev, "connected to a CDP, drive DP up\n"); ret = qusb_phy_enable_power(qphy, true); if (ret < 0) { dev_dbg(qphy->phy.dev, "dpdm regulator enable failed:%d\n", ret); return ret; } qusb_phy_gdsc(qphy, true); qusb_phy_enable_clocks(qphy, true); ret = reset_control_assert(qphy->phy_reset); if (ret) dev_err(qphy->phy.dev, "phyassert failed\n"); usleep_range(100, 150); ret = reset_control_deassert(qphy->phy_reset); if (ret) dev_err(qphy->phy.dev, "deassert failed\n"); /* Configure PHY to enable control on DP/DM lines */ writel_relaxed(CLAMP_N_EN | FREEZIO_N | POWER_DOWN, qphy->base + QUSB2PHY_PORT_POWERDOWN); writel_relaxed(TERM_SELECT | XCVR_SELECT_FS | OP_MODE_NON_DRIVE | SUSPEND_N, qphy->base + QUSB2PHY_PORT_UTMI_CTRL1); writel_relaxed(UTMI_ULPI_SEL | UTMI_TEST_MUX_SEL, qphy->base + QUSB2PHY_PORT_UTMI_CTRL2); writel_relaxed(PLL_RESET_N_CNT_5, qphy->base + QUSB2PHY_PLL_AUTOPGM_CTL1); writel_relaxed(CLAMP_N_EN | FREEZIO_N, qphy->base + QUSB2PHY_PORT_POWERDOWN); writel_relaxed(REF_BUF_EN | REXT_EN | PLL_BYPASSNL | REXT_TRIM_0, qphy->base + QUSB2PHY_PLL_PWR_CTL); usleep_range(5, 10); writel_relaxed(0x15, qphy->base + QUSB2PHY_PLL_AUTOPGM_CTL1); writel_relaxed(PLL_RESET_N | PLL_RESET_N_CNT_5, qphy->base + QUSB2PHY_PLL_AUTOPGM_CTL1); writel_relaxed(0x00, qphy->base + QUSB2PHY_PORT_QC1); writel_relaxed(0x00, qphy->base + QUSB2PHY_PORT_QC2); usleep_range(50, 60); /* Enable Rdp_en to pull DP up to 3V */ writel_relaxed(RDP_UP_EN, qphy->base + QUSB2PHY_PORT_QC2); msleep(pulse_width); /* Put the PHY and DP back to normal state */ writel_relaxed(CLAMP_N_EN | FREEZIO_N | POWER_DOWN, qphy->base + QUSB2PHY_PORT_POWERDOWN); /* 23 */ writel_relaxed(PLL_AUTOPGM_EN | PLL_RESET_N | PLL_RESET_N_CNT_5, qphy->base + QUSB2PHY_PLL_AUTOPGM_CTL1); writel_relaxed(UTMI_ULPI_SEL, qphy->base + QUSB2PHY_PORT_UTMI_CTRL2); writel_relaxed(TERM_SELECT, qphy->base + QUSB2PHY_PORT_UTMI_CTRL1); qusb_phy_enable_clocks(qphy, false); qusb_phy_gdsc(qphy, false); ret = qusb_phy_enable_power(qphy, false); if (ret < 0) { dev_dbg(qphy->phy.dev, "dpdm regulator disable failed:%d\n", ret); return ret; } return 0; } static int qusb_phy_dpdm_regulator_enable(struct regulator_dev *rdev) { int ret = 0; Loading Loading @@ -1239,6 +1331,7 @@ static int qusb_phy_probe(struct platform_device *pdev) qphy->phy.type = USB_PHY_TYPE_USB2; qphy->phy.notify_connect = qusb_phy_notify_connect; qphy->phy.notify_disconnect = qusb_phy_notify_disconnect; qphy->phy.drive_dp_pulse = qusb_phy_drive_dp_pulse; /* * On some platforms multiple QUSB PHYs are available. If QUSB PHY is Loading
include/linux/usb/phy.h +11 −0 Original line number Diff line number Diff line Loading @@ -176,6 +176,8 @@ struct usb_phy { /* reset the PHY clocks */ int (*reset)(struct usb_phy *x); int (*drive_dp_pulse)(struct usb_phy *x, unsigned int pulse_width); }; /** Loading Loading @@ -259,6 +261,15 @@ usb_phy_reset(struct usb_phy *x) return 0; } static inline int usb_phy_drive_dp_pulse(struct usb_phy *x, unsigned int pulse_width) { if (x && x->drive_dp_pulse) return x->drive_dp_pulse(x, pulse_width); return 0; } /* for usb host and peripheral controller drivers */ #if IS_ENABLED(CONFIG_USB_PHY) extern struct usb_phy *usb_get_phy(enum usb_phy_type type); Loading