@@ -583,7 +583,9 @@ static void clk_clean_rate_cache(struct clk *clk)
ulong clk_set_rate(struct clk *clk, ulong rate)
{
const struct clk_ops *ops;
+ struct clk *pclk;
struct clk *clkp;
+ ulong ret;
debug("%s(clk=%p, rate=%lu)\n", __func__, clk, rate);
if (!clk_valid(clk))
@@ -598,11 +600,37 @@ ulong clk_set_rate(struct clk *clk, ulong rate)
/* Clean up cached rates for us and all child clocks */
clk_clean_rate_cache(clkp);
- return ops->set_rate(clk, rate);
+ if (clk->flags & CLK_SET_RATE_UNGATE) {
+ ret = clk_enable(clk);
+ if (ret)
+ return ret;
+ }
+
+ pclk = clk_get_parent(clk);
+ if (pclk) {
+ if (clk->flags & CLK_OPS_PARENT_ENABLE) {
+ ret = clk_enable(pclk);
+ if (ret)
+ goto out;
+ }
+ }
+
+ ret = ops->set_rate(clk, rate);
+
+ if (pclk && clk->flags & CLK_OPS_PARENT_ENABLE)
+ clk_disable(pclk);
+
+out:
+ if (clk->flags & CLK_SET_RATE_UNGATE)
+ clk_disable(clk);
+
+ return ret;
}
int clk_set_parent(struct clk *clk, struct clk *parent)
{
+ struct clk *old_parent;
+
const struct clk_ops *ops;
int ret;
@@ -614,6 +642,15 @@ int clk_set_parent(struct clk *clk, struct clk *parent)
if (!ops->set_parent)
return -ENOSYS;
+ if (clk->enable_count)
+ clk_enable(parent);
+
+ old_parent = clk_get_parent(clk);
+ if (clk->flags & CLK_OPS_PARENT_ENABLE) {
+ clk_enable(old_parent);
+ clk_enable(parent);
+ }
+
ret = ops->set_parent(clk, parent);
if (ret)
return ret;
@@ -621,6 +658,14 @@ int clk_set_parent(struct clk *clk, struct clk *parent)
if (CONFIG_IS_ENABLED(CLK_CCF))
ret = device_reparent(clk->dev, parent->dev);
+ if (clk->flags & CLK_OPS_PARENT_ENABLE) {
+ clk_disable(parent);
+ clk_disable(old_parent);
+ }
+
+ if (clk->enable_count)
+ clk_disable(old_parent);
+
return ret;
}
There are scenario that we need to enable the new parent clock before reparent, or we need to do the same with clk_set_rate. The patch cover those scenario Signed-off-by: Michael Trimarchi <michael@amarulasolutions.com> --- drivers/clk/clk-uclass.c | 47 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-)