#include <linux/regulator/consumer.h>
 #include <linux/reset.h>
 #include <linux/slab.h>
+#include <linux/usb/typec.h>
 
 #include <dt-bindings/phy/phy-qcom-qmp.h>
 
 /* QPHY_V3_PCS_MISC_CLAMP_ENABLE register bits */
 #define CLAMP_EN                               BIT(0) /* enables i/o clamp_n */
 
+/* QPHY_V3_DP_COM_TYPEC_CTRL register bits */
+#define SW_PORTSELECT_VAL                      BIT(0)
+#define SW_PORTSELECT_MUX                      BIT(1)
+
 #define PHY_INIT_COMPLETE_TIMEOUT              10000
 
 struct qmp_phy_init_tbl {
        struct clk_fixed_rate pipe_clk_fixed;
        struct clk_hw dp_link_hw;
        struct clk_hw dp_pixel_hw;
+
+       enum typec_orientation orientation;
 };
 
 static void qmp_v3_dp_aux_init(struct qmp_combo *qmp);
 
 static bool qmp_combo_configure_dp_mode(struct qmp_combo *qmp)
 {
+       bool reverse = (qmp->orientation == TYPEC_ORIENTATION_REVERSE);
+       const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts;
        u32 val;
-       bool reverse = false;
 
        val = DP_PHY_PD_CTL_PWRDN | DP_PHY_PD_CTL_AUX_PWRDN |
              DP_PHY_PD_CTL_PLL_PWRDN | DP_PHY_PD_CTL_DP_CLAMP_EN;
 
-       /*
-        * TODO: Assume orientation is CC1 for now and two lanes, need to
-        * use type-c connector to understand orientation and lanes.
-        *
-        * Otherwise val changes to be like below if this code understood
-        * the orientation of the type-c cable.
-        *
-        * if (lane_cnt == 4 || orientation == ORIENTATION_CC2)
-        *      val |= DP_PHY_PD_CTL_LANE_0_1_PWRDN;
-        * if (lane_cnt == 4 || orientation == ORIENTATION_CC1)
-        *      val |= DP_PHY_PD_CTL_LANE_2_3_PWRDN;
-        * if (orientation == ORIENTATION_CC2)
-        *      writel(0x4c, qmp->dp_dp_phy + QSERDES_V3_DP_PHY_MODE);
-        */
-       val |= DP_PHY_PD_CTL_LANE_2_3_PWRDN;
+       if (dp_opts->lanes == 4 || reverse)
+               val |= DP_PHY_PD_CTL_LANE_0_1_PWRDN;
+       if (dp_opts->lanes == 4 || !reverse)
+               val |= DP_PHY_PD_CTL_LANE_2_3_PWRDN;
+
        writel(val, qmp->dp_dp_phy + QSERDES_DP_PHY_PD_CTL);
 
-       writel(0x5c, qmp->dp_dp_phy + QSERDES_DP_PHY_MODE);
+       if (reverse)
+               writel(0x4c, qmp->pcs + QSERDES_DP_PHY_MODE);
+       else
+               writel(0x5c, qmp->pcs + QSERDES_DP_PHY_MODE);
 
        return reverse;
 }
 
 static int qmp_v4_configure_dp_phy(struct qmp_combo *qmp)
 {
+       bool reverse = (qmp->orientation == TYPEC_ORIENTATION_REVERSE);
        const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts;
        u32 bias0_en, drvr0_en, bias1_en, drvr1_en;
-       bool reverse = false;
        u32 status;
        int ret;
 
 
 static int qmp_v5_configure_dp_phy(struct qmp_combo *qmp)
 {
+       bool reverse = (qmp->orientation == TYPEC_ORIENTATION_REVERSE);
        const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts;
        u32 bias0_en, drvr0_en, bias1_en, drvr1_en;
-       bool reverse = false;
        u32 status;
        int ret;
 
 
 static int qmp_v6_configure_dp_phy(struct qmp_combo *qmp)
 {
+       bool reverse = (qmp->orientation == TYPEC_ORIENTATION_REVERSE);
        const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts;
        u32 bias0_en, drvr0_en, bias1_en, drvr1_en;
-       bool reverse = false;
        u32 status;
        int ret;
 
        const struct qmp_phy_cfg *cfg = qmp->cfg;
        void __iomem *com = qmp->com;
        int ret;
+       u32 val;
 
        if (qmp->init_count++)
                return 0;
                        SW_DPPHY_RESET_MUX | SW_DPPHY_RESET |
                        SW_USB3PHY_RESET_MUX | SW_USB3PHY_RESET);
 
-       /* Default type-c orientation, i.e CC1 */
-       qphy_setbits(com, QPHY_V3_DP_COM_TYPEC_CTRL, 0x02);
-
-       qphy_setbits(com, QPHY_V3_DP_COM_PHY_MODE_CTRL, USB3_MODE | DP_MODE);
+       /* Use software based port select and switch on typec orientation */
+       val = SW_PORTSELECT_MUX;
+       if (qmp->orientation == TYPEC_ORIENTATION_REVERSE)
+               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);
 
        /* bring both QMP USB and QMP DP PHYs PCS block out of reset */
        qphy_clrbits(com, QPHY_V3_DP_COM_RESET_OVRD_CTRL,
 
        qmp->dev = dev;
 
+       qmp->orientation = TYPEC_ORIENTATION_NORMAL;
+
        qmp->cfg = of_device_get_match_data(dev);
        if (!qmp->cfg)
                return -EINVAL;