[PATCH v2 6/7] phy: exynos5-usbdrd: convert to clk_bulk for phy (register) access

André Draszik
2024-05-01T09:19:41Z

In preparation for support for additional platforms, convert the phy
register access clock to using the clk_bulk interfaces.

Newer SoCs like Google Tensor gs101 require more clocks for register
access, and converting to clk_bulk simplifies addition of those extra
clocks.

Given the list of phy register clocks is requested as optional, I
haven't made it platform specific, as only those clocks that are
actually declared (in the DT) will be retrieved and the code behaves as
before this change. Nevertheless, this piece of the code is easy to
change in the future if the need arises.

Signed-off-by: André Draszik <andre.draszik@linaro.org>
---
drivers/phy/samsung/phy-exynos5-usbdrd.c | 45 +++++++++++++++++++++-----------
1 file changed, 30 insertions(+), 15 deletions(-)

diff --git a/drivers/phy/samsung/phy-exynos5-usbdrd.c b/drivers/phy/samsung/phy-exynos5-usbdrd.c
index 200285fa823b..c5a0c4882a86 100644
--- a/drivers/phy/samsung/phy-exynos5-usbdrd.c
+++ b/drivers/phy/samsung/phy-exynos5-usbdrd.c
@@ -195,7 +195,8 @@ struct exynos5_usbdrd_phy_drvdata {
* struct exynos5_usbdrd_phy - driver data for USB 3.0 PHY
* @dev: pointer to device instance of this platform device
* @reg_phy: usb phy controller register memory base
- * @clk: phy clock for register access
+ * @phy_clks: phy clocks for register access
+ * @n_phy_clks: number of phy clocks for register access
* @pipeclk: clock for pipe3 phy
* @utmiclk: clock for utmi+ phy
* @itpclk: clock for ITP generation
@@ -212,7 +213,8 @@ struct exynos5_usbdrd_phy_drvdata {
struct exynos5_usbdrd_phy {
struct device *dev;
void __iomem *reg_phy;
- struct clk *clk;
+ struct clk_bulk_data *phy_clks;
+ size_t n_phy_clks;
struct clk *pipeclk;
struct clk *utmiclk;
struct clk *itpclk;
@@ -408,7 +410,7 @@ static int exynos5_usbdrd_phy_init(struct phy *phy)
struct phy_usb_instance *inst = phy_get_drvdata(phy);
struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);

- ret = clk_prepare_enable(phy_drd->clk);
+ ret = clk_bulk_prepare_enable(phy_drd->n_phy_clks, phy_drd->phy_clks);
if (ret)
return ret;

@@ -458,7 +460,7 @@ static int exynos5_usbdrd_phy_init(struct phy *phy)
reg &= ~PHYCLKRST_PORTRESET;
writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYCLKRST);

- clk_disable_unprepare(phy_drd->clk);
+ clk_bulk_disable_unprepare(phy_drd->n_phy_clks, phy_drd->phy_clks);

return 0;
}
@@ -470,7 +472,7 @@ static int exynos5_usbdrd_phy_exit(struct phy *phy)
struct phy_usb_instance *inst = phy_get_drvdata(phy);
struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);

- ret = clk_prepare_enable(phy_drd->clk);
+ ret = clk_bulk_prepare_enable(phy_drd->n_phy_clks, phy_drd->phy_clks);
if (ret)
return ret;

@@ -492,7 +494,7 @@ static int exynos5_usbdrd_phy_exit(struct phy *phy)
PHYTEST_POWERDOWN_HSP;
writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYTEST);

- clk_disable_unprepare(phy_drd->clk);
+ clk_bulk_disable_unprepare(phy_drd->n_phy_clks, phy_drd->phy_clks);

return 0;
}
@@ -827,14 +829,14 @@ static int exynos850_usbdrd_phy_init(struct phy *phy)
struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
int ret;

- ret = clk_prepare_enable(phy_drd->clk);
+ ret = clk_bulk_prepare_enable(phy_drd->n_phy_clks, phy_drd->phy_clks);
if (ret)
return ret;

/* UTMI or PIPE3 specific init */
inst->phy_cfg->phy_init(phy_drd);

- clk_disable_unprepare(phy_drd->clk);
+ clk_bulk_disable_unprepare(phy_drd->n_phy_clks, phy_drd->phy_clks);

return 0;
}
@@ -847,7 +849,7 @@ static int exynos850_usbdrd_phy_exit(struct phy *phy)
u32 reg;
int ret;

- ret = clk_prepare_enable(phy_drd->clk);
+ ret = clk_bulk_prepare_enable(phy_drd->n_phy_clks, phy_drd->phy_clks);
if (ret)
return ret;

@@ -870,7 +872,7 @@ static int exynos850_usbdrd_phy_exit(struct phy *phy)
reg &= ~CLKRST_LINK_SW_RST;
writel(reg, regs_base + EXYNOS850_DRD_CLKRST);

- clk_disable_unprepare(phy_drd->clk);
+ clk_bulk_disable_unprepare(phy_drd->n_phy_clks, phy_drd->phy_clks);

return 0;
}
@@ -883,16 +885,29 @@ static const struct phy_ops exynos850_usbdrd_phy_ops = {
.owner = THIS_MODULE,
};

+static const char * const phy_clk_list[] = {
+ "phy",
+};
+
static int exynos5_usbdrd_phy_clk_handle(struct exynos5_usbdrd_phy *phy_drd)
{
unsigned long ref_rate;
int ret;

- phy_drd->clk = devm_clk_get(phy_drd->dev, "phy");
- if (IS_ERR(phy_drd->clk)) {
- dev_err(phy_drd->dev, "Failed to get phy clock\n");
- return PTR_ERR(phy_drd->clk);
- }
+ phy_drd->n_phy_clks = ARRAY_SIZE(phy_clk_list);
+ phy_drd->phy_clks = devm_kcalloc(phy_drd->dev, phy_drd->n_phy_clks,
+ sizeof(*phy_drd->phy_clks),
+ GFP_KERNEL);
+ if (!phy_drd->phy_clks)
+ return -ENOMEM;
+
+ for (int i = 0; i < phy_drd->n_phy_clks; ++i)
+ phy_drd->phy_clks[i].id = phy_clk_list[i];
+
+ ret = devm_clk_bulk_get_optional(phy_drd->dev, phy_drd->n_phy_clks,
+ phy_drd->phy_clks);
+ if (ret < 0)
+ return ret;

phy_drd->ref_clk = devm_clk_get(phy_drd->dev, "ref");
if (IS_ERR(phy_drd->ref_clk)) {