mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-08 21:11:14 -04:00
usb: dwc3: Drive a pulse on DP on CDP detection
Some USB host PCs switch the downstream port mode from CDP to SDP if the device does not pull DP up within certain duration (~2s). This limits the current drawn by the device to 500mA(or 900mA) as opposed to the possible 1.5A resulting in slow charging of the battery. Fix this by driving a DP pulse when there is a connect notification from PMIC and detected the charger type as CDP. Change-Id: I7655a0812ba85bdc29fc4f66d4675717f5b4cd8f Signed-off-by: Elson Roy Serrao <eserrao@codeaurora.org>
This commit is contained in:
parent
629f831242
commit
2882ba56b9
4 changed files with 73 additions and 15 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 <linux/module.h>
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in a new issue