rk3288: fix problem of mux clk with frac parent in rk3288
authordkl <dkl@rock-chips.com>
Tue, 25 Mar 2014 12:00:30 +0000 (20:00 +0800)
committerdkl <dkl@rock-chips.com>
Tue, 25 Mar 2014 12:16:37 +0000 (20:16 +0800)
Mux clk with frac parent in rk3288, like i2s/spdif/uart,
has problem when set rate before.

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

index 36661c0b989c12cc13bd1a20e7725f581769c531..8fcd38cfe44b88d7fa45efec5727761e6c8777dd 100755 (executable)
                                                clock-output-names = "clk_uart4";
                                                #clock-cells = <0>;
                                                rockchip,clkops-idx =
-                                                       <CLKOPS_RATE_UART>;
+                                                       <CLKOPS_RATE_RK3288_I2S>;
                                                rockchip,flags = <CLK_SET_RATE_PARENT>;
                                        };
 
                                                clocks = <&clk_i2s_pll>, <&i2s_frac>, <&i2s_clkin>, <&xin12m>;
                                                clock-output-names = "clk_i2s";
                                                #clock-cells = <0>;
+                                               rockchip,clkops-idx =
+                                                       <CLKOPS_RATE_RK3288_I2S>;
                                                rockchip,flags = <CLK_SET_RATE_PARENT>;
                                        };
 
                                                clocks = <&spdif_div>, <&spdif_frac>, <&xin12m>, <&dummy>;
                                                clock-output-names = "clk_spdif";
                                                #clock-cells = <0>;
+                                               rockchip,clkops-idx =
+                                                       <CLKOPS_RATE_RK3288_I2S>;
                                                rockchip,flags = <CLK_SET_RATE_PARENT>;
                                        };
 
                                                clock-output-names = "clk_uart0";
                                                #clock-cells = <0>;
                                                rockchip,clkops-idx =
-                                                       <CLKOPS_RATE_UART>;
+                                                       <CLKOPS_RATE_RK3288_I2S>;
                                                rockchip,flags = <CLK_SET_RATE_PARENT>;
                                        };
 
                                                clock-output-names = "clk_uart1";
                                                #clock-cells = <0>;
                                                rockchip,clkops-idx =
-                                                       <CLKOPS_RATE_UART>;
+                                                       <CLKOPS_RATE_RK3288_I2S>;
                                                rockchip,flags = <CLK_SET_RATE_PARENT>;
                                        };
 
                                                clock-output-names = "clk_uart2";
                                                #clock-cells = <0>;
                                                rockchip,clkops-idx =
-                                                       <CLKOPS_RATE_UART>;
+                                                       <CLKOPS_RATE_RK3288_I2S>;
                                                rockchip,flags = <CLK_SET_RATE_PARENT>;
                                        };
 
                                                clock-output-names = "clk_uart3";
                                                #clock-cells = <0>;
                                                rockchip,clkops-idx =
-                                                       <CLKOPS_RATE_UART>;
+                                                       <CLKOPS_RATE_RK3288_I2S>;
                                                rockchip,flags = <CLK_SET_RATE_PARENT>;
                                        };
 
                                                clocks = <&spdif_8ch_div>, <&spdif_8ch_frac>, <&xin12m>;
                                                clock-output-names = "clk_spdif_8ch";
                                                #clock-cells = <0>;
+                                               rockchip,clkops-idx =
+                                                       <CLKOPS_RATE_RK3288_I2S>;
                                                rockchip,flags = <CLK_SET_RATE_PARENT>;
                                        };
 
index 66795dd9d8f7114a09bf4bce0a6957de24549a02..3b59e3def34ff39bc50b0906831f3aefe5676f66 100644 (file)
@@ -476,6 +476,43 @@ const struct clk_ops clkops_rate_ddr = {
        .determine_rate = clk_ddr_determine_rate,
 };
 
+static unsigned long clk_3288_i2s_recalc_rate(struct clk_hw *hw,
+               unsigned long parent_rate)
+{
+       return parent_rate;
+}
+
+static long clk_3288_i2s_round_rate(struct clk_hw *hw, unsigned long rate,
+               unsigned long *prate)
+{
+       return rate;
+}
+
+static int clk_3288_i2s_set_rate(struct clk_hw *hw, unsigned long rate,
+               unsigned long parent_rate)
+{
+       struct clk *parent = __clk_get_parent(hw->clk);
+       struct clk *grand_p = __clk_get_parent(parent);
+
+
+       if (IS_ERR_OR_NULL(parent) || IS_ERR_OR_NULL(grand_p)) {
+               return 0;
+       }
+
+       if (parent->ops->set_rate) {
+               parent->ops->set_rate(parent->hw, rate/2, __clk_get_rate(grand_p));
+               parent->ops->set_rate(parent->hw, rate, __clk_get_rate(grand_p));
+       }
+
+       return 0;
+}
+
+const struct clk_ops clkops_rate_3288_i2s = {
+       .recalc_rate    = clk_3288_i2s_recalc_rate,
+       .round_rate     = clk_3288_i2s_round_rate,
+       .set_rate       = clk_3288_i2s_set_rate,
+};
+
 struct clk_ops_table rk_clkops_rate_table[] = {
        {.index = CLKOPS_RATE_MUX_DIV,          .clk_ops = &clkops_rate_auto_parent},
        {.index = CLKOPS_RATE_EVENDIV,          .clk_ops = &clkops_rate_evendiv},
@@ -485,6 +522,7 @@ struct clk_ops_table rk_clkops_rate_table[] = {
        {.index = CLKOPS_RATE_CORE,             .clk_ops = &clkops_rate_core},
        {.index = CLKOPS_RATE_CORE_CHILD,       .clk_ops = &clkops_rate_core_peri},
        {.index = CLKOPS_RATE_DDR,              .clk_ops = &clkops_rate_ddr},
+       {.index = CLKOPS_RATE_RK3288_I2S,       .clk_ops = &clkops_rate_3288_i2s},
        {.index = CLKOPS_RATE_I2S,              .clk_ops = NULL},
        {.index = CLKOPS_RATE_CIFOUT,           .clk_ops = NULL},
        {.index = CLKOPS_RATE_UART,             .clk_ops = NULL},
index eeca45ec68cbf868af1789242fc4b0e27baa2b3b..d05d846d84067b763109622775c54c84a154fed9 100644 (file)
@@ -50,6 +50,7 @@
 #define CLKOPS_RATE_CORE               11
 #define CLKOPS_RATE_CORE_CHILD         12
 #define CLKOPS_RATE_DDR                        13
+#define CLKOPS_RATE_RK3288_I2S         14
 #define CLKOPS_TABLE_END               (~0)
 
 #endif /* _DT_BINDINGS_CLOCK_ROCKCHIP_H */