Message ID | 20240929061025.3704-1-frawang.cn@gmail.com |
---|---|
State | Superseded |
Headers | show |
Series | [v4,1/3] phy: rockchip: inno-usb2: convert clock management to bulk | expand |
On Sun, Sep 29, 2024 at 02:10:23PM +0800, Frank Wang wrote: > From: Frank Wang <frank.wang@rock-chips.com> > > 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@rock-chips.com> > --- > 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
Hi Krzysztof, On 2024/9/30 3:38, Krzysztof Kozlowski wrote: > On Sun, Sep 29, 2024 at 02:10:23PM +0800, Frank Wang wrote: >> From: Frank Wang <frank.wang@rock-chips.com> >> >> 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@rock-chips.com> >> --- >> 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? Yes, the clock properties are optional. Best regards, Frank > Best regards, > Krzysztof >
On 08/10/2024 05:07, Frank Wang wrote: >>> + } >>> + >>> + 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? > > Yes, the clock properties are optional. And? So are you going to use optional variant of clk get or not? Is it appropriate? Are you going to improve it? Best regards, Krzysztof
Hi Krzysztof, On 2024/10/8 22:35, Krzysztof Kozlowski wrote: > On 08/10/2024 05:07, Frank Wang wrote: >>>> + } >>>> + >>>> + 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? >> Yes, the clock properties are optional. > And? So are you going to use optional variant of clk get or not? Is it > appropriate? Are you going to improve it? Using devm_clk_bulk_get_all() not only get clk_bulk_data, but also can get num_clks. The clocks numbers (num_clks) are used for search the ref_clk in rockchip_usb2phy_clk480m_register(). However, right now, the optional variant of clk_*_optional functions can not get num_clksor must know num_clks, then can get clk_bulk_data. Best regards, Frank > Best regards, > Krzysztof >
Hi Krzysztof, On 2024/10/8 22:35, Krzysztof Kozlowski wrote: > On 08/10/2024 05:07, Frank Wang wrote: >>>> + } >>>> + >>>> + 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? >> Yes, the clock properties are optional. > And? So are you going to use optional variant of clk get or not? Is it > appropriate? Are you going to improve it? Using devm_clk_bulk_get_all() not only get clk_bulk_data, but also can get num_clks. The clocks numbers (num_clks) are used for search the ref_clk in rockchip_usb2phy_clk480m_register(). However, right now, the optional variant of clk_*_optional functions can not get num_clks, or must know num_clks, then can get clk_bulk_data. Best regards, Frank > Best regards, > Krzysztof >
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) { + return dev_err_probe(&pdev->dev, -EPROBE_DEFER, "failed to get phyclk\n"); } + /* Clocks are optional */ + rphy->num_clks = ret < 0 ? 0 : ret; + ret = rockchip_usb2phy_clk480m_register(rphy); if (ret) { dev_err(dev, "failed to register 480m output clock\n"); return ret; } + ret = clk_bulk_prepare_enable(rphy->num_clks, rphy->clks); + if (ret) + return ret; + + ret = devm_add_action_or_reset(dev, rockchip_usb2phy_clk_bulk_disable, rphy); + if (ret) + return ret; + if (rphy->phy_cfg->phy_tuning) { ret = rphy->phy_cfg->phy_tuning(rphy); if (ret)