phy: qcom: qmp-usbc: handle CLAMP register in a correct way
authorDmitry Baryshkov <dmitry.baryshkov@linaro.org>
Wed, 17 Jan 2024 14:04:24 +0000 (16:04 +0200)
committerVinod Koul <vkoul@kernel.org>
Tue, 23 Jan 2024 14:10:30 +0000 (19:40 +0530)
The QMP USB PHYs on msm8998, qcm2290 and some other platforms don't have
the PCS_MISC_CLAMP_ENABLE register. Instead they need to toggle the
register in the TCSR space. Make the new phy-qcom-qmp-usbc driver
correctly handle the clamp register.

Fixes: a51969fafc82 ("phy: qcom-qmp: Add QMP V3 USB3 PHY support for msm8998")
Fixes: 8abe5e778b2c ("phy: qcom-qmp: Add QCM2290 USB3 PHY support")
Cc: Jeffrey Hugo <quic_jhugo@quicinc.com>
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Acked-by: Konrad Dybcio <konrad.dybcio@linaro.org>
Link: https://lore.kernel.org/r/20240117-usbc-phy-vls-clamp-v2-3-a950c223f10f@linaro.org
Signed-off-by: Vinod Koul <vkoul@kernel.org>
drivers/phy/qualcomm/phy-qcom-qmp-usbc.c

index 214cf4203de415ec21f3da58545a03cf615ddeec..3a4b4849db0f5e092726b2ae729a6b5b77b1b40b 100644 (file)
 #include <linux/io.h>
 #include <linux/iopoll.h>
 #include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/phy/phy.h>
 #include <linux/platform_device.h>
+#include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
 #include <linux/reset.h>
 #include <linux/slab.h>
@@ -56,9 +58,6 @@
 /* QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR register bits */
 #define IRQ_CLEAR                              BIT(0)
 
-/* QPHY_V3_PCS_MISC_CLAMP_ENABLE register bits */
-#define CLAMP_EN                               BIT(0) /* enables i/o clamp_n */
-
 #define PHY_INIT_COMPLETE_TIMEOUT              10000
 
 struct qmp_phy_init_tbl {
@@ -94,7 +93,6 @@ enum qphy_reg_layout {
        QPHY_PCS_AUTONOMOUS_MODE_CTRL,
        QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR,
        QPHY_PCS_POWER_DOWN_CONTROL,
-       QPHY_PCS_MISC_CLAMP_ENABLE,
        /* Keep last to ensure regs_layout arrays are properly initialized */
        QPHY_LAYOUT_SIZE
 };
@@ -106,7 +104,6 @@ static const unsigned int qmp_v3_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = {
        [QPHY_PCS_AUTONOMOUS_MODE_CTRL] = QPHY_V3_PCS_AUTONOMOUS_MODE_CTRL,
        [QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR] = QPHY_V3_PCS_LFPS_RXTERM_IRQ_CLEAR,
        [QPHY_PCS_POWER_DOWN_CONTROL]   = QPHY_V3_PCS_POWER_DOWN_CONTROL,
-       [QPHY_PCS_MISC_CLAMP_ENABLE]    = QPHY_V3_PCS_MISC_CLAMP_ENABLE,
 };
 
 static const unsigned int qmp_v3_usb3phy_regs_layout_qcm2290[QPHY_LAYOUT_SIZE] = {
@@ -369,6 +366,9 @@ struct qmp_usbc {
        void __iomem *tx2;
        void __iomem *rx2;
 
+       struct regmap *tcsr_map;
+       u32 vls_clamp_reg;
+
        struct clk *pipe_clk;
        struct clk_bulk_data *clks;
        int num_clks;
@@ -691,7 +691,6 @@ static void qmp_usbc_enable_autonomous_mode(struct qmp_usbc *qmp)
 {
        const struct qmp_phy_cfg *cfg = qmp->cfg;
        void __iomem *pcs = qmp->pcs;
-       void __iomem *pcs_misc = qmp->pcs_misc;
        u32 intr_mask;
 
        if (qmp->mode == PHY_MODE_USB_HOST_SS ||
@@ -712,19 +711,18 @@ static void qmp_usbc_enable_autonomous_mode(struct qmp_usbc *qmp)
        qphy_setbits(pcs, cfg->regs[QPHY_PCS_AUTONOMOUS_MODE_CTRL], intr_mask);
 
        /* Enable i/o clamp_n for autonomous mode */
-       if (pcs_misc && cfg->regs[QPHY_PCS_MISC_CLAMP_ENABLE])
-               qphy_clrbits(pcs_misc, cfg->regs[QPHY_PCS_MISC_CLAMP_ENABLE], CLAMP_EN);
+       if (qmp->tcsr_map && qmp->vls_clamp_reg)
+               regmap_write(qmp->tcsr_map, qmp->vls_clamp_reg, 1);
 }
 
 static void qmp_usbc_disable_autonomous_mode(struct qmp_usbc *qmp)
 {
        const struct qmp_phy_cfg *cfg = qmp->cfg;
        void __iomem *pcs = qmp->pcs;
-       void __iomem *pcs_misc = qmp->pcs_misc;
 
        /* Disable i/o clamp_n on resume for normal mode */
-       if (pcs_misc && cfg->regs[QPHY_PCS_MISC_CLAMP_ENABLE])
-               qphy_setbits(pcs_misc, cfg->regs[QPHY_PCS_MISC_CLAMP_ENABLE], CLAMP_EN);
+       if (qmp->tcsr_map && qmp->vls_clamp_reg)
+               regmap_write(qmp->tcsr_map, qmp->vls_clamp_reg, 0);
 
        qphy_clrbits(pcs, cfg->regs[QPHY_PCS_AUTONOMOUS_MODE_CTRL],
                     ARCVR_DTCT_EN | ARCVR_DTCT_EVENT_SEL | ALFPS_DTCT_EN);
@@ -1063,6 +1061,30 @@ static int qmp_usbc_parse_dt(struct qmp_usbc *qmp)
        return 0;
 }
 
+static int qmp_usbc_parse_vls_clamp(struct qmp_usbc *qmp)
+{
+       struct of_phandle_args tcsr_args;
+       struct device *dev = qmp->dev;
+       int ret;
+
+       /*  for backwards compatibility ignore if there is no property */
+       ret = of_parse_phandle_with_fixed_args(dev->of_node, "qcom,tcsr-reg", 1, 0,
+                                              &tcsr_args);
+       if (ret == -ENOENT)
+               return 0;
+       else if (ret < 0)
+               return dev_err_probe(dev, ret, "Failed to parse qcom,tcsr-reg\n");
+
+       qmp->tcsr_map = syscon_node_to_regmap(tcsr_args.np);
+       of_node_put(tcsr_args.np);
+       if (IS_ERR(qmp->tcsr_map))
+               return PTR_ERR(qmp->tcsr_map);
+
+       qmp->vls_clamp_reg = tcsr_args.args[0];
+
+       return 0;
+}
+
 static int qmp_usbc_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
@@ -1093,6 +1115,10 @@ static int qmp_usbc_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
+       ret = qmp_usbc_parse_vls_clamp(qmp);
+       if (ret)
+               return ret;
+
        /* Check for legacy binding with child node. */
        np = of_get_child_by_name(dev->of_node, "phy");
        if (np) {