Skip to content

Commit

Permalink
phy: qcom-qmp: Register as a typec switch for orientation detection
Browse files Browse the repository at this point in the history
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.

bod: Ported from earlier version of driver to phy-qcom-qmp-combo.c

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>
  • Loading branch information
lumag authored and intel-lab-lkp committed Mar 18, 2023
1 parent 99b585d commit 76d1e35
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 4 deletions.
8 changes: 8 additions & 0 deletions drivers/phy/qualcomm/Kconfig
Expand Up @@ -101,6 +101,14 @@ config PHY_QCOM_QMP_USB

endif # PHY_QCOM_QMP

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)
Expand Down
80 changes: 76 additions & 4 deletions drivers/phy/qualcomm/phy-qcom-qmp-combo.c
Expand Up @@ -19,6 +19,7 @@
#include <linux/regulator/consumer.h>
#include <linux/reset.h>
#include <linux/slab.h>
#include <linux/usb/typec_mux.h>

#include <dt-bindings/phy/phy-qcom-qmp.h>

Expand Down Expand Up @@ -63,6 +64,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 {
Expand Down Expand Up @@ -1323,6 +1328,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);
Expand Down Expand Up @@ -1970,7 +1978,8 @@ 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 = &qmp->dp_opts;

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;
Expand All @@ -1989,10 +1998,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, qmp->pcs + QSERDES_DP_PHY_MODE);
else
writel(0x5c, qmp->pcs + QSERDES_DP_PHY_MODE);

return reverse;
}
Expand Down Expand Up @@ -2476,6 +2493,7 @@ static int qmp_combo_com_init(struct qmp_combo *qmp)
{
const struct qmp_phy_cfg *cfg = qmp->cfg;
void __iomem *com = qmp->com;
u32 val;
int ret;

mutex_lock(&qmp->phy_mutex);
Expand Down Expand Up @@ -2513,8 +2531,11 @@ static int qmp_combo_com_init(struct qmp_combo *qmp)
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);
/* 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(com, QPHY_V3_DP_COM_TYPEC_CTRL, val);

qphy_setbits(com, QPHY_V3_DP_COM_PHY_MODE_CTRL, USB3_MODE | DP_MODE);

Expand Down Expand Up @@ -3353,6 +3374,53 @@ 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 qmp_combo_typec_switch_set(struct typec_switch_dev *sw,
enum typec_orientation orientation)
{
struct qmp_combo *qmp = typec_switch_get_drvdata(sw);
struct phy *dp_phy = qmp->dp_phy;
int ret = 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)
ret = qmp_combo_dp_power_off(dp_phy);
} else {
if (!qmp->init_count)
ret = qmp_combo_dp_power_on(dp_phy);
}

return 0;
}

static int qmp_combo_typec_switch_register(struct qmp_combo *qmp)
{
struct typec_switch_desc sw_desc;
struct device *dev = qmp->dev;

sw_desc.drvdata = qmp;
sw_desc.fwnode = dev->fwnode;
sw_desc.set = qmp_combo_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 qmp_combo_typec_switch_register(struct qmp_combo *qmp)
{
return 0;
}
#endif

static int qmp_combo_probe(struct platform_device *pdev)
{
struct qmp_combo *qmp;
Expand Down Expand Up @@ -3443,6 +3511,10 @@ static int qmp_combo_probe(struct platform_device *pdev)
else
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);

ret = qmp_combo_typec_switch_register(qmp);
if (ret)
goto err_node_put;

of_node_put(usb_np);
of_node_put(dp_np);

Expand Down

0 comments on commit 76d1e35

Please sign in to comment.