Read the USB-C cable orientation from the orientation-gpios
property on the qcom,pmic-glink node and use it when programming
the TypeC port-select mux.

Taken from Linux commit 815891eee668 ("phy: qcom-qmp-combo: Introduce 
orientation variable")

Previously the driver always set SW_PORTSELECT_MUX without
accounting for cable orientation, so the SuperSpeed/DP lanes could
be routed to the wrong side of the connector on boards where the
cable was flipped. Now orientation is read once during DT parsing
and SW_PORTSELECT_VAL is added to the mux value when a reversed
orientation is detected.

Tested on QCS6490 RB3 Gen2 board.

Signed-off-by: Balaji Selvanathan <[email protected]>
---
 drivers/phy/qcom/phy-qcom-qmp-combo.c | 35 +++++++++++++++++++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/drivers/phy/qcom/phy-qcom-qmp-combo.c 
b/drivers/phy/qcom/phy-qcom-qmp-combo.c
index 0d63e482ee4..615d481513f 100644
--- a/drivers/phy/qcom/phy-qcom-qmp-combo.c
+++ b/drivers/phy/qcom/phy-qcom-qmp-combo.c
@@ -7,10 +7,12 @@
 #include <dm.h>
 #include <dm/device_compat.h>
 #include <dm/devres.h>
+#include <dm/ofnode.h>
 #include <generic-phy.h>
 #include <reset.h>
 #include <power/regulator.h>
 #include <asm/io.h>
+#include <asm-generic/gpio.h>
 #include <linux/bitops.h>
 #include <linux/compat.h>
 #include <linux/delay.h>
@@ -39,6 +41,7 @@
 #define DP_MODE                                 BIT(1) /* enables DP mode */
 
 /* QPHY_V3_DP_COM_TYPEC_CTRL register bits */
+#define SW_PORTSELECT_VAL                       BIT(0)
 #define SW_PORTSELECT_MUX                       BIT(1)
 
 /* PHY slot identifiers for device tree phandle arguments */
@@ -238,6 +241,7 @@ struct qmp_combo {
        struct udevice **vregs;
        int num_vregs;
        const struct qmp_phy_cfg *cfg;
+       bool orientation_reversed;
 };
 
 static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val)
@@ -333,6 +337,8 @@ static int qmp_combo_com_init(struct qmp_combo *qmp)
                     SW_USB3PHY_RESET_MUX | SW_USB3PHY_RESET);
 
        val = SW_PORTSELECT_MUX;
+       if (qmp->orientation_reversed)
+               val |= SW_PORTSELECT_VAL;
        writel(val, com + QPHY_V3_DP_COM_TYPEC_CTRL);
 
        writel(USB3_MODE | DP_MODE, com + QPHY_V3_DP_COM_PHY_MODE_CTRL);
@@ -521,6 +527,33 @@ static int qmp_combo_vreg_init(struct qmp_combo *qmp)
        return 0;
 }
 
+/*
+ * The orientation of the USB-C connector on this platform is reported by a
+ * single GPIO exposed on the "qcom,pmic-glink" node ("orientation-gpios").
+ * Read it once here so the port-select mux can be programmed to
+ * match physical cable orientation.
+ */
+static bool qmp_combo_read_orientation(void)
+{
+       ofnode node;
+       struct gpio_desc desc;
+       int ret, val;
+
+       node = ofnode_by_compatible(ofnode_null(), "qcom,pmic-glink");
+       if (!ofnode_valid(node))
+               return false;
+
+       ret = gpio_request_by_name_nodev(node, "orientation-gpios", 0,
+                                        &desc, GPIOD_IS_IN);
+       if (ret)
+               return false;
+
+       val = dm_gpio_get_value(&desc);
+       dm_gpio_free(desc.dev, &desc);
+
+       return val > 0;
+}
+
 static int qmp_combo_parse_dt(struct qmp_combo *qmp)
 {
        const struct qmp_phy_cfg *cfg = qmp->cfg;
@@ -536,6 +569,8 @@ static int qmp_combo_parse_dt(struct qmp_combo *qmp)
        if (IS_ERR(base))
                return PTR_ERR(base);
 
+       qmp->orientation_reversed = qmp_combo_read_orientation();
+
        qmp->com = base + offs->com;
        qmp->serdes = base + offs->usb3_serdes;
        qmp->tx = base + offs->txa;

---
base-commit: d7ef23c07b8e34f65b3e15e3b4e7f58d074923c8
change-id: 20260724-kodiak_ss_orientation-b171351c78b7

Best regards,
-- 
Balaji Selvanathan <[email protected]>

Reply via email to