On SoCs like MSM8953 the fixed "se_clk_scheme_default" variable does not reflect the correct value for that SoC, so support reading the correct value from TCSR.
The code was adapted from the Linux driver. Signed-off-by: Luca Weiss <[email protected]> --- drivers/phy/qcom/Kconfig | 1 + drivers/phy/qcom/phy-qcom-qusb2.c | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/drivers/phy/qcom/Kconfig b/drivers/phy/qcom/Kconfig index 1fdadaccb12..ff85efeec32 100644 --- a/drivers/phy/qcom/Kconfig +++ b/drivers/phy/qcom/Kconfig @@ -35,6 +35,7 @@ config PHY_QCOM_QMP_UFS config PHY_QCOM_QUSB2 bool "Qualcomm USB QUSB2 PHY driver" depends on PHY && ARCH_SNAPDRAGON + depends on SYSCON help Enable this to support the Super-Speed USB transceiver on various Qualcomm chipsets. diff --git a/drivers/phy/qcom/phy-qcom-qusb2.c b/drivers/phy/qcom/phy-qcom-qusb2.c index a6c1095f412..01e64542c89 100644 --- a/drivers/phy/qcom/phy-qcom-qusb2.c +++ b/drivers/phy/qcom/phy-qcom-qusb2.c @@ -11,7 +11,9 @@ #include <generic-phy.h> #include <linux/bitops.h> #include <linux/delay.h> +#include <regmap.h> #include <reset.h> +#include <syscon.h> #include <dt-bindings/phy/phy-qcom-qusb2.h> @@ -318,6 +320,7 @@ static const struct qusb2_phy_cfg qusb2_v2_phy_cfg = { * * @cfg_ahb_clk: AHB2PHY interface clock * @phy_rst: phy reset control + * @tcsr: TCSR syscon register map * * @cfg: phy config data * @has_se_clk_scheme: indicate if PHY has single-ended ref clock scheme @@ -328,6 +331,7 @@ struct qusb2_phy { struct clk cfg_ahb_clk; struct reset_ctl phy_rst; + struct regmap *tcsr; const struct qusb2_phy_cfg *cfg; bool has_se_clk_scheme; @@ -369,6 +373,7 @@ static int qusb2phy_power_on(struct phy *phy) { struct qusb2_phy *qphy = dev_get_priv(phy->dev); const struct qusb2_phy_cfg *cfg = qphy->cfg; + unsigned int clk_scheme; int ret; u32 val; @@ -401,6 +406,31 @@ static int qusb2phy_power_on(struct phy *phy) */ qphy->has_se_clk_scheme = cfg->se_clk_scheme_default; + /* + * read TCSR_PHY_CLK_SCHEME register to check if single-ended + * clock scheme is selected. If yes, then disable differential + * ref_clk and use single-ended clock, otherwise use differential + * ref_clk only. + */ + if (qphy->tcsr) { + ret = regmap_read(qphy->tcsr, qphy->cfg->clk_scheme_offset, + &clk_scheme); + if (ret) { + printf("%s: failed to read clk scheme reg\n", __func__); + return ret; + } + + /* is it a differential clock scheme ? */ + if (!(clk_scheme & PHY_CLK_SCHEME_SEL)) { + debug("%s(): select differential clk\n", + __func__); + qphy->has_se_clk_scheme = false; + } else { + debug("%s(): select single-ended clk\n", + __func__); + } + } + if (cfg->has_pll_test) { if (!qphy->has_se_clk_scheme) val &= ~CLK_REF_SEL; @@ -488,6 +518,13 @@ static int qusb2phy_probe(struct udevice *dev) return -EINVAL; } + qphy->tcsr = syscon_regmap_lookup_by_phandle(dev, + "qcom,tcsr-syscon"); + if (IS_ERR(qphy->tcsr)) { + debug("%s: failed to lookup TCSR regmap\n", __func__); + qphy->tcsr = NULL; + } + debug("%s success qusb phy cfg %p\n", __func__, qphy->cfg); return 0; } -- 2.55.0

