diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index eb0924e535ad..2b91cf8900a4 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -3931,7 +3931,7 @@ static int dwc3_msm_vbus_notifier(struct notifier_block *nb, if (get_chg_type(mdwc) == POWER_SUPPLY_TYPE_USB_CDP && mdwc->vbus_active && !mdwc->check_eud_state) { dev_dbg(mdwc->dev, "Connected to CDP, pull DP up\n"); - usb_phy_drive_dp_pulse(mdwc->hs_phy, DP_PULSE_WIDTH_MSEC); + mdwc->hs_phy->charger_detect(mdwc->hs_phy); } mdwc->ext_idx = enb->idx; diff --git a/drivers/usb/phy/phy-msm-qusb-v2.c b/drivers/usb/phy/phy-msm-qusb-v2.c index 5af027034061..9a828e29f5c3 100644 --- a/drivers/usb/phy/phy-msm-qusb-v2.c +++ b/drivers/usb/phy/phy-msm-qusb-v2.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2014-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2021, The Linux Foundation. All rights reserved. */ #include @@ -834,7 +834,8 @@ static int qusb_phy_notify_disconnect(struct usb_phy *phy, return 0; } -void usb_phy_drive_dp_pulse(void *phy, unsigned int interval_ms) +#define DP_PULSE_WIDTH_MSEC 200 +static enum usb_charger_type usb_phy_drive_dp_pulse(struct usb_phy *phy) { struct qusb_phy *qphy = container_of(phy, struct qusb_phy, phy); int ret; @@ -843,7 +844,7 @@ void usb_phy_drive_dp_pulse(void *phy, unsigned int interval_ms) if (ret < 0) { dev_dbg(qphy->phy.dev, "dpdm regulator enable failed:%d\n", ret); - return; + return 0; } qusb_phy_enable_clocks(qphy, true); msm_usb_write_readback(qphy->base, qphy->phy_reg[PWR_CTRL1], @@ -862,7 +863,7 @@ void usb_phy_drive_dp_pulse(void *phy, unsigned int interval_ms) msm_usb_write_readback(qphy->base, qphy->phy_reg[INTR_CTRL], DPSE_INTR_EN, DPSE_INTR_EN); - msleep(interval_ms); + msleep(DP_PULSE_WIDTH_MSEC); msm_usb_write_readback(qphy->base, qphy->phy_reg[INTR_CTRL], DPSE_INTR_HIGH_SEL | @@ -884,8 +885,9 @@ void usb_phy_drive_dp_pulse(void *phy, unsigned int interval_ms) dev_dbg(qphy->phy.dev, "dpdm regulator disable failed:%d\n", ret); } + + return 0; } -EXPORT_SYMBOL(usb_phy_drive_dp_pulse); static int qusb_phy_dpdm_regulator_enable(struct regulator_dev *rdev) { @@ -1316,6 +1318,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 = usb_phy_drive_dp_pulse; ret = usb_add_phy_dev(&qphy->phy); if (ret) diff --git a/drivers/usb/phy/phy-msm-snps-hs.c b/drivers/usb/phy/phy-msm-snps-hs.c index 619951fee626..a7c8d043b56a 100644 --- a/drivers/usb/phy/phy-msm-snps-hs.c +++ b/drivers/usb/phy/phy-msm-snps-hs.c @@ -28,6 +28,11 @@ #define OPMODE_MASK (0x3 << 3) #define OPMODE_NONDRIVING (0x1 << 3) #define SLEEPM BIT(0) +#define OPMODE_NORMAL (0x00) +#define TERMSEL BIT(5) + +#define USB2_PHY_USB_PHY_UTMI_CTRL1 (0x40) +#define XCVRSEL BIT(0) #define USB2_PHY_USB_PHY_UTMI_CTRL5 (0x50) #define POR BIT(1) @@ -557,6 +562,63 @@ static int msm_hsphy_notify_disconnect(struct usb_phy *uphy, return 0; } +#define DP_PULSE_WIDTH_MSEC 200 +static enum usb_charger_type usb_phy_drive_dp_pulse(struct usb_phy *uphy) +{ + struct msm_hsphy *phy = container_of(uphy, struct msm_hsphy, phy); + int ret; + + ret = msm_hsphy_enable_power(phy, true); + if (ret < 0) { + dev_dbg(phy->phy.dev, + "dpdm regulator enable failed:%d\n", ret); + return 0; + } + msm_hsphy_enable_clocks(phy, true); + /* set utmi_phy_cmn_cntrl_override_en & + * utmi_phy_datapath_ctrl_override_en + */ + msm_usb_write_readback(phy->base, USB2_PHY_USB_PHY_CFG0, + UTMI_PHY_CMN_CTRL_OVERRIDE_EN, + UTMI_PHY_CMN_CTRL_OVERRIDE_EN); + msm_usb_write_readback(phy->base, USB2_PHY_USB_PHY_CFG0, + UTMI_PHY_DATAPATH_CTRL_OVERRIDE_EN, + UTMI_PHY_DATAPATH_CTRL_OVERRIDE_EN); + /* set opmode to normal i.e. 0x0 & termsel to fs */ + msm_usb_write_readback(phy->base, USB2_PHY_USB_PHY_UTMI_CTRL0, + OPMODE_MASK, OPMODE_NORMAL); + msm_usb_write_readback(phy->base, USB2_PHY_USB_PHY_UTMI_CTRL0, + TERMSEL, TERMSEL); + /* set xcvrsel to fs */ + msm_usb_write_readback(phy->base, USB2_PHY_USB_PHY_UTMI_CTRL1, + XCVRSEL, XCVRSEL); + msleep(DP_PULSE_WIDTH_MSEC); + /* clear termsel to fs */ + msm_usb_write_readback(phy->base, USB2_PHY_USB_PHY_UTMI_CTRL0, + TERMSEL, 0x00); + /* clear xcvrsel */ + msm_usb_write_readback(phy->base, USB2_PHY_USB_PHY_UTMI_CTRL1, + XCVRSEL, 0x00); + /* clear utmi_phy_cmn_cntrl_override_en & + * utmi_phy_datapath_ctrl_override_en + */ + msm_usb_write_readback(phy->base, USB2_PHY_USB_PHY_CFG0, + UTMI_PHY_CMN_CTRL_OVERRIDE_EN, 0x00); + msm_usb_write_readback(phy->base, USB2_PHY_USB_PHY_CFG0, + UTMI_PHY_DATAPATH_CTRL_OVERRIDE_EN, 0x00); + + msleep(20); + + msm_hsphy_enable_clocks(phy, false); + ret = msm_hsphy_enable_power(phy, false); + if (ret < 0) { + dev_dbg(phy->phy.dev, + "dpdm regulator disable failed:%d\n", ret); + } + + return 0; +} + static int msm_hsphy_dpdm_regulator_enable(struct regulator_dev *rdev) { int ret = 0; @@ -827,6 +889,7 @@ static int msm_hsphy_probe(struct platform_device *pdev) phy->phy.notify_connect = msm_hsphy_notify_connect; phy->phy.notify_disconnect = msm_hsphy_notify_disconnect; phy->phy.type = USB_PHY_TYPE_USB2; + phy->phy.charger_detect = usb_phy_drive_dp_pulse; ret = usb_add_phy_dev(&phy->phy); if (ret) diff --git a/include/linux/usb/dwc3-msm.h b/include/linux/usb/dwc3-msm.h index 6762da8c2c5f..1b224cfb71b3 100644 --- a/include/linux/usb/dwc3-msm.h +++ b/include/linux/usb/dwc3-msm.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. */ #ifndef __LINUX_USB_DWC3_MSM_H @@ -115,14 +115,6 @@ struct gsi_channel_info { struct usb_gsi_request *ch_req; }; -#if IS_ENABLED(CONFIG_MSM_QUSB_PHY) -extern void usb_phy_drive_dp_pulse(void *phy, - unsigned int interval_ms); -#else -static inline void usb_phy_drive_dp_pulse(void *phy, unsigned int interval_ms) -{ } -#endif - #if IS_ENABLED(CONFIG_USB_DWC3_MSM) struct usb_ep *usb_ep_autoconfig_by_name(struct usb_gadget *gadget, struct usb_endpoint_descriptor *desc, const char *ep_name);