aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Baryshkov <dmitry.baryshkov@linaro.org>2021-04-01 19:35:46 +0300
committerBryan O'Donoghue <bryan.odonoghue@linaro.org>2023-01-31 00:49:31 +0000
commitfe9cc58c128efd7eccb8df81f6322ceb9e98731a (patch)
tree6bc66df73113c5b16bf07ec589bcd4ea388dbbf6
parent671d98b6228c2066f0c08aacd46665f23a04cd58 (diff)
phy: qcom-qmp: Register as a typec switch for orientation detectionpm8150b-tcpm
The lane select switch for USB typec orientation is within the USB QMP PHY. the current device. It could be connected through an endpoint, to an independent device handling the typec detection, ie the QCOM SPMI typec driver. bod: Fixed the logic qcom_qmp_phy_typec_switch_set() to disable phy on disconnect if and only if we have initialized the PHY. Retained CC orientation logic in qcom_qmp_phy_com_init() to simplify patch. Co-developed-by: Wesley Cheng <wcheng@codeaurora.org> Signed-off-by: Wesley Cheng <wcheng@codeaurora.org> Co-developed-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org> Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
-rw-r--r--drivers/phy/qualcomm/Kconfig8
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-combo.c67
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-usb.c10
3 files changed, 81 insertions, 4 deletions
diff --git a/drivers/phy/qualcomm/Kconfig b/drivers/phy/qualcomm/Kconfig
index eb9ddc685b38..a57ce3618c23 100644
--- a/drivers/phy/qualcomm/Kconfig
+++ b/drivers/phy/qualcomm/Kconfig
@@ -59,6 +59,14 @@ config PHY_QCOM_QMP
Enable this to support the QMP PHY transceiver that is used
with controllers such as PCIe, UFS, and USB on Qualcomm chips.
+config PHY_QCOM_QMP_TYPEC
+ def_bool PHY_QCOM_QMP=y && TYPEC=y || PHY_QCOM_QMP=m && TYPEC
+ help
+ Register a type C switch from the QMP PHY driver for type C
+ orientation support. This has dependencies with if the type C kernel
+ configuration is enabled or not. This support will not be present if
+ USB type C is disabled.
+
config PHY_QCOM_QUSB2
tristate "Qualcomm QUSB2 PHY Driver"
depends on OF && (ARCH_QCOM || COMPILE_TEST)
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
index 1f022e580407..dfb9214dcef5 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
@@ -62,6 +62,10 @@
/* 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 {
@@ -912,6 +916,9 @@ struct qmp_combo {
struct clk_fixed_rate pipe_clk_fixed;
struct clk_hw dp_link_hw;
struct clk_hw dp_pixel_hw;
+
+ struct typec_switch_dev *sw;
+ enum typec_orientation orientation;
};
static void qmp_v3_dp_aux_init(struct qmp_combo *qmp);
@@ -1384,7 +1391,9 @@ static void qmp_v3_configure_dp_tx(struct qmp_combo *qmp)
static bool qmp_combo_configure_dp_mode(struct qmp_combo *qmp)
{
u32 val;
- bool reverse = false;
+ bool reverse = qmp->orientation == TYPEC_ORIENTATION_REVERSE;
+ const struct phy_configure_opts_dp *dp_opts = &qphy->dp_opts;
+ struct qcom_qmp *qmp = qphy->qmp;
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;
@@ -1403,10 +1412,18 @@ static bool qmp_combo_configure_dp_mode(struct qmp_combo *qmp)
* if (orientation == ORIENTATION_CC2)
* writel(0x4c, qmp->dp_dp_phy + QSERDES_V3_DP_PHY_MODE);
*/
+ 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;
+
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, qphy->pcs + QSERDES_DP_PHY_MODE);
+ else
+ writel(0x5c, qphy->pcs + QSERDES_DP_PHY_MODE);
return reverse;
}
@@ -2669,6 +2686,52 @@ static struct phy *qmp_combo_phy_xlate(struct device *dev, struct of_phandle_arg
return ERR_PTR(-EINVAL);
}
+#if IS_ENABLED(CONFIG_PHY_QCOM_QMP_TYPEC)
+static int qcom_qmp_phy_typec_switch_set(struct typec_switch_dev *sw,
+ enum typec_orientation orientation)
+{
+ struct qcom_qmp *qmp = typec_switch_get_drvdata(sw);
+ struct qmp_phy *qphy = qmp->phys[0];
+
+ dev_dbg(qmp->dev, "Toggling orientation current %d requested %d\n",
+ qmp->orientation, orientation);
+
+ qmp->orientation = orientation;
+
+ if (orientation == TYPEC_ORIENTATION_NONE) {
+ if (qmp->init_count)
+ qcom_qmp_phy_power_off(qphy->phy);
+ } else {
+ if (!qmp->init_count)
+ qcom_qmp_phy_power_on(qphy->phy);
+ }
+
+ return 0;
+}
+
+static int qcom_qmp_phy_typec_switch_register(struct qcom_qmp *qmp, const struct qmp_phy_cfg *cfg)
+{
+ struct typec_switch_desc sw_desc;
+ struct device *dev = qmp->dev;
+
+ sw_desc.drvdata = qmp;
+ sw_desc.fwnode = dev->fwnode;
+ sw_desc.set = qcom_qmp_phy_typec_switch_set;
+ qmp->sw = typec_switch_register(dev, &sw_desc);
+ if (IS_ERR(qmp->sw)) {
+ dev_err(dev, "Error registering typec switch: %ld\n",
+ PTR_ERR(qmp->sw));
+ }
+
+ return 0;
+}
+#else
+static int qcom_qmp_phy_typec_switch_register(struct qcom_qmp *qmp, const struct qmp_phy_cfg *cfg)
+{
+ return 0;
+}
+#endif
+
static int qmp_combo_probe(struct platform_device *pdev)
{
struct qmp_combo *qmp;
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usb.c b/drivers/phy/qualcomm/phy-qcom-qmp-usb.c
index a49711c5a63d..ce44d3a23130 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-usb.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-usb.c
@@ -19,6 +19,7 @@
#include <linux/regulator/consumer.h>
#include <linux/reset.h>
#include <linux/slab.h>
+#include <linux/usb/typec_mux.h>
#include "phy-qcom-qmp.h"
#include "phy-qcom-qmp-pcs-misc-v3.h"
@@ -2015,8 +2016,11 @@ static int qmp_usb_init(struct phy *phy)
SW_DPPHY_RESET_MUX | SW_DPPHY_RESET |
SW_USB3PHY_RESET_MUX | SW_USB3PHY_RESET);
- /* Default type-c orientation, i.e CC1 */
- qphy_setbits(dp_com, QPHY_V3_DP_COM_TYPEC_CTRL, 0x02);
+ /* Latch CC orientation based on reported state by TCPM */
+ val = SW_PORTSELECT_MUX;
+ if (qmp->orientation == TYPEC_ORIENTATION_REVERSE)
+ val |= SW_PORTSELECT_VAL;
+ qphy_setbits(dp_com, QPHY_V3_DP_COM_TYPEC_CTRL, val);
qphy_setbits(dp_com, QPHY_V3_DP_COM_PHY_MODE_CTRL,
USB3_MODE | DP_MODE);
@@ -2571,6 +2575,8 @@ static int qmp_usb_probe(struct platform_device *pdev)
phy_set_drvdata(qmp->phy, qmp);
of_node_put(np);
+ if (cfg->has_phy_dp_com_ctrl)
+ qcom_qmp_phy_typec_switch_register(qmp, cfg);
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);