Add `qmp_phy_usbc_type` enum and a `type` field in `qmp_usbc` to distinguish between USB and DP PHYs.
- Introduce `qmp_phy_usbc_type` enum with USB and DP types. - Update device match table to associate compatible strings with type and config. - Wrap existing USB-specific logic with type checks to prepare for future DP support. No functional changes and serves as a preparatory step for adding DP PHY support. Signed-off-by: Xiangxu Yin <[email protected]> --- drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 195 ++++++++++++++++++++----------- 1 file changed, 126 insertions(+), 69 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c index 078752dbc66f9b9844c003e7755fff6466ea1d6c..647e2f54b744bf099ea667e672c606dd7aef3bcf 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c @@ -286,6 +286,16 @@ static const struct qmp_phy_init_tbl qcm2290_usb3_pcs_tbl[] = { QMP_PHY_INIT_CFG(QPHY_V3_PCS_RX_SIGDET_LVL, 0x88), }; +enum qmp_phy_usbc_type { + QMP_PHY_USBC_USB, + QMP_PHY_USBC_DP, +}; + +struct qmp_phy_cfg { + int type; + const void *cfg; +}; + struct qmp_usbc_usb_offsets { u16 serdes; u16 pcs; @@ -454,23 +464,40 @@ static const struct qmp_phy_usb_cfg sdm660_usb3phy_cfg = { .regs = qmp_v3_usb3phy_regs_layout_qcm2290, }; +static const struct qmp_phy_cfg msm8998_phy_usb3_cfg = { + .type = QMP_PHY_USBC_USB, + .cfg = &msm8998_usb3phy_cfg, +}; + +static const struct qmp_phy_cfg qcm2290_phy_usb3_cfg = { + .type = QMP_PHY_USBC_USB, + .cfg = &qcm2290_usb3phy_cfg, +}; + +static const struct qmp_phy_cfg sdm660_phy_usb3_cfg = { + .type = QMP_PHY_USBC_USB, + .cfg = &sdm660_usb3phy_cfg, +}; + #define to_usb_cfg(x) ((struct qmp_phy_usb_cfg *)((x)->cfg)) #define to_usb_layout(x) ((struct qmp_phy_usb_layout *)((x)->layout)) static int qmp_usbc_generic_init(struct phy *phy) { struct qmp_usbc *qmp = phy_get_drvdata(phy); - struct qmp_phy_usb_cfg *cfg = to_usb_cfg(qmp); - struct qmp_phy_usb_layout *layout = to_usb_layout(qmp); int num_vregs; - unsigned int reg_pwr_dn; u32 val; int ret; + unsigned int reg_pwr_dn; - num_vregs = cfg->num_vregs; - reg_pwr_dn = cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL]; + if (qmp->type == QMP_PHY_USBC_USB) { + struct qmp_phy_usb_cfg *cfg = to_usb_cfg(qmp); - ret = regulator_bulk_enable(cfg->num_vregs, qmp->vregs); + num_vregs = cfg->num_vregs; + reg_pwr_dn = cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL]; + } + + ret = regulator_bulk_enable(num_vregs, qmp->vregs); if (ret) { dev_err(qmp->dev, "failed to enable regulators, err=%d\n", ret); return ret; @@ -497,8 +524,12 @@ static int qmp_usbc_generic_init(struct phy *phy) if (qmp->orientation == TYPEC_ORIENTATION_REVERSE) val |= SW_PORTSELECT_VAL; - qphy_setbits(layout->pcs, reg_pwr_dn, SW_PWRDN); - writel(val, layout->pcs_misc); + if (qmp->type == QMP_PHY_USBC_USB) { + struct qmp_phy_usb_layout *layout = to_usb_layout(qmp); + + qphy_setbits(layout->pcs, reg_pwr_dn, SW_PWRDN); + writel(val, layout->pcs_misc); + } return 0; @@ -513,13 +544,18 @@ static int qmp_usbc_generic_init(struct phy *phy) static int qmp_usbc_generic_exit(struct phy *phy) { struct qmp_usbc *qmp = phy_get_drvdata(phy); - struct qmp_phy_usb_cfg *cfg = to_usb_cfg(qmp); + int num_vregs; reset_control_bulk_assert(qmp->num_resets, qmp->resets); clk_bulk_disable_unprepare(qmp->num_clks, qmp->clks); - regulator_bulk_disable(cfg->num_vregs, qmp->vregs); + if (qmp->type == QMP_PHY_USBC_USB) { + struct qmp_phy_usb_cfg *cfg = to_usb_cfg(qmp); + + num_vregs = cfg->num_vregs; + } + regulator_bulk_disable(num_vregs, qmp->vregs); return 0; } @@ -650,7 +686,7 @@ static const struct phy_ops qmp_usbc_usb_phy_ops = { static void qmp_usbc_enable_autonomous_mode(struct qmp_usbc *qmp) { - const struct qmp_phy_usb_cfg *cfg = qmp->cfg; + const struct qmp_phy_usb_cfg *cfg = to_usb_cfg(qmp); struct qmp_phy_usb_layout *layout = to_usb_layout(qmp); void __iomem *pcs = layout->pcs; u32 intr_mask; @@ -698,18 +734,20 @@ static void qmp_usbc_disable_autonomous_mode(struct qmp_usbc *qmp) static int __maybe_unused qmp_usbc_runtime_suspend(struct device *dev) { struct qmp_usbc *qmp = dev_get_drvdata(dev); - struct qmp_phy_usb_layout *layout = to_usb_layout(qmp); - - dev_vdbg(dev, "Suspending QMP phy, mode:%d\n", layout->mode); if (!qmp->phy->init_count) { dev_vdbg(dev, "PHY not initialized, bailing out\n"); return 0; } - qmp_usbc_enable_autonomous_mode(qmp); + if (qmp->type == QMP_PHY_USBC_USB) { + struct qmp_phy_usb_layout *layout = to_usb_layout(qmp); + + dev_vdbg(dev, "Suspending QMP phy, mode:%d\n", layout->mode); + qmp_usbc_enable_autonomous_mode(qmp); + clk_disable_unprepare(layout->pipe_clk); + } - clk_disable_unprepare(layout->pipe_clk); clk_bulk_disable_unprepare(qmp->num_clks, qmp->clks); return 0; @@ -718,11 +756,8 @@ static int __maybe_unused qmp_usbc_runtime_suspend(struct device *dev) static int __maybe_unused qmp_usbc_runtime_resume(struct device *dev) { struct qmp_usbc *qmp = dev_get_drvdata(dev); - struct qmp_phy_usb_layout *layout = to_usb_layout(qmp); int ret = 0; - dev_vdbg(dev, "Resuming QMP phy, mode:%d\n", layout->mode); - if (!qmp->phy->init_count) { dev_vdbg(dev, "PHY not initialized, bailing out\n"); return 0; @@ -732,14 +767,19 @@ static int __maybe_unused qmp_usbc_runtime_resume(struct device *dev) if (ret) return ret; - ret = clk_prepare_enable(layout->pipe_clk); - if (ret) { - dev_err(dev, "pipe_clk enable failed, err=%d\n", ret); - clk_bulk_disable_unprepare(qmp->num_clks, qmp->clks); - return ret; - } + if (qmp->type == QMP_PHY_USBC_USB) { + struct qmp_phy_usb_layout *layout = to_usb_layout(qmp); + + dev_vdbg(dev, "Resuming QMP phy, mode:%d\n", layout->mode); + ret = clk_prepare_enable(layout->pipe_clk); + if (ret) { + dev_err(dev, "pipe_clk enable failed, err=%d\n", ret); + clk_bulk_disable_unprepare(qmp->num_clks, qmp->clks); + return ret; + } - qmp_usbc_disable_autonomous_mode(qmp); + qmp_usbc_disable_autonomous_mode(qmp); + } return 0; } @@ -751,20 +791,28 @@ static const struct dev_pm_ops qmp_usbc_pm_ops = { static int qmp_usbc_vreg_init(struct qmp_usbc *qmp) { - struct qmp_phy_usb_cfg *cfg = to_usb_cfg(qmp); struct device *dev = qmp->dev; - int i; + int ret, i; - int num = cfg->num_vregs; + if (qmp->type == QMP_PHY_USBC_USB) { + struct qmp_phy_usb_cfg *cfg = to_usb_cfg(qmp); + int num = cfg->num_vregs; - qmp->vregs = devm_kcalloc(dev, num, sizeof(*qmp->vregs), GFP_KERNEL); - if (!qmp->vregs) - return -ENOMEM; + qmp->vregs = devm_kcalloc(dev, num, sizeof(*qmp->vregs), GFP_KERNEL); + if (!qmp->vregs) + return -ENOMEM; - for (i = 0; i < num; i++) - qmp->vregs[i].supply = cfg->vreg_list[i]; + for (i = 0; i < num; i++) + qmp->vregs[i].supply = cfg->vreg_list[i]; - return devm_regulator_bulk_get(dev, num, qmp->vregs); + ret = devm_regulator_bulk_get(dev, num, qmp->vregs); + if (ret) { + dev_err(dev, "failed at devm_regulator_bulk_get\n"); + return ret; + } + } + + return 0; } static int qmp_usbc_reset_init(struct qmp_usbc *qmp, @@ -1061,6 +1109,7 @@ static int qmp_usbc_probe(struct platform_device *pdev) struct phy_provider *phy_provider; struct device_node *np; struct qmp_usbc *qmp; + const struct qmp_phy_cfg *data_cfg; int ret; qmp = devm_kzalloc(dev, sizeof(*qmp), GFP_KERNEL); @@ -1072,39 +1121,45 @@ static int qmp_usbc_probe(struct platform_device *pdev) qmp->orientation = TYPEC_ORIENTATION_NORMAL; - qmp->cfg = of_device_get_match_data(dev); - if (!qmp->cfg) + data_cfg = of_device_get_match_data(dev); + if (!data_cfg) return -EINVAL; mutex_init(&qmp->phy_mutex); + qmp->type = data_cfg->type; + qmp->cfg = data_cfg->cfg; + ret = qmp_usbc_vreg_init(qmp); if (ret) return ret; - qmp->layout = devm_kzalloc(dev, sizeof(struct qmp_phy_usb_layout), GFP_KERNEL); - if (!qmp->layout) - return -ENOMEM; + if (qmp->type == QMP_PHY_USBC_USB) { + qmp->layout = devm_kzalloc(dev, sizeof(struct qmp_phy_usb_layout), GFP_KERNEL); + if (!qmp->layout) + return -ENOMEM; + + 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) { + ret = qmp_usbc_parse_usb_dt_legacy(qmp, np); + } else { + np = of_node_get(dev->of_node); + ret = qmp_usbc_parse_usb_dt(qmp); + } + + if (ret) + goto err_node_put; + } ret = qmp_usbc_typec_switch_register(qmp); 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) { - ret = qmp_usbc_parse_usb_dt_legacy(qmp, np); - } else { - np = of_node_get(dev->of_node); - ret = qmp_usbc_parse_usb_dt(qmp); - } - if (ret) - goto err_node_put; - pm_runtime_set_active(dev); ret = devm_pm_runtime_enable(dev); if (ret) @@ -1115,15 +1170,17 @@ static int qmp_usbc_probe(struct platform_device *pdev) */ pm_runtime_forbid(dev); - ret = phy_pipe_clk_register(qmp, np); - if (ret) - goto err_node_put; - - qmp->phy = devm_phy_create(dev, np, &qmp_usbc_usb_phy_ops); - if (IS_ERR(qmp->phy)) { - ret = PTR_ERR(qmp->phy); - dev_err(dev, "failed to create PHY: %d\n", ret); - goto err_node_put; + if (qmp->type == QMP_PHY_USBC_USB) { + ret = phy_pipe_clk_register(qmp, np); + if (ret) + goto err_node_put; + + qmp->phy = devm_phy_create(dev, np, &qmp_usbc_usb_phy_ops); + if (IS_ERR(qmp->phy)) { + ret = PTR_ERR(qmp->phy); + dev_err(dev, "failed to create PHY: %d\n", ret); + goto err_node_put; + } } phy_set_drvdata(qmp->phy, qmp); @@ -1142,19 +1199,19 @@ static int qmp_usbc_probe(struct platform_device *pdev) static const struct of_device_id qmp_usbc_of_match_table[] = { { .compatible = "qcom,msm8998-qmp-usb3-phy", - .data = &msm8998_usb3phy_cfg, + .data = &msm8998_phy_usb3_cfg, }, { .compatible = "qcom,qcm2290-qmp-usb3-phy", - .data = &qcm2290_usb3phy_cfg, + .data = &qcm2290_phy_usb3_cfg, }, { .compatible = "qcom,qcs615-qmp-usb3-phy", - .data = &qcm2290_usb3phy_cfg, + .data = &qcm2290_phy_usb3_cfg, }, { .compatible = "qcom,sdm660-qmp-usb3-phy", - .data = &sdm660_usb3phy_cfg, + .data = &sdm660_phy_usb3_cfg, }, { .compatible = "qcom,sm6115-qmp-usb3-phy", - .data = &qcm2290_usb3phy_cfg, + .data = &qcm2290_phy_usb3_cfg, }, { }, }; -- 2.34.1
