From 016b6c5734af191cda98571d7e8974de5e9dafd9 Mon Sep 17 00:00:00 2001 From: William Wu Date: Mon, 19 Jul 2021 12:08:32 +0800 Subject: [PATCH] phy: rockchip-naneng-usb2: keep utmi clk on during charge detection When do charge detection, the phy specification suggests that it needs to holds the phy in reset state to avoid USB data communication. However, the utmi clk60_30 will be disabled at the same time, that's causing a synchronization issue between the phy and the USB controller. I test on RV1126 EVB Linux SDK, do usb device hot plug test quickly. The USB dwc3 controller may fail to enable ep0 because of no clk60_30 is supplied by the phy. This patch sets the phy utmi in normal mode by GRF to keeps the utmi clk on for USB controller. Signed-off-by: William Wu Change-Id: I8958a491130faeb9ac361b8639e4c3d3190fad1b --- .../phy/rockchip/phy-rockchip-naneng-usb2.c | 58 ++++++++++++++++--- 1 file changed, 50 insertions(+), 8 deletions(-) diff --git a/drivers/phy/rockchip/phy-rockchip-naneng-usb2.c b/drivers/phy/rockchip/phy-rockchip-naneng-usb2.c index 7580e5cc85b7..924b316ef6d2 100644 --- a/drivers/phy/rockchip/phy-rockchip-naneng-usb2.c +++ b/drivers/phy/rockchip/phy-rockchip-naneng-usb2.c @@ -109,6 +109,7 @@ struct rockchip_chg_det_reg { * @ls_det_en: linestate detection enable register. * @ls_det_st: linestate detection state register. * @ls_det_clr: linestate detection clear register. + * @phy_chg_mode: set phy in charge detection mode. * @phy_sus: phy suspend register. * @utmi_bvalid: utmi vbus bvalid status register. * @utmi_iddig: otg port id pin status register. @@ -140,6 +141,7 @@ struct rockchip_usb2phy_port_cfg { struct usb2phy_reg ls_det_en; struct usb2phy_reg ls_det_st; struct usb2phy_reg ls_det_clr; + struct usb2phy_reg phy_chg_mode; struct usb2phy_reg phy_sus; struct usb2phy_reg utmi_bvalid; struct usb2phy_reg utmi_iddig; @@ -796,12 +798,45 @@ static void rockchip_chg_detect(struct rockchip_usb2phy *rphy, struct rockchip_usb2phy_port *rport) { bool chg_valid, phy_connect; - int result; - int cnt; + const struct usb2phy_reg *phy_sus_reg; + unsigned int phy_sus_cfg, mask; + int result, cnt, ret; mutex_lock(&rport->mutex); - reset_control_assert(rphy->reset); + /* + * We are violating what the phy specification says about + * the charge detection process. Ideally we need to hold + * the phy in the reset state during the charge detection + * process, but that's causing trouble synchronizing between + * the phy and usb controller because CLK60_30 is disabled + * while phy in reset. + * + * We have discussed this with the phy IP Provider, and + * it was suggested to keep the CLK60_30 while do charging + * detection. + * + * Set the phy in charge mode (keep the CLK60_30): + * Enable the DP/DM pulldown resistor; + * Set the opmode to non-driving mode; + * Set the phy controlled by GRF utmi interface, and set + * the utmi in normal mode to keep the CLK60_30. + */ + phy_sus_reg = &rport->port_cfg->phy_sus; + ret = regmap_read(rphy->grf, phy_sus_reg->offset, &phy_sus_cfg); + if (ret) { + dev_err(&rport->phy->dev, + "Fail to read phy_sus reg offset 0x%x, ret %d\n", + phy_sus_reg->offset, ret); + goto unlock; + } + + ret = property_enable(rphy->grf, &rport->port_cfg->phy_chg_mode, true); + if (ret) { + dev_err(&rport->phy->dev, + "Fail to set phy_chg_mode reg, ret %d\n", ret); + goto unlock; + } /* CHG_RST is set to 1'b0 to start charge detection */ property_enable(rphy->grf, &rphy->phy_cfg->chg_det.chg_en, true); @@ -841,15 +876,21 @@ static void rockchip_chg_detect(struct rockchip_usb2phy *rphy, dev_info(&rport->phy->dev, "charger = %s\n", chg_to_string(rphy->chg_type)); - usleep_range(1000, 1100); - reset_control_deassert(rphy->reset); - /* waiting for the utmi_clk to become stable */ - usleep_range(2500, 3000); - /* disable the chg detection module */ property_enable(rphy->grf, &rphy->phy_cfg->chg_det.chg_rst, true); property_enable(rphy->grf, &rphy->phy_cfg->chg_det.chg_en, false); + mask = GENMASK(phy_sus_reg->bitend, phy_sus_reg->bitstart); + /* Restore the phy suspend configuration */ + ret = regmap_write(rphy->grf, phy_sus_reg->offset, + ((phy_sus_cfg << phy_sus_reg->bitstart) | + (mask << BIT_WRITEABLE_SHIFT))); + if (ret) + dev_err(&rport->phy->dev, + "Fail to set phy_sus reg offset 0x%x, ret %d\n", + phy_sus_reg->offset, ret); + +unlock: mutex_unlock(&rport->mutex); } @@ -1860,6 +1901,7 @@ static const struct rockchip_usb2phy_cfg rv1126_phy_cfgs[] = { .ls_det_en = { 0x10300, 0, 0, 0, 1 }, .ls_det_st = { 0x10304, 0, 0, 0, 1 }, .ls_det_clr = { 0x10308, 0, 0, 0, 1 }, + .phy_chg_mode = { 0x10230, 8, 0, 0x052, 0x1d7 }, .phy_sus = { 0x10230, 8, 0, 0x052, 0x1d5 }, .utmi_bvalid = { 0x10248, 9, 9, 0, 1 }, .utmi_iddig = { 0x10248, 6, 6, 0, 1 },