sh: clkfwk: Improve the generic clk_set_parent() implementation.
authorPaul Mundt <lethal@linux-sh.org>
Mon, 11 May 2009 20:51:05 +0000 (05:51 +0900)
committerPaul Mundt <lethal@linux-sh.org>
Mon, 11 May 2009 20:51:05 +0000 (05:51 +0900)
This causes the generic clk_set_parent() implementation to be a bit more
intelligent. A clk_reparent() is added to move the clock over to the new
parent's sibling list, which then allows the generic rate propagation
code to succeed. This also becomes a nop if the new and old parents are
unchanged.

Signed-off-by: Paul Mundt <lethal@linux-sh.org>
arch/sh/include/asm/clock.h
arch/sh/kernel/cpu/clock.c

index 5de72ee..fdb9156 100644 (file)
@@ -48,6 +48,7 @@ int clk_init(void);
 unsigned long followparent_recalc(struct clk *);
 void recalculate_root_clocks(void);
 void propagate_rate(struct clk *);
+int clk_reparent(struct clk *child, struct clk *parent);
 void clk_recalc_rate(struct clk *);
 int clk_register(struct clk *);
 void clk_unregister(struct clk *);
index e027fe5..e3d1de8 100644 (file)
@@ -81,6 +81,19 @@ unsigned long followparent_recalc(struct clk *clk)
        return clk->parent->rate;
 }
 
+int clk_reparent(struct clk *child, struct clk *parent)
+{
+       list_del_init(&child->sibling);
+       if (parent)
+               list_add(&child->sibling, &parent->children);
+       child->parent = parent;
+
+       /* now do the debugfs renaming to reattach the child
+          to the proper parent */
+
+       return 0;
+}
+
 /* Propagate rate to children */
 void propagate_rate(struct clk *tclk)
 {
@@ -288,12 +301,19 @@ int clk_set_parent(struct clk *clk, struct clk *parent)
 
        if (!parent || !clk)
                return ret;
+       if (clk->parent == parent)
+               return 0;
 
        spin_lock_irqsave(&clock_lock, flags);
        if (clk->usecount == 0) {
                if (clk->ops->set_parent)
                        ret = clk->ops->set_parent(clk, parent);
+               else
+                       ret = clk_reparent(clk, parent);
+
                if (ret == 0) {
+                       pr_debug("clock: set parent of %s to %s (new rate %ld)\n",
+                                clk->name, clk->parent->name, clk->rate);
                        if (clk->ops->recalc)
                                clk->rate = clk->ops->recalc(clk);
                        propagate_rate(clk);