clk: rockchip: add CLK_SET_RATE_PARENT_IN_ORDER
authordkl <dkl@rock-chips.com>
Thu, 24 Apr 2014 01:30:12 +0000 (09:30 +0800)
committerdkl <dkl@rock-chips.com>
Mon, 28 Apr 2014 13:24:24 +0000 (21:24 +0800)
If the flag CLK_SET_RATE_PARENT_IN_ORDER is set, consider the
order of .set_parent and .set_rate, to prevent a too large
temporary rate on rate change. This will fix the bug of clk_gpu
in rk3288.

arch/arm/boot/dts/rk3288-clocks.dtsi
drivers/clk/clk.c
include/dt-bindings/clock/rockchip.h
include/linux/clk-provider.h

index f3e007fe34d3b7e89ce1cd61d5f8096ae441f8cc..1649d729f81f794b87d7069474bf1e94056c2dab 100755 (executable)
                                                #clock-cells = <0>;
                                                rockchip,clkops-idx =
                                                        <CLKOPS_RATE_MUX_DIV>;
+                                               rockchip,flags = <CLK_SET_RATE_PARENT_IN_ORDER>;
                                        };
 
                                        /* reg[5]: reserved */
index 2cf2ea6b77a1ac307c22d35aed28b12d7a0da75f..251c10b63c41b5d38768250d7a78c618e8647388 100644 (file)
@@ -1374,14 +1374,23 @@ static struct clk *clk_propagate_rate_change(struct clk *clk, unsigned long even
 static void clk_change_rate(struct clk *clk)
 {
        struct clk *child;
-       unsigned long old_rate;
+       unsigned long old_rate, tmp_rate;
        unsigned long best_parent_rate = 0;
 
        old_rate = clk->rate;
 
        /* set parent */
-       if (clk->new_parent && clk->new_parent != clk->parent)
+       if (clk->new_parent && clk->new_parent != clk->parent) {
+               if (clk->flags & CLK_SET_RATE_PARENT_IN_ORDER) {
+                       tmp_rate = clk->ops->recalc_rate(clk->hw, clk->new_parent->rate);
+                       if ((tmp_rate > clk->rate) && (tmp_rate > clk->new_rate)) {
+                               if (clk->ops->set_rate)
+                                       clk->ops->set_rate(clk->hw, clk->new_rate, clk->new_parent->rate);
+                       }
+               }
+
                __clk_set_parent(clk, clk->new_parent, clk->new_parent_index);
+       }
 
        if (clk->parent)
                best_parent_rate = clk->parent->rate;
index c216a0e9c1095bff45f4132951422373a26b937a..ffd38921c4b02ee60d6a2672813e5a36e4893793 100644 (file)
 #define CLK_IS_BASIC           BIT(5) /* Basic clk, can't do a to_clk_foo() */
 #define CLK_GET_RATE_NOCACHE   BIT(6) /* do not use the cached clk rate */
 #define CLK_SET_RATE_NO_REPARENT BIT(7) /* don't re-parent on rate change */
+#define CLK_SET_RATE_PARENT_IN_ORDER BIT(8) /* consider the order of re-parent
+                                               and set_div on rate change */
+
+
 
 /* Rockchip pll flags */
 #define CLK_PLL_3188           BIT(0)
index dce14cd2a41078cb5f70dfaf3f95730257b644d7..6ee9fbf109ef66ceca1424dbd8c8b37036b8f984 100644 (file)
@@ -28,6 +28,9 @@
 #define CLK_IS_BASIC           BIT(5) /* Basic clk, can't do a to_clk_foo() */
 #define CLK_GET_RATE_NOCACHE   BIT(6) /* do not use the cached clk rate */
 #define CLK_SET_RATE_NO_REPARENT BIT(7) /* don't re-parent on rate change */
+#define CLK_SET_RATE_PARENT_IN_ORDER BIT(8) /* consider the order of re-parent
+                                               and set_div on rate change */
+
 
 struct clk_hw;