On Sun, Sep 29, 2024 at 02:10:23PM +0800, Frank Wang wrote: > From: Frank Wang <frank.wang@xxxxxxxxxxxxxx> > > Since some Rockchip SoCs (e.g RK3576) have more than one clock, > this converts the clock management from single to bulk method to > make the driver more flexible. > > Signed-off-by: Frank Wang <frank.wang@xxxxxxxxxxxxxx> > --- > Changelog: > v4: > - a new patch split from the [PATCH v3 2/2], suggestions from Heiko. > > v1-v3: > - none > > drivers/phy/rockchip/phy-rockchip-inno-usb2.c | 43 ++++++++++++++++--- > 1 file changed, 36 insertions(+), 7 deletions(-) > > diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c > index 4f71373ae6e1..ad3e65dc6aa4 100644 > --- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c > +++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c > @@ -229,9 +229,10 @@ struct rockchip_usb2phy_port { > * @dev: pointer to device. > * @grf: General Register Files regmap. > * @usbgrf: USB General Register Files regmap. > - * @clk: clock struct of phy input clk. > + * @clks: array of phy input clocks. > * @clk480m: clock struct of phy output clk. > * @clk480m_hw: clock struct of phy output clk management. > + * @num_clks: number of phy input clocks. > * @phy_reset: phy reset control. > * @chg_state: states involved in USB charger detection. > * @chg_type: USB charger types. > @@ -246,9 +247,10 @@ struct rockchip_usb2phy { > struct device *dev; > struct regmap *grf; > struct regmap *usbgrf; > - struct clk *clk; > + struct clk_bulk_data *clks; > struct clk *clk480m; > struct clk_hw clk480m_hw; > + int num_clks; > struct reset_control *phy_reset; > enum usb_chg_state chg_state; > enum power_supply_type chg_type; > @@ -310,6 +312,13 @@ static int rockchip_usb2phy_reset(struct rockchip_usb2phy *rphy) > return 0; > } > > +static void rockchip_usb2phy_clk_bulk_disable(void *data) > +{ > + struct rockchip_usb2phy *rphy = data; > + > + clk_bulk_disable_unprepare(rphy->num_clks, rphy->clks); > +} > + > static int rockchip_usb2phy_clk480m_prepare(struct clk_hw *hw) > { > struct rockchip_usb2phy *rphy = > @@ -376,7 +385,9 @@ rockchip_usb2phy_clk480m_register(struct rockchip_usb2phy *rphy) > { > struct device_node *node = rphy->dev->of_node; > struct clk_init_data init; > + struct clk *refclk = NULL; > const char *clk_name; > + int i; > int ret = 0; > > init.flags = 0; > @@ -386,8 +397,15 @@ rockchip_usb2phy_clk480m_register(struct rockchip_usb2phy *rphy) > /* optional override of the clockname */ > of_property_read_string(node, "clock-output-names", &init.name); > > - if (rphy->clk) { > - clk_name = __clk_get_name(rphy->clk); > + for (i = 0; i < rphy->num_clks; i++) { > + if (!strncmp(rphy->clks[i].id, "phyclk", 6)) { > + refclk = rphy->clks[i].clk; > + break; > + } > + } > + > + if (!IS_ERR(refclk)) { > + clk_name = __clk_get_name(refclk); > init.parent_names = &clk_name; > init.num_parents = 1; > } else { > @@ -1406,18 +1424,29 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev) > if (IS_ERR(rphy->phy_reset)) > return PTR_ERR(rphy->phy_reset); > > - rphy->clk = devm_clk_get_optional_enabled(dev, "phyclk"); > - if (IS_ERR(rphy->clk)) { > - return dev_err_probe(&pdev->dev, PTR_ERR(rphy->clk), > + ret = devm_clk_bulk_get_all(dev, &rphy->clks); > + if (ret == -EPROBE_DEFER) { This does not make much sense. Why would you proceed on other critical errors? You want to use optional variant, I guess? Best regards, Krzysztof