diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index 2b91cf8900a4..e37471462756 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -3928,7 +3928,7 @@ static int dwc3_msm_vbus_notifier(struct notifier_block *nb, * Drive a pulse on DP to ensure proper CDP detection * and only when the vbus connect event is a valid one. */ - if (get_chg_type(mdwc) == POWER_SUPPLY_TYPE_USB_CDP && + if (get_chg_type(mdwc) == POWER_SUPPLY_USB_TYPE_CDP && mdwc->vbus_active && !mdwc->check_eud_state) { dev_dbg(mdwc->dev, "Connected to CDP, pull DP up\n"); mdwc->hs_phy->charger_detect(mdwc->hs_phy); diff --git a/drivers/usb/phy/phy-msm-qusb.c b/drivers/usb/phy/phy-msm-qusb.c index cda987f2b366..40e97780b35c 100644 --- a/drivers/usb/phy/phy-msm-qusb.c +++ b/drivers/usb/phy/phy-msm-qusb.c @@ -22,6 +22,17 @@ #include #include +#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) @@ -50,6 +61,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) @@ -735,6 +747,85 @@ static int qusb_phy_notify_disconnect(struct usb_phy *phy, qphy->cable_connected); return 0; } +#define DP_PULSE_WIDTH_MSEC 200 +static enum usb_charger_type qusb_phy_drive_dp_pulse(struct usb_phy *phy) +{ + 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 0; + } + 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(DP_PULSE_WIDTH_MSEC); + + /* 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 0; +} static int qusb_phy_dpdm_regulator_enable(struct regulator_dev *rdev) { @@ -1141,6 +1232,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.charger_detect = qusb_phy_drive_dp_pulse; /* * On some platforms multiple QUSB PHYs are available. If QUSB PHY is