From: Michael Trimarchi <mich...@amarulasolutions.com>

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 <mich...@amarulasolutions.com>
Signed-off-by: Dario Binacchi <dario.binac...@amarulasolutions.com>
---

 drivers/clk/clk-uclass.c | 47 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 46 insertions(+), 1 deletion(-)

diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c
index e8db9b0ff2fd..b571a3620222 100644
--- a/drivers/clk/clk-uclass.c
+++ b/drivers/clk/clk-uclass.c
@@ -582,7 +582,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))
@@ -597,11 +599,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;
 
@@ -613,6 +641,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;
@@ -620,6 +657,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;
 }
 
-- 
2.43.0

Reply via email to