Merge "usb: phy: qusb: Make sure QUSB PHY is into proper state"
This commit is contained in:
commit
bf9bb2a461
1 changed files with 74 additions and 12 deletions
|
@ -109,6 +109,7 @@ struct qusb_phy {
|
|||
void __iomem *base;
|
||||
void __iomem *tune2_efuse_reg;
|
||||
void __iomem *ref_clk_base;
|
||||
void __iomem *tcsr_clamp_dig_n;
|
||||
|
||||
struct clk *ref_clk_src;
|
||||
struct clk *ref_clk;
|
||||
|
@ -147,6 +148,7 @@ struct qusb_phy {
|
|||
int phy_pll_reset_seq_len;
|
||||
int *emu_dcm_reset_seq;
|
||||
int emu_dcm_reset_seq_len;
|
||||
bool put_into_high_z_state;
|
||||
};
|
||||
|
||||
static void qusb_phy_enable_clocks(struct qusb_phy *qphy, bool on)
|
||||
|
@ -329,6 +331,47 @@ static int qusb_phy_update_dpdm(struct usb_phy *phy, int value)
|
|||
dev_dbg(phy->dev, "DP_DM_F: rm_pulldown:%d\n",
|
||||
qphy->rm_pulldown);
|
||||
}
|
||||
|
||||
if (qphy->put_into_high_z_state) {
|
||||
if (qphy->tcsr_clamp_dig_n)
|
||||
writel_relaxed(0x1,
|
||||
qphy->tcsr_clamp_dig_n);
|
||||
|
||||
qusb_phy_enable_clocks(qphy, true);
|
||||
|
||||
dev_dbg(phy->dev, "RESET QUSB PHY\n");
|
||||
ret = reset_control_assert(qphy->phy_reset);
|
||||
if (ret)
|
||||
dev_err(phy->dev, "phyassert failed\n");
|
||||
usleep_range(100, 150);
|
||||
ret = reset_control_deassert(qphy->phy_reset);
|
||||
if (ret)
|
||||
dev_err(phy->dev, "deassert failed\n");
|
||||
|
||||
/*
|
||||
* Phy in non-driving mode leaves Dp and Dm
|
||||
* lines in high-Z state. Controller power
|
||||
* collapse is not switching phy to non-driving
|
||||
* mode causing charger detection failure. Bring
|
||||
* phy to non-driving mode by overriding
|
||||
* controller output via UTMI interface.
|
||||
*/
|
||||
writel_relaxed(TERM_SELECT | XCVR_SELECT_FS |
|
||||
OP_MODE_NON_DRIVE,
|
||||
qphy->base + QUSB2PHY_PORT_UTMI_CTRL1);
|
||||
writel_relaxed(UTMI_ULPI_SEL |
|
||||
UTMI_TEST_MUX_SEL,
|
||||
qphy->base + QUSB2PHY_PORT_UTMI_CTRL2);
|
||||
|
||||
/* Disable PHY */
|
||||
writel_relaxed(CLAMP_N_EN | FREEZIO_N |
|
||||
POWER_DOWN,
|
||||
qphy->base + QUSB2PHY_PORT_POWERDOWN);
|
||||
/* Make sure that above write is completed */
|
||||
wmb();
|
||||
|
||||
qusb_phy_enable_clocks(qphy, false);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -337,6 +380,9 @@ static int qusb_phy_update_dpdm(struct usb_phy *phy, int value)
|
|||
dev_dbg(phy->dev, "POWER_SUPPLY_DP_DM_DPR_DMR\n");
|
||||
if (qphy->rm_pulldown) {
|
||||
if (!qphy->cable_connected) {
|
||||
if (qphy->tcsr_clamp_dig_n)
|
||||
writel_relaxed(0x0,
|
||||
qphy->tcsr_clamp_dig_n);
|
||||
dev_dbg(phy->dev, "turn off for HVDCP case\n");
|
||||
ret = qusb_phy_enable_power(qphy, false);
|
||||
}
|
||||
|
@ -647,22 +693,23 @@ static int qusb_phy_set_suspend(struct usb_phy *phy, int suspend)
|
|||
/* Disable all interrupts */
|
||||
writel_relaxed(0x00,
|
||||
qphy->base + QUSB2PHY_PORT_INTR_CTRL);
|
||||
/*
|
||||
* Phy in non-driving mode leaves Dp and Dm lines in
|
||||
* high-Z state. Controller power collapse is not
|
||||
* switching phy to non-driving mode causing charger
|
||||
* detection failure. Bring phy to non-driving mode by
|
||||
* overriding controller output via UTMI interface.
|
||||
*/
|
||||
writel_relaxed(TERM_SELECT | XCVR_SELECT_FS |
|
||||
OP_MODE_NON_DRIVE,
|
||||
qphy->base + QUSB2PHY_PORT_UTMI_CTRL1);
|
||||
writel_relaxed(UTMI_ULPI_SEL | UTMI_TEST_MUX_SEL,
|
||||
qphy->base + QUSB2PHY_PORT_UTMI_CTRL2);
|
||||
|
||||
/* Make sure that above write is completed */
|
||||
wmb();
|
||||
|
||||
qusb_phy_enable_clocks(qphy, false);
|
||||
if (qphy->tcsr_clamp_dig_n)
|
||||
writel_relaxed(0x0,
|
||||
qphy->tcsr_clamp_dig_n);
|
||||
qusb_phy_enable_power(qphy, false);
|
||||
/*
|
||||
* Set put_into_high_z_state to true so next USB
|
||||
* cable connect, DPF_DMF request performs PHY
|
||||
* reset and put it into high-z state. For bootup
|
||||
* with or without USB cable, it doesn't require
|
||||
* to put QUSB PHY into high-z state.
|
||||
*/
|
||||
qphy->put_into_high_z_state = true;
|
||||
}
|
||||
qphy->suspended = true;
|
||||
} else {
|
||||
|
@ -675,6 +722,9 @@ static int qusb_phy_set_suspend(struct usb_phy *phy, int suspend)
|
|||
qphy->base + QUSB2PHY_PORT_INTR_CTRL);
|
||||
} else {
|
||||
qusb_phy_enable_power(qphy, true);
|
||||
if (qphy->tcsr_clamp_dig_n)
|
||||
writel_relaxed(0x1,
|
||||
qphy->tcsr_clamp_dig_n);
|
||||
qusb_phy_enable_clocks(qphy, true);
|
||||
}
|
||||
qphy->suspended = false;
|
||||
|
@ -845,6 +895,18 @@ static int qusb_phy_probe(struct platform_device *pdev)
|
|||
}
|
||||
}
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
|
||||
"tcsr_clamp_dig_n_1p8");
|
||||
if (res) {
|
||||
qphy->tcsr_clamp_dig_n = devm_ioremap_nocache(dev,
|
||||
res->start, resource_size(res));
|
||||
if (IS_ERR(qphy->tcsr_clamp_dig_n)) {
|
||||
dev_err(dev, "err reading tcsr_clamp_dig_n\n");
|
||||
qphy->tcsr_clamp_dig_n = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
qphy->ref_clk_src = devm_clk_get(dev, "ref_clk_src");
|
||||
if (IS_ERR(qphy->ref_clk_src))
|
||||
dev_dbg(dev, "clk get failed for ref_clk_src\n");
|
||||
|
|
Loading…
Add table
Reference in a new issue