Messages in this thread Patch in this message | | | Date | Thu, 20 Oct 2022 11:31:35 +0300 | Subject | Re: [PATCH v2 13/15] phy: qcom-qmp-pcie: add support for pipediv2 clock | From | Dmitry Baryshkov <> |
| |
On 19/10/2022 14:35, Johan Hovold wrote: > Some QMP PHYs have a second fixed-divider pipe clock that needs to be > enabled along with the pipe clock. > > Add support for an optional "pipediv2" clock. > > Signed-off-by: Johan Hovold <johan+linaro@kernel.org> > --- > drivers/phy/qualcomm/phy-qcom-qmp-pcie.c | 42 ++++++++++++++++++++---- > 1 file changed, 36 insertions(+), 6 deletions(-) > > diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c > index 9c8e009033f1..c1d74c06fad1 100644 > --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c > +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c > @@ -1379,7 +1379,9 @@ struct qmp_pcie { > void __iomem *rx2; > > struct clk *pipe_clk; > + struct clk *pipediv2_clk; > struct clk_bulk_data *clks; > + > struct reset_control_bulk_data *resets; > struct regulator_bulk_data *vregs; > > @@ -1902,6 +1904,36 @@ static int qmp_pcie_exit(struct phy *phy) > return 0; > } > > +static int pipe_clk_enable(struct qmp_pcie *qmp) > +{ > + int ret; > + > + ret = clk_prepare_enable(qmp->pipe_clk); > + if (ret) { > + dev_err(qmp->dev, "failed to enable pipe clock: %d\n", ret); > + return ret; > + } > + > + ret = clk_prepare_enable(qmp->pipediv2_clk); > + if (ret) { > + dev_err(qmp->dev, "failed to enable pipediv2 clock: %d\n", ret); > + goto err_disable_pipe_clk; > + } > + > + return 0; > + > +err_disable_pipe_clk: > + clk_disable_unprepare(qmp->pipe_clk); > + > + return ret; > +} > + > +static void pipe_clk_disable(struct qmp_pcie *qmp) > +{ > + clk_disable_unprepare(qmp->pipediv2_clk); > + clk_disable_unprepare(qmp->pipe_clk); > +} > + > static int qmp_pcie_power_on(struct phy *phy) > { > struct qmp_pcie *qmp = phy_get_drvdata(phy); > @@ -1923,11 +1955,9 @@ static int qmp_pcie_power_on(struct phy *phy) > qmp_pcie_init_registers(qmp, &cfg->tables); > qmp_pcie_init_registers(qmp, mode_tables); > > - ret = clk_prepare_enable(qmp->pipe_clk); > - if (ret) { > - dev_err(qmp->dev, "pipe_clk enable failed err=%d\n", ret); > + ret = pipe_clk_enable(qmp); > + if (ret) > return ret; > - } > > /* Pull PHY out of reset state */ > qphy_clrbits(pcs, cfg->regs[QPHY_SW_RESET], SW_RESET); > @@ -1950,7 +1980,7 @@ static int qmp_pcie_power_on(struct phy *phy) > return 0; > > err_disable_pipe_clk: > - clk_disable_unprepare(qmp->pipe_clk); > + pipe_clk_disable(qmp); > > return ret; > } > @@ -1960,7 +1990,7 @@ static int qmp_pcie_power_off(struct phy *phy) > struct qmp_pcie *qmp = phy_get_drvdata(phy); > const struct qmp_phy_cfg *cfg = qmp->cfg; > > - clk_disable_unprepare(qmp->pipe_clk); > + pipe_clk_disable(qmp); > > /* PHY reset */ > qphy_setbits(qmp->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
I still think that the attached patch is somewhat simpler. Diffstat supports that idea:
$ diffstat /tmp/pipe.diff phy-qcom-qmp-pcie.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-)
Yes, I'm speaking this after having cleaned up several open-coded versions of clk_bulk_foo from the drm/msm code. It typically starts with the 'just another clock' story, and then suddenly they are all over the code.
-- With best wishes Dmitry diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c index 9c8e009033f1..a148b143dd90 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c @@ -1378,8 +1378,10 @@ struct qmp_pcie { void __iomem *tx2; void __iomem *rx2; - struct clk *pipe_clk; + struct clk_bulk_data *pipe_clks; + int num_pipe_clks; struct clk_bulk_data *clks; + struct reset_control_bulk_data *resets; struct regulator_bulk_data *vregs; @@ -1923,11 +1925,9 @@ static int qmp_pcie_power_on(struct phy *phy) qmp_pcie_init_registers(qmp, &cfg->tables); qmp_pcie_init_registers(qmp, mode_tables); - ret = clk_prepare_enable(qmp->pipe_clk); - if (ret) { - dev_err(qmp->dev, "pipe_clk enable failed err=%d\n", ret); + ret = clk_bulk_prepare_enable(qmp->num_pipe_clks, qmp->pipe_clks); + if (ret) return ret; - } /* Pull PHY out of reset state */ qphy_clrbits(pcs, cfg->regs[QPHY_SW_RESET], SW_RESET); @@ -1950,7 +1950,7 @@ static int qmp_pcie_power_on(struct phy *phy) return 0; err_disable_pipe_clk: - clk_disable_unprepare(qmp->pipe_clk); + clk_bulk_disable_unprepare(qmp->num_pipe_clks, qmp->pipe_clks); return ret; } @@ -1960,7 +1960,7 @@ static int qmp_pcie_power_off(struct phy *phy) struct qmp_pcie *qmp = phy_get_drvdata(phy); const struct qmp_phy_cfg *cfg = qmp->cfg; - clk_disable_unprepare(qmp->pipe_clk); + clk_bulk_disable_unprepare(qmp->num_pipe_clks, qmp->pipe_clks); /* PHY reset */ qphy_setbits(qmp->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET); @@ -2154,6 +2154,7 @@ static int qmp_pcie_parse_dt_legacy(struct qmp_pcie *qmp, struct device_node *np struct platform_device *pdev = to_platform_device(qmp->dev); const struct qmp_phy_cfg *cfg = qmp->cfg; struct device *dev = qmp->dev; + struct clk *clk; qmp->serdes = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(qmp->serdes)) @@ -2206,12 +2207,17 @@ static int qmp_pcie_parse_dt_legacy(struct qmp_pcie *qmp, struct device_node *np } } - qmp->pipe_clk = devm_get_clk_from_child(dev, np, NULL); - if (IS_ERR(qmp->pipe_clk)) { - return dev_err_probe(dev, PTR_ERR(qmp->pipe_clk), + clk = devm_get_clk_from_child(dev, np, NULL); + if (IS_ERR(clk)) { + return dev_err_probe(dev, PTR_ERR(clk), "failed to get pipe clock\n"); } + qmp->num_pipe_clks = 1; + qmp->pipe_clks = devm_kcalloc(dev, qmp->num_pipe_clks, + sizeof(*qmp->pipe_clks), GFP_KERNEL); + qmp->pipe_clks[0].clk = clk; + return 0; } | |