clk: rk: add RKCLK_FIXED_RATE_TYPE and RKCLK_FIXED_FACTOR_TYPE
authordkl <dkl@rock-chips.com>
Thu, 27 Mar 2014 06:18:45 +0000 (14:18 +0800)
committerdkl <dkl@rock-chips.com>
Thu, 27 Mar 2014 07:21:13 +0000 (15:21 +0800)
arch/arm/boot/dts/rk3188-clocks.dtsi
arch/arm/boot/dts/rk3188.dtsi
arch/arm/boot/dts/rk3288-clocks.dtsi
drivers/clk/rockchip/clk.c

index e252ce4e1e9f1baf9f982a396db9b6191fbe0d84..5253980aa0b807a5170eae48cf48459d2f9787f9 100755 (executable)
                #size-cells = <1>;
                ranges = <0x0 0x20000000 0x0100>;
 
-               xin24m: xin24m {
-                       compatible = "fixed-clock";
-                       #clock-cells = <0>;
-                       clock-output-names = "xin24m";
-                       clock-frequency = <24000000>;
-               };
+               fixed_rate_cons {
+                       compatible = "rockchip,rk-fixed-rate-cons";
+
+                       xin24m: xin24m {
+                               compatible = "fixed-clock";
+                               #clock-cells = <0>;
+                               clock-output-names = "xin24m";
+                               clock-frequency = <24000000>;
+                       };
 
-               xin12m: xin12m {
-                       compatible = "fixed-clock";
-                       #clock-cells = <0>;
-                       clocks = <&xin24m>;
-                       clock-output-names = "xin12m";
-                       clock-frequency = <12000000>;
-               };
+                       xin12m: xin12m {
+                               compatible = "fixed-clock";
+                               #clock-cells = <0>;
+                               clocks = <&xin24m>;
+                               clock-output-names = "xin12m";
+                               clock-frequency = <12000000>;
+                       };
 
-               dummy: dummy {
-                       compatible = "fixed-clock";
-                       #clock-cells = <0>;
-                       clock-frequency = <0>;
-               };
+                       dummy: dummy {
+                               compatible = "fixed-clock";
+                               #clock-cells = <0>;
+                               clock-output-names = "dummy";
+                               clock-frequency = <0>;
+                       };
 
 
-               rmii_clkin: rmii_clkin {
-                       compatible = "fixed-clock";
-                       #clock-cells = <0>;
-                       clock-output-names = "rmii_clkin";
-                       clock-frequency = <0>;
-               };
+                       rmii_clkin: rmii_clkin {
+                               compatible = "fixed-clock";
+                               #clock-cells = <0>;
+                               clock-output-names = "rmii_clkin";
+                               clock-frequency = <0>;
+                       };
 
-               clk_hsadc_ext: clk_hsadc_ext {
-                       compatible = "fixed-clock";
-                       #clock-cells = <0>;
-                       clock-output-names = "clk_hsadc_ext";
-                       clock-frequency = <0>;
-               };
+                       clk_hsadc_ext: clk_hsadc_ext {
+                               compatible = "fixed-clock";
+                               #clock-cells = <0>;
+                               clock-output-names = "clk_hsadc_ext";
+                               clock-frequency = <0>;
+                       };
 
-               clk_cif_in: clk_cif_in {
-                       compatible = "fixed-clock";
-                       #clock-cells = <0>;
-                       clock-output-names = "clk_cif_in";
-                       clock-frequency = <0>;
-               };
+                       clk_cif_in: clk_cif_in {
+                               compatible = "fixed-clock";
+                               #clock-cells = <0>;
+                               clock-output-names = "clk_cif_in";
+                               clock-frequency = <0>;
+                       };
 
-               clk_otgphy0_480m: clk_otgphy0_480m {
-                       compatible = "fixed-factor-clock";
-                       clocks = <&clk_gates1 5>;
-                       clock-output-names = "clk_otgphy0_480m";
-                       clock-div = <1>;
-                       clock-mult = <20>;
-                       #clock-cells = <0>;
                };
 
-               clk_otgphy1_480m: clk_otgphy1_480m {
-                       compatible = "fixed-factor-clock";
-                       clocks = <&clk_gates1 6>;
-                       clock-output-names = "clk_otgphy1_480m";
-                       clock-div = <1>;
-                       clock-mult = <20>;
-                       #clock-cells = <0>;
+               fixed_factor_cons {
+                       compatible = "rockchip,rk-fixed-factor-cons";
+
+                       otgphy0_480m: otgphy0_480m {
+                               compatible = "fixed-factor-clock";
+                               clocks = <&clk_gates1 5>;
+                               clock-output-names = "otgphy0_480m";
+                               clock-div = <1>;
+                               clock-mult = <20>;
+                               #clock-cells = <0>;
+                       };
+
+                       otgphy1_480m: otgphy1_480m {
+                               compatible = "fixed-factor-clock";
+                               clocks = <&clk_gates1 6>;
+                               clock-output-names = "otgphy1_480m";
+                               clock-div = <1>;
+                               clock-mult = <20>;
+                               #clock-cells = <0>;
+                       };
+
                };
 
                clock_regs {
                                        clk_hsicphy480m: clk_hsicphy480m_mux {
                                                compatible = "rockchip,rk3188-mux-con";
                                                rockchip,bits = <0 2>;
-                                               clocks = <&clk_otgphy0_480m>, <&clk_otgphy1_480m>,
+                                               clocks = <&otgphy0_480m>, <&otgphy1_480m>,
                                                         <&clk_gpll>, <&clk_cpll>;
                                                clock-output-names = "clk_hsicphy480m";
                                                #clock-cells = <0>;
index d7842bd4e798c28c4c2ba1413f9353cdfc0e8e74..5191fadbebae382d260de7b133186849357f787b 100755 (executable)
                reg = <0x10240000 0x40000>;
                interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
                clocks = <&clk_hsicphy480m>, <&clk_gates7 4>,
-                 <&clk_hsicphy12m>, <&clk_otgphy1_480m>;
+                 <&clk_hsicphy12m>, <&otgphy1_480m>;
                clock-names = "hsicphy_480m", "hclk_hsic",
                       "hsicphy_12m", "hsic_usbphy1";
        };
index 8fcd38cfe44b88d7fa45efec5727761e6c8777dd..3750fabd138115b5484e46e012d08abbdbf238c5 100755 (executable)
                #size-cells = <1>;
                ranges = <0x0 0xFF760000 0x01b0>;
 
-               xin24m: xin24m {
-                       compatible = "fixed-clock";
-                       #clock-cells = <0>;
-                       clock-output-names = "xin24m";
-                       clock-frequency = <24000000>;
-               };
+               fixed_rate_cons {
+                       compatible = "rockchip,rk-fixed-rate-cons";
+
+                       xin24m: xin24m {
+                               compatible = "rockchip,rk-fixed-clock";
+                               clock-output-names = "xin24m";
+                               clock-frequency = <24000000>;
+                               #clock-cells = <0>;
+                       };
 
-               xin12m: xin12m {
-                       compatible = "fixed-clock";
-                       #clock-cells = <0>;
-                       clocks = <&xin24m>;
-                       clock-output-names = "xin12m";
-                       clock-frequency = <12000000>;
-               };
+                       xin12m: xin12m {
+                               compatible = "rockchip,rk-fixed-clock";
+                               clocks = <&xin24m>;
+                               clock-output-names = "xin12m";
+                               clock-frequency = <12000000>;
+                               #clock-cells = <0>;
+                       };
 
-               xin32k: xin32k {
-                       compatible = "fixed-clock";
-                       #clock-cells = <0>;
-                       clock-output-names = "xin32k";
-                       clock-frequency = <32000>;
-               };
+                       xin32k: xin32k {
+                               compatible = "rockchip,rk-fixed-clock";
+                               clock-output-names = "xin32k";
+                               clock-frequency = <32000>;
+                               #clock-cells = <0>;
+                       };
 
-               io_27m_in: io_27m_in {
-                       compatible = "fixed-clock";
-                       #clock-cells = <0>;
-                       clock-output-names = "io_27m_in";
-                       clock-frequency = <27000000>;
-               };
+                       io_27m_in: io_27m_in {
+                               compatible = "rockchip,rk-fixed-clock";
+                               clock-output-names = "io_27m_in";
+                               clock-frequency = <27000000>;
+                               #clock-cells = <0>;
+                       };
 
-               dummy: dummy {
-                       compatible = "fixed-clock";
-                       #clock-cells = <0>;
-                       clock-frequency = <0>;
-               };
+                       dummy: dummy {
+                               compatible = "rockchip,rk-fixed-clock";
+                               clock-output-names = "dummy";
+                               clock-frequency = <0>;
+                               #clock-cells = <0>;
+                       };
 
-               i2s_clkin: i2s_clkin {
-                       compatible = "fixed-clock";
-                       #clock-cells = <0>;
-                       clock-output-names = "i2s_clkin";
-                       clock-frequency = <0>;
-               };
+                       i2s_clkin: i2s_clkin {
+                               compatible = "rockchip,rk-fixed-clock";
+                               clock-output-names = "i2s_clkin";
+                               clock-frequency = <0>;
+                               #clock-cells = <0>;
+                       };
 
-               edp_24m_clkin: edp_24m_clkin {
-                       compatible = "fixed-clock";
-                       #clock-cells = <0>;
-                       clock-output-names = "edp_24m_clkin";
-                       clock-frequency = <0>;
-               };
+                       edp_24m_clkin: edp_24m_clkin {
+                               compatible = "rockchip,rk-fixed-clock";
+                               #clock-cells = <0>;
+                               clock-output-names = "edp_24m_clkin";
+                               clock-frequency = <0>;
+                       };
 
-               gmac_clkin: gmac_clkin {
-                       compatible = "fixed-clock";
-                       #clock-cells = <0>;
-                       clock-output-names = "gmac_clkin";
-                       clock-frequency = <0>;
-               };
+                       gmac_clkin: gmac_clkin {
+                               compatible = "rockchip,rk-fixed-clock";
+                               #clock-cells = <0>;
+                               clock-output-names = "gmac_clkin";
+                               clock-frequency = <0>;
+                       };
 
-               clk_hsadc_ext: clk_hsadc_ext {
-                       compatible = "fixed-clock";
-                       #clock-cells = <0>;
-                       clock-output-names = "clk_hsadc_ext";
-                       clock-frequency = <0>;
-               };
+                       clk_hsadc_ext: clk_hsadc_ext {
+                               compatible = "rockchip,rk-fixed-clock";
+                               #clock-cells = <0>;
+                               clock-output-names = "clk_hsadc_ext";
+                               clock-frequency = <0>;
+                       };
 
-               jtag_clkin: jtag_clkin {
-                       compatible = "fixed-clock";
-                       #clock-cells = <0>;
-                       clock-output-names = "jtag_clkin";
-                       clock-frequency = <0>;
-               };
+                       jtag_clkin: jtag_clkin {
+                               compatible = "rockchip,rk-fixed-clock";
+                               #clock-cells = <0>;
+                               clock-output-names = "jtag_clkin";
+                               clock-frequency = <0>;
+                       };
 
-               pclkin_cif: pclkin_cif {
-                       compatible = "fixed-clock";
-                       #clock-cells = <0>;
-                       clock-output-names = "pclkin_cif";
-                       clock-frequency = <0>;
-               };
+                       pclkin_cif: pclkin_cif {
+                               compatible = "rockchip,rk-fixed-clock";
+                               #clock-cells = <0>;
+                               clock-output-names = "pclkin_cif";
+                               clock-frequency = <0>;
+                       };
 
-               pclkin_isp: pclkin_isp {
-                       compatible = "fixed-clock";
-                       #clock-cells = <0>;
-                       clock-output-names = "pclkin_isp";
-                       clock-frequency = <0>;
-               };
+                       pclkin_isp: pclkin_isp {
+                               compatible = "rockchip,rk-fixed-clock";
+                               #clock-cells = <0>;
+                               clock-output-names = "pclkin_isp";
+                               clock-frequency = <0>;
+                       };
 
-               clk_otgphy0_480m: clk_otgphy0_480m {
-                       compatible = "fixed-factor-clock";
-                       clocks = <&clk_gates13 4>;
-                       clock-output-names = "clk_otgphy0_480m";
-                       clock-div = <1>;
-                       clock-mult = <20>;
-                       #clock-cells = <0>;
                };
 
-               clk_otgphy1_480m: clk_otgphy1_480m {
-                       compatible = "fixed-factor-clock";
-                       clocks = <&clk_gates13 5>;
-                       clock-output-names = "clk_otgphy1_480m";
-                       clock-div = <1>;
-                       clock-mult = <20>;
-                       #clock-cells = <0>;
-               };
+               fixed_factor_cons {
+                               compatible = "rockchip,rk-fixed-factor-cons";
 
-               clk_otgphy2_480m: clk_otgphy2_480m {
-                       compatible = "fixed-factor-clock";
-                       clocks = <&clk_gates13 6>;
-                       clock-output-names = "clk_otgphy2_480m";
-                       clock-div = <1>;
-                       clock-mult = <20>;
-                       #clock-cells = <0>;
-               };
+                       otgphy0_480m: otgphy0_480m {
+                               compatible = "rockchip,rk-fixed-factor-clock";
+                               clocks = <&clk_gates13 4>;
+                               clock-output-names = "otgphy0_480m";
+                               clock-div = <1>;
+                               clock-mult = <20>;
+                               #clock-cells = <0>;
+                       };
 
-               clk_hsadc_inv: clk_hsadc_inv {
-                       compatible = "fixed-factor-clock";
-                       clocks = <&clk_hsadc_out>;
-                       clock-output-names = "clk_hsadc_inv";
-                       clock-div = <1>;
-                       clock-mult = <1>;
-                       #clock-cells = <0>;
-               };
+                       otgphy1_480m: otgphy1_480m {
+                               compatible = "rockchip,rk-fixed-factor-clock";
+                               clocks = <&clk_gates13 5>;
+                               clock-output-names = "otgphy1_480m";
+                               clock-div = <1>;
+                               clock-mult = <20>;
+                               #clock-cells = <0>;
+                       };
 
-               pclkin_cif_inv: pclkin_cif_inv {
-                       compatible = "fixed-factor-clock";
-                       clocks = <&clk_gates16 0>;
-                       clock-output-names = "pclkin_cif_inv";
-                       clock-div = <1>;
-                       clock-mult = <1>;
-                       #clock-cells = <0>;
-               };
+                       otgphy2_480m: otgphy2_480m {
+                               compatible = "rockchip,rk-fixed-factor-clock";
+                               clocks = <&clk_gates13 6>;
+                               clock-output-names = "otgphy2_480m";
+                               clock-div = <1>;
+                               clock-mult = <20>;
+                               #clock-cells = <0>;
+                       };
 
-               pclkin_isp_inv: pclkin_isp_inv {
-                       compatible = "fixed-factor-clock";
-                       clocks = <&clk_gates16 3>;
-                       clock-output-names = "pclkin_isp_inv";
-                       clock-div = <1>;
-                       clock-mult = <1>;
-                       #clock-cells = <0>;
-               };
+                       clk_hsadc_inv: clk_hsadc_inv {
+                               compatible = "rockchip,rk-fixed-factor-clock";
+                               clocks = <&clk_hsadc_out>;
+                               clock-output-names = "clk_hsadc_inv";
+                               clock-div = <1>;
+                               clock-mult = <1>;
+                               #clock-cells = <0>;
+                       };
 
-               hclk_vepu: hclk_vepu {
-                       compatible = "fixed-factor-clock";
-                       clocks = <&clk_vepu>;
-                       clock-output-names = "hclk_vepu";
-                       clock-div = <4>;
-                       clock-mult = <1>;
-                       #clock-cells = <0>;
-               };
+                       pclkin_cif_inv: pclkin_cif_inv {
+                               compatible = "rockchip,rk-fixed-factor-clock";
+                               clocks = <&clk_gates16 0>;
+                               clock-output-names = "pclkin_cif_inv";
+                               clock-div = <1>;
+                               clock-mult = <1>;
+                               #clock-cells = <0>;
+                       };
 
-               hclk_vdpu: hclk_vdpu {
-                       compatible = "fixed-factor-clock";
-                       clocks = <&clk_vdpu>;
-                       clock-output-names = "hclk_vdpu";
-                       clock-div = <4>;
-                       clock-mult = <1>;
-                       #clock-cells = <0>;
+                       pclkin_isp_inv: pclkin_isp_inv {
+                               compatible = "rockchip,rk-fixed-factor-clock";
+                               clocks = <&clk_gates16 3>;
+                               clock-output-names = "pclkin_isp_inv";
+                               clock-div = <1>;
+                               clock-mult = <1>;
+                               #clock-cells = <0>;
+                       };
+
+                       hclk_vepu: hclk_vepu {
+                               compatible = "rockchip,rk-fixed-factor-clock";
+                               clocks = <&clk_vepu>;
+                               clock-output-names = "hclk_vepu";
+                               clock-div = <4>;
+                               clock-mult = <1>;
+                               #clock-cells = <0>;
+                       };
+
+                       hclk_vdpu: hclk_vdpu {
+                               compatible = "rockchip,rk-fixed-factor-clock";
+                               clocks = <&clk_vdpu>;
+                               clock-output-names = "hclk_vdpu";
+                               clock-div = <4>;
+                               clock-mult = <1>;
+                               #clock-cells = <0>;
+                       };
                };
 
                clock_regs {
                                        usbphy_480m: usbphy_480m_mux {
                                                compatible = "rockchip,rk3188-mux-con";
                                                rockchip,bits = <11 2>;
-                                               clocks = <&clk_otgphy0_480m>, <&clk_otgphy1_480m>, <&clk_otgphy2_480m>;
+                                               clocks = <&otgphy0_480m>, <&otgphy1_480m>, <&otgphy2_480m>;
                                                clock-output-names = "usbphy_480m";
                                                #clock-cells = <0>;
                                        };
index 31bda92a0bb23e3907919e6733378fd86d7d23d4..8816392e444a67c67d3489b0e6c9232cfb78eb22 100755 (executable)
@@ -68,6 +68,20 @@ struct rkclk_pllinfo {
        u32                     clkops_idx;
 };
 
+struct rkclk_fixed_rate_info {
+       const char              *clk_name;
+       struct device_node      *np;
+       struct clk_fixed_rate   *fixed_rate;
+       const char              *parent_name;
+};
+
+struct rkclk_fixed_factor_info {
+       const char              *clk_name;
+       struct device_node      *np;
+       struct clk_fixed_factor   *fixed_factor;
+       const char              *parent_name;
+};
+
 struct rkclk {
        const char              *clk_name;
        //struct device_node    *np;
@@ -78,17 +92,22 @@ struct rkclk {
        struct rkclk_fracinfo   *frac_info;
        struct rkclk_pllinfo    *pll_info;
        struct rkclk_gateinfo   *gate_info;
+       struct rkclk_fixed_rate_info *fixed_rate_info;
+       struct rkclk_fixed_factor_info *fixed_factor_info;
        struct list_head        node;
 };
 
 static DEFINE_SPINLOCK(clk_lock);
 LIST_HEAD(rk_clks);
 
-#define RKCLK_PLL_TYPE (1 << 0)
-#define RKCLK_MUX_TYPE (1 << 1)
-#define RKCLK_DIV_TYPE (1 << 2)
-#define RKCLK_FRAC_TYPE        (1 << 3)
-#define RKCLK_GATE_TYPE        (1 << 4)
+#define RKCLK_PLL_TYPE         (1 << 0)
+#define RKCLK_MUX_TYPE         (1 << 1)
+#define RKCLK_DIV_TYPE         (1 << 2)
+#define RKCLK_FRAC_TYPE                (1 << 3)
+#define RKCLK_GATE_TYPE                (1 << 4)
+#define RKCLK_FIXED_RATE_TYPE  (1 << 5)
+#define RKCLK_FIXED_FACTOR_TYPE        (1 << 6)
+
 
 static int rkclk_init_muxinfo(struct device_node *np, void __iomem *addr)
 {
@@ -787,6 +806,243 @@ out:
        return ret;
 }
 
+static int __init rkclk_init_fixed_rate(struct device_node *np)
+{
+       struct device_node *node = NULL;
+       struct rkclk_fixed_rate_info *fixed_rate_info = NULL;
+       struct clk_fixed_rate *fixed_rate = NULL;
+       u32 rate;
+       int ret = 0;
+       u8 found = 0;
+       struct rkclk *rkclk = NULL;
+
+
+       for_each_available_child_of_node(np, node) {
+               fixed_rate_info = kzalloc(sizeof(struct rkclk_fixed_rate_info),
+                       GFP_KERNEL);
+               if (!fixed_rate_info) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
+
+               fixed_rate_info->fixed_rate = kzalloc(sizeof(struct clk_fixed_rate),
+                       GFP_KERNEL);
+               if (!fixed_rate_info->fixed_rate) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
+               fixed_rate = fixed_rate_info->fixed_rate;
+
+               fixed_rate_info->np = node;
+
+               ret = of_property_read_string_index(node, "clock-output-names",
+                               0, &fixed_rate_info->clk_name);
+               if (ret)
+                       goto out;
+
+               fixed_rate_info->parent_name = of_clk_get_parent_name(node, 0);
+
+               ret = of_property_read_u32(node, "clock-frequency", &rate);
+               if (ret != 0) {
+                       clk_err("%s: can not get clock-frequency\n", __func__);
+                       goto out;
+               }
+               fixed_rate->fixed_rate = (unsigned long)rate;
+
+               found = 0;
+               list_for_each_entry(rkclk, &rk_clks, node) {
+                       if (strcmp(fixed_rate_info->clk_name, rkclk->clk_name) == 0) {
+                               if (rkclk->fixed_rate_info != NULL) {
+                                       clk_err("%s %d:\n", __func__, __LINE__);
+                                       clk_err("This clk(%s) has been used,"
+                                                       "will be overwrited here!\n",
+                                                       rkclk->clk_name);
+                               }
+                               clk_debug("%s: find match %s\n", __func__,
+                                               rkclk->clk_name);
+                               found = 1;
+                               rkclk->fixed_rate_info = fixed_rate_info;
+                               rkclk->clk_type |= RKCLK_FIXED_RATE_TYPE;
+                               rkclk->flags |= CLK_IS_ROOT;
+                               break;
+                       }
+               }
+
+               if (!found) {
+                       rkclk = kzalloc(sizeof(struct rkclk), GFP_KERNEL);
+                       if (!rkclk) {
+                               ret = -ENOMEM;
+                               goto out;
+                       }
+                       rkclk->clk_name = fixed_rate_info->clk_name;
+                       rkclk->fixed_rate_info = fixed_rate_info;
+                       rkclk->clk_type = RKCLK_FIXED_RATE_TYPE;
+                       rkclk->flags = CLK_IS_ROOT;
+                       clk_debug("%s: creat %s\n", __func__, rkclk->clk_name);
+                       list_add_tail(&rkclk->node, &rk_clks);
+               }
+       }
+
+out:
+       if (ret) {
+               clk_err("%s error, ret = %d\n", __func__, ret);
+               if (fixed_rate_info) {
+                       if (fixed_rate_info->fixed_rate)
+                               kfree(fixed_rate_info->fixed_rate);
+                       kfree(fixed_rate_info);
+               }
+               if (rkclk)
+                       kfree(rkclk);
+       }
+
+       return ret;
+}
+
+static int __init rkclk_init_fixed_factor(struct device_node *np)
+{
+       struct device_node *node = NULL;
+       struct rkclk_fixed_factor_info *fixed_factor_info = NULL;
+       struct clk_fixed_factor *fixed_factor = NULL;
+       u32 flags, mult, div;
+       int ret = 0;
+       u8 found = 0;
+       struct rkclk *rkclk = NULL;
+
+
+       for_each_available_child_of_node(np, node) {
+               fixed_factor_info = kzalloc(sizeof(struct rkclk_fixed_factor_info),
+                       GFP_KERNEL);
+               if (!fixed_factor_info) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
+
+               fixed_factor_info->fixed_factor = kzalloc(sizeof(struct clk_fixed_factor),
+                       GFP_KERNEL);
+               if (!fixed_factor_info->fixed_factor) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
+               fixed_factor = fixed_factor_info->fixed_factor;
+
+               fixed_factor_info->np = node;
+
+               ret = of_property_read_string_index(node, "clock-output-names",
+                               0, &fixed_factor_info->clk_name);
+               if (ret)
+                       goto out;
+
+               fixed_factor_info->parent_name = of_clk_get_parent_name(node, 0);
+
+               ret = of_property_read_u32(node, "rockchip,flags", &flags);
+               if (ret != 0) {
+                       flags = 0;
+                       ret = 0;
+               }
+
+               ret = of_property_read_u32(node, "clock-mult", &mult);
+               if (ret != 0) {
+                       clk_err("%s: can not get mult\n", __func__);
+                       goto out;
+               }
+               fixed_factor->mult = (unsigned int)mult;
+
+               ret = of_property_read_u32(node, "clock-div", &div);
+               if (ret != 0) {
+                       clk_err("%s: can not get div\n", __func__);
+                       goto out;
+               }
+               fixed_factor->div = (unsigned int)div;
+
+
+               found = 0;
+               list_for_each_entry(rkclk, &rk_clks, node) {
+                       if (strcmp(fixed_factor_info->clk_name, rkclk->clk_name) == 0) {
+                               if (rkclk->fixed_factor_info != NULL) {
+                                       clk_err("%s %d:\n", __func__, __LINE__);
+                                       clk_err("This clk(%s) has been used,"
+                                                       "will be overwrited here!\n",
+                                                       rkclk->clk_name);
+                               }
+                               clk_debug("%s: find match %s\n", __func__,
+                                               rkclk->clk_name);
+                               found = 1;
+                               rkclk->fixed_factor_info = fixed_factor_info;
+                               rkclk->clk_type |= RKCLK_FIXED_FACTOR_TYPE;
+                               rkclk->flags |= flags;
+                               break;
+                       }
+               }
+
+               if (!found) {
+                       rkclk = kzalloc(sizeof(struct rkclk), GFP_KERNEL);
+                       if (!rkclk) {
+                               ret = -ENOMEM;
+                               goto out;
+                       }
+                       rkclk->clk_name = fixed_factor_info->clk_name;
+                       rkclk->fixed_factor_info = fixed_factor_info;
+                       rkclk->clk_type = RKCLK_FIXED_FACTOR_TYPE;
+                       rkclk->flags = flags;
+                       clk_debug("%s: creat %s\n", __func__, rkclk->clk_name);
+                       list_add_tail(&rkclk->node, &rk_clks);
+               }
+       }
+
+out:
+       if (ret) {
+               clk_err("%s error, ret = %d\n", __func__, ret);
+               if (fixed_factor_info) {
+                       if (fixed_factor_info->fixed_factor)
+                               kfree(fixed_factor_info->fixed_factor);
+                       kfree(fixed_factor_info);
+               }
+               if (rkclk)
+                       kfree(rkclk);
+       }
+
+       return ret;
+}
+
+static int __init rkclk_init_regcon(struct device_node *np)
+{
+       struct device_node *node;
+       const char *compatible;
+       int ret = 0;
+
+
+       for_each_available_child_of_node(np, node) {
+               clk_debug("\n");
+               of_property_read_string(node, "compatible", &compatible);
+
+               if (strcmp(compatible, "rockchip,rk-pll-cons") == 0) {
+                       ret = rkclk_init_pllcon(node);
+                       if (ret != 0) {
+                               clk_err("%s: init pll cons err\n", __func__);
+                               goto out;
+                       }
+               } else if (strcmp(compatible, "rockchip,rk-sel-cons") == 0) {
+                       ret = rkclk_init_selcon(node);
+                       if (ret != 0) {
+                               clk_err("%s: init sel cons err\n", __func__);
+                               goto out;
+                       }
+               } else if (strcmp(compatible, "rockchip,rk-gate-cons") == 0) {
+                       ret = rkclk_init_gatecon(node);
+                       if (ret != 0) {
+                               clk_err("%s: init gate cons err\n", __func__);
+                               goto out;
+                       }
+               } else {
+                       clk_err("%s: unknown\n", __func__);
+                       ret = -EINVAL;
+                       goto out;
+               }
+       }
+out:
+       return ret;
+}
+
 static int rkclk_register(struct rkclk *rkclk)
 {
        struct clk              *clk = NULL;
@@ -795,6 +1051,8 @@ static int rkclk_register(struct rkclk *rkclk)
        struct clk_gate         *gate = NULL;
        struct clk_pll          *pll = NULL;
        struct clk_divider      *frac = NULL;
+       struct clk_fixed_rate   *fixed_rate = NULL;
+       struct clk_fixed_factor *fixed_factor = NULL;
 
        struct clk_hw           *mux_hw = NULL;
        const struct clk_ops    *mux_ops = NULL;
@@ -805,6 +1063,7 @@ static int rkclk_register(struct rkclk *rkclk)
 
        int                     parent_num;
        const char              **parent_names = NULL;
+       u8                      rate_type_count = 0;
 
 
        if (rkclk && rkclk->clk_name) {
@@ -826,6 +1085,10 @@ static int rkclk_register(struct rkclk *rkclk)
                pll = rkclk->pll_info->pll;
        if (rkclk->frac_info && rkclk->frac_info->frac)
                frac = rkclk->frac_info->frac;
+       if (rkclk->fixed_rate_info && rkclk->fixed_rate_info->fixed_rate)
+               fixed_rate = rkclk->fixed_rate_info->fixed_rate;
+       if (rkclk->fixed_factor_info && rkclk->fixed_factor_info->fixed_factor)
+               fixed_factor = rkclk->fixed_factor_info->fixed_factor;
 
        switch (rkclk->clk_type) {
                case RKCLK_MUX_TYPE:
@@ -874,23 +1137,47 @@ static int rkclk_register(struct rkclk *rkclk)
                                        gate->reg, gate->bit_idx, gate->flags,
                                        &clk_lock);
                        goto add_lookup;
-               case (RKCLK_DIV_TYPE|RKCLK_PLL_TYPE):
-               case (RKCLK_DIV_TYPE|RKCLK_FRAC_TYPE):
-               case (RKCLK_PLL_TYPE|RKCLK_FRAC_TYPE):
-               case (RKCLK_DIV_TYPE|RKCLK_PLL_TYPE|RKCLK_FRAC_TYPE):
-                       clk_err("Invalid rkclk type!\n");
-                       return -EINVAL;
+               case RKCLK_FIXED_RATE_TYPE:
+                       clk_debug("use clk_register_fixed_rate\n");
+                       clk = clk_register_fixed_rate(NULL, rkclk->clk_name,
+                                       rkclk->fixed_rate_info->parent_name,
+                                       rkclk->flags, fixed_rate->fixed_rate);
+                       goto add_lookup;
+               case RKCLK_FIXED_FACTOR_TYPE:
+                       clk_debug("use clk_register_fixed_factor\n");
+                       clk = clk_register_fixed_factor(NULL, rkclk->clk_name,
+                                       rkclk->fixed_factor_info->parent_name,
+                                       rkclk->flags, fixed_factor->mult,
+                                       fixed_factor->div);
+                       goto add_lookup;
                default:
                        goto rgs_comp;
        }
 
 rgs_comp:
+
+       if (rkclk->clk_type & RKCLK_DIV_TYPE)
+               rate_type_count++;
+       if (rkclk->clk_type & RKCLK_PLL_TYPE)
+               rate_type_count++;
+       if (rkclk->clk_type & RKCLK_FRAC_TYPE)
+               rate_type_count++;
+       if (rkclk->clk_type & RKCLK_FIXED_RATE_TYPE)
+               rate_type_count++;
+       if (rkclk->clk_type & RKCLK_FIXED_FACTOR_TYPE)
+               rate_type_count++;
+
+       if (rate_type_count > 1) {
+               clk_err("Invalid rkclk type!\n");
+               return -EINVAL;
+       }
+
        clk_debug("use clk_register_composite\n");
 
        /* prepare args for clk_register_composite */
 
        /* prepare parent_num && parent_names
-        * priority: MUX > DIV=PLL=FRAC > GATE
+        * priority: MUX > DIV=PLL=FRAC=FIXED_FACTOR > GATE
         */
        if (rkclk->clk_type & RKCLK_MUX_TYPE) {
                parent_num = rkclk->mux_info->parent_num;
@@ -904,6 +1191,9 @@ rgs_comp:
        } else if (rkclk->clk_type & RKCLK_FRAC_TYPE) {
                parent_num = 1;
                parent_names = &(rkclk->frac_info->parent_name);
+       } else if (rkclk->clk_type & RKCLK_FIXED_FACTOR_TYPE) {
+               parent_num = 1;
+               parent_names = &(rkclk->fixed_factor_info->parent_name);
        } else if (rkclk->clk_type & RKCLK_GATE_TYPE) {
                parent_num = 1;
                parent_names = &(rkclk->gate_info->parent_name);
@@ -916,7 +1206,7 @@ rgs_comp:
        }
 
        /* prepare rate_hw && rate_ops
-        * priority: DIV=PLL=FRAC > MUX
+        * priority: DIV=PLL=FRAC=FIXED_FACTOR > MUX
         */
        if (rkclk->clk_type & RKCLK_DIV_TYPE) {
                rate_hw = &div->hw;
@@ -930,6 +1220,9 @@ rgs_comp:
        } else if (rkclk->clk_type & RKCLK_FRAC_TYPE) {
                rate_hw = &frac->hw;
                rate_ops = rk_get_clkops(rkclk->frac_info->clkops_idx);
+       } else if (rkclk->clk_type & RKCLK_FIXED_FACTOR_TYPE) {
+               rate_hw = &fixed_factor->hw;
+               rate_ops = &clk_fixed_factor_ops;
        } else if ((rkclk->clk_type & RKCLK_MUX_TYPE) &&
                        (rkclk->mux_info->clkops_idx != CLKOPS_TABLE_END)) {
                /* when a mux node has specified clkops_idx, prepare rate_hw &&
@@ -970,7 +1263,7 @@ add_lookup:
        return 0;
 }
 
-static int rkclk_add_provider(struct device_node *np)
+static int _rkclk_add_provider(struct device_node *np)
 {
        int i, cnt, ret = 0;
        const char *name = NULL;
@@ -1044,6 +1337,53 @@ static int rkclk_add_provider(struct device_node *np)
        return ret;
 }
 
+static void rkclk_add_provider(struct device_node *np)
+{
+       struct device_node *node, *node_reg, *node_tmp, *node_prd;
+       const char *compatible;
+
+
+       for_each_available_child_of_node(np, node) {
+               of_property_read_string(node, "compatible", &compatible);
+
+               if (strcmp(compatible, "rockchip,rk-fixed-rate-cons") == 0) {
+                       for_each_available_child_of_node(node, node_prd) {
+                                _rkclk_add_provider(node_prd);
+                       }
+               } else if (strcmp(compatible, "rockchip,rk-fixed-factor-cons") == 0) {
+                       for_each_available_child_of_node(node, node_prd) {
+                                _rkclk_add_provider(node_prd);
+                       }
+               } else if (strcmp(compatible, "rockchip,rk-clock-regs") == 0) {
+                       for_each_available_child_of_node(node, node_reg) {
+                               of_property_read_string(node_reg, "compatible", &compatible);
+
+                               if (strcmp(compatible, "rockchip,rk-pll-cons") == 0) {
+                                       for_each_available_child_of_node(node_reg, node_prd) {
+                                               _rkclk_add_provider(node_prd);
+                                       }
+                               } else if (strcmp(compatible, "rockchip,rk-sel-cons") == 0) {
+                                       for_each_available_child_of_node(node_reg, node_tmp) {
+                                               for_each_available_child_of_node(node_tmp,
+                                                       node_prd) {
+                                                       _rkclk_add_provider(node_prd);
+                                               }
+                                       }
+                               } else if (strcmp(compatible, "rockchip,rk-gate-cons") == 0) {
+                                       for_each_available_child_of_node(node_reg, node_prd) {
+                                                _rkclk_add_provider(node_prd);
+                                       }
+                               } else {
+                                       clk_err("%s: unknown\n", __func__);
+                               }
+                       }
+               } else {
+                       clk_err("%s: unknown\n", __func__);
+               }
+       }
+
+}
+
 static void rkclk_cache_parents(struct rkclk *rkclk)
 {
        struct clk *clk, *parent;
@@ -1104,6 +1444,8 @@ void rkclk_dump_info(struct rkclk *rkclk)
        struct clk_gate         *gate = NULL;
        struct clk_pll          *pll = NULL;
        struct clk_divider      *frac = NULL;
+       struct clk_fixed_rate   *fixed_rate = NULL;
+       struct clk_fixed_factor *fixed_factor = NULL;
        int i;
 
 
@@ -1121,6 +1463,10 @@ void rkclk_dump_info(struct rkclk *rkclk)
                frac = rkclk->frac_info->frac;
        if (rkclk->gate_info && rkclk->gate_info->gate)
                gate = rkclk->gate_info->gate;
+       if (rkclk->fixed_rate_info && rkclk->fixed_rate_info->fixed_rate)
+               fixed_rate = rkclk->fixed_rate_info->fixed_rate;
+       if (rkclk->fixed_factor_info && rkclk->fixed_factor_info->fixed_factor)
+               fixed_factor = rkclk->fixed_factor_info->fixed_factor;
 
        if (rkclk->mux_info) {
                clk_debug("\t\tmux_info: name=%s, clkops_idx=%u\n",
@@ -1135,6 +1481,7 @@ void rkclk_dump_info(struct rkclk *rkclk)
                                        mux->mask, mux->shift, mux->flags);
                }
        }
+
        if (rkclk->pll_info) {
                clk_debug("\t\tpll_info: name=%s, parent=%s, clkops_idx=0x%x\n",
                                rkclk->pll_info->clk_name,
@@ -1151,6 +1498,7 @@ void rkclk_dump_info(struct rkclk *rkclk)
                                        pll->flags);
                }
        }
+
        if (rkclk->div_info) {
                clk_debug("\t\tdiv_info: name=%s, div_type=0x%x, parent=%s, "
                                "clkops_idx=%d\n",
@@ -1164,6 +1512,7 @@ void rkclk_dump_info(struct rkclk *rkclk)
                                        div->shift, div->width, div->flags);
                }
        }
+
        if (rkclk->frac_info) {
                clk_debug("\t\tfrac_info: name=%s, parent=%s, clkops_idx=%d\n",
                                rkclk->frac_info->clk_name,
@@ -1175,6 +1524,7 @@ void rkclk_dump_info(struct rkclk *rkclk)
                                        frac->shift, frac->width, frac->flags);
                }
        }
+
        if (rkclk->gate_info) {
                clk_debug("\t\tgate_info: name=%s, parent=%s\n",
                                rkclk->gate_info->clk_name,
@@ -1185,6 +1535,25 @@ void rkclk_dump_info(struct rkclk *rkclk)
                                        gate->bit_idx, gate->flags);
                }
        }
+
+       if (rkclk->fixed_rate_info) {
+               clk_debug("\t\tfixed_rate_info: name=%s\n",
+                               rkclk->fixed_rate_info->clk_name);
+               if (fixed_rate) {
+                       clk_debug("\t\tfixed_rate=%lu, fixed_rate_flags=0x%x\n",
+                               fixed_rate->fixed_rate, fixed_rate->flags);
+               }
+       }
+
+       if (rkclk->fixed_factor_info) {
+               clk_debug("\t\tfixed_factor_info: name=%s, parent=%s\n",
+                               rkclk->fixed_factor_info->clk_name,
+                               rkclk->fixed_factor_info->parent_name);
+               if (fixed_factor) {
+                       clk_debug("\t\tfixed_factor: mult=%u, div=%u\n",
+                               fixed_factor->mult, fixed_factor->div);
+               }
+       }
 }
 #else
 void rkclk_dump_info(struct rkclk *rkclk) {}
@@ -1294,10 +1663,10 @@ void rkclk_init_clks(struct device_node *node);
 static struct device_node * clk_root_node=NULL;
 static void __init rk_clk_tree_init(struct device_node *np)
 {
-       struct device_node *node, *node_tmp, *node_prd, *node_init;
+       struct device_node *node, *node_init;
        struct rkclk *rkclk;
        const char *compatible;
-    
+
        printk("%s start! cru base = 0x%08x\n", __func__, (u32)RK_CRU_VIRT);
 
        node_init=of_find_node_by_name(NULL,"clocks-init");
@@ -1305,29 +1674,27 @@ static void __init rk_clk_tree_init(struct device_node *np)
                clk_err("%s: can not get clocks-init node\n", __func__);
                return;
        }
-        clk_root_node=np;
+        clk_root_node=of_find_node_by_name(NULL,"clock_regs");
+
 
        for_each_available_child_of_node(np, node) {
                clk_debug("\n");
                of_property_read_string(node, "compatible",
                                &compatible);
 
-               if (strcmp(compatible, "fixed-clock") == 0) {
-                       clk_debug("do nothing for fixed-clock node\n");
-                       continue;
-               } else if (strcmp(compatible, "rockchip,rk-pll-cons") == 0) {
-                       if (rkclk_init_pllcon(node) != 0) {
-                               clk_err("%s: init pll cons err\n", __func__);
+               if (strcmp(compatible, "rockchip,rk-fixed-rate-cons") == 0) {
+                       if (rkclk_init_fixed_rate(node) != 0) {
+                               clk_err("%s: init fixed_rate err\n", __func__);
                                return ;
                        }
-               } else if (strcmp(compatible, "rockchip,rk-sel-cons") == 0) {
-                       if (rkclk_init_selcon(node) != 0) {
-                               clk_err("%s: init sel cons err\n", __func__);
+               } else if (strcmp(compatible, "rockchip,rk-fixed-factor-cons") == 0) {
+                       if (rkclk_init_fixed_factor(node) != 0) {
+                               clk_err("%s: init fixed_factor err\n", __func__);
                                return ;
                        }
-               } else if (strcmp(compatible, "rockchip,rk-gate-cons") == 0) {
-                       if (rkclk_init_gatecon(node) != 0) {
-                               clk_err("%s: init gate cons err\n", __func__);
+               } else if (strcmp(compatible, "rockchip,rk-clock-regs") == 0) {
+                       if (rkclk_init_regcon(node) != 0) {
+                               clk_err("%s: init reg cons err\n", __func__);
                                return ;
                        }
                } else {
@@ -1342,32 +1709,7 @@ static void __init rk_clk_tree_init(struct device_node *np)
                rkclk_register(rkclk);
        }
 
-       for_each_available_child_of_node(np, node) {
-               of_property_read_string(node, "compatible",
-                               &compatible);
-
-               if (strcmp(compatible, "fixed-clock") == 0) {
-                       clk_debug("do nothing for fixed-clock node\n");
-                       continue;
-               } else if (strcmp(compatible, "rockchip,rk-pll-cons") == 0) {
-                       for_each_available_child_of_node(node, node_prd) {
-                               rkclk_add_provider(node_prd);
-                       }
-               } else if (strcmp(compatible, "rockchip,rk-sel-cons") == 0) {
-                       for_each_available_child_of_node(node, node_tmp) {
-                               for_each_available_child_of_node(node_tmp,
-                                               node_prd) {
-                                       rkclk_add_provider(node_prd);
-                               }
-                       }
-               } else if (strcmp(compatible, "rockchip,rk-gate-cons") == 0) {
-                       for_each_available_child_of_node(node, node_prd) {
-                               rkclk_add_provider(node_prd);
-                       }
-               } else {
-                       clk_err("%s: unknown\n", __func__);
-               }
-       }
+       rkclk_add_provider(np);
 
        /* fill clock parents cache after all clocks have been registered */
        list_for_each_entry(rkclk, &rk_clks, node) {
@@ -1379,7 +1721,7 @@ static void __init rk_clk_tree_init(struct device_node *np)
 
        rk_clk_test();
 }
-CLK_OF_DECLARE(rk_clocks, "rockchip,rk-clock-regs", rk_clk_tree_init);
+CLK_OF_DECLARE(rk_clocks, "rockchip,rk-clocks", rk_clk_tree_init);
 
 
 /***************************** rockchip clks init******************************/
@@ -1526,9 +1868,9 @@ u32 clk_suspend_clkgt_info_get(u32 *clk_ungt_msk,u32 *clk_ungt_msk_last,u32 buf_
 
     gt_cnt=0;
     cru_base= of_iomap(clk_root_node, 0);
-        
+
     for_each_available_child_of_node(clk_root_node, node) {
-        
+
            if (of_device_is_compatible(node,"rockchip,rk-gate-cons"))
             {
 
@@ -1547,16 +1889,16 @@ u32 clk_suspend_clkgt_info_get(u32 *clk_ungt_msk,u32 *clk_ungt_msk_last,u32 buf_
                         clk_ungt_msk_last[gt_cnt]=temp_val[1];
                     }
                     else
-                    {   
+                    {
                         clk_ungt_msk[gt_cnt]=0xffff;
                         clk_ungt_msk_last[gt_cnt]=0xffff;
                     }
 
                     if(gt_cnt==0)
-                    {      
+                    {
                         gt_base=of_iomap(node_gt, 0);
                         reg_p=gt_base;
-                        reg_n=gt_base;                         
+                        reg_n=gt_base;
                     }
                     else
                     {
@@ -1566,7 +1908,7 @@ u32 clk_suspend_clkgt_info_get(u32 *clk_ungt_msk,u32 *clk_ungt_msk_last,u32 buf_
                         {
                             printk("%s: gt reg is not continue\n",__FUNCTION__);
                             return 0;
-                        }                                
+                        }
                         reg_p=reg_n;
                     }
 
@@ -1578,7 +1920,7 @@ u32 clk_suspend_clkgt_info_get(u32 *clk_ungt_msk,u32 *clk_ungt_msk_last,u32 buf_
                 }
 
                 break;
-            }      
+            }
     }
 
     if(gt_cnt!=buf_cnt)
@@ -1587,7 +1929,7 @@ u32 clk_suspend_clkgt_info_get(u32 *clk_ungt_msk,u32 *clk_ungt_msk_last,u32 buf_
            return 0;
     }
     clk_debug("%s:crubase=%x,gtbase=%x\n",__FUNCTION__,cru_base,gt_base);
-     
+
     return (u32)(gt_base-cru_base);
 
 }