mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-08 21:22:09 -04:00
usb: phy: 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: I76ac4c33dbbc538f5cb680fd1b5c15f8fb3bfe50 Signed-off-by: Sriharsha Allenki <sallenki@codeaurora.org> Signed-off-by: Udipto Goswami <ugoswami@codeaurora.org>
This commit is contained in:
parent
2882ba56b9
commit
ef4e7c17dd
2 changed files with 93 additions and 1 deletions
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -22,6 +22,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)
|
||||
|
||||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue