clk: rk: add aclk_lcdc init, fix dclk_lcdc/i2s clk ops
authordkl <dkl@rock-chips.com>
Mon, 24 Feb 2014 06:51:59 +0000 (14:51 +0800)
committerdkl <dkl@rock-chips.com>
Mon, 24 Feb 2014 07:05:33 +0000 (15:05 +0800)
1. Init aclk_lcdc 300M.
2. Fix dclk_lcdc clk ops to set even div only.
3. Repeatly write i2s clk reg, to fix rk3188 problem.

arch/arm/boot/dts/rk3188-clocks.dtsi
arch/arm/boot/dts/rk3188.dtsi
drivers/clk/rockchip/clk-ops.c

index 4ca1c32a94cb9c9ff9e6bfae4c30b665361c9472..36e26483dd0e21cf839bcd82a795ca2f45d126f8 100755 (executable)
                                                clocks = <&clk_cpll>, <&clk_gpll>;
                                                clock-output-names = "aclk_lcdc0";
                                                #clock-cells = <0>;
+                                               #clock-init-cells = <1>;
                                        };
 
                                        aclk_lcdc1_pre_div: aclk_lcdc1_pre_div {
                                                clocks = <&clk_cpll>, <&clk_gpll>;
                                                clock-output-names = "aclk_lcdc1";
                                                #clock-cells = <0>;
+                                               #clock-init-cells = <1>;
                                        };
                                };
 
index 5242cf46b1293b9f931a892dd7881f3a412cbe5a..b41084451c92448690e6cc0bb831ba6c6ca70914 100755 (executable)
                        <&hclk_cpu 96000000>,   <&pclk_cpu 48000000>,
                        <&pclk_ahb2apb 48000000>,       <&aclk_peri 192000000>,
                        <&hclk_peri 96000000>,  <&pclk_peri 48000000>,
-                       <&clk_gpu 200000000>;
+                       <&clk_gpu 200000000>, <&aclk_lcdc0 300000000>,
+                       <&aclk_lcdc1 300000000>;
        };
 
        fb: fb{
index e895f55fda7c2a430441b409a8c62e70670c9b67..681ec552063fd15590c2dd36ff445920874a28e8 100644 (file)
@@ -220,83 +220,114 @@ static long clk_div_round_rate_even(struct clk_hw *hw, unsigned long rate,
        struct clk_divider *divider =to_clk_divider(hw);
        int max_div = 1 << divider->width;
 
-       for (i = 1; i < max_div; i++) {
+       for (i = 1; i <= max_div; i++) {
                if (i > 1 && (i % 2 != 0))
                        continue;
-               if (rate >= *prate / i)
+               if (rate >= (*prate / i))
                        return *prate / i;
        }
-       return -EINVAL;
-}
 
-static int clk_div_set_rate_even(struct clk_hw *hw, unsigned long rate,
-               unsigned long parent_rate)
-{
-       return clk_divider_ops.set_rate(hw, rate, parent_rate);
+       return (*prate / max_div);
 }
 
 const struct clk_ops clkops_rate_evendiv = {
        .recalc_rate    = clk_divider_recalc_rate,
        .round_rate     = clk_div_round_rate_even,
-       .set_rate       = clk_div_set_rate_even,
+       .set_rate       = clk_divider_set_rate,
 };
 
-static long dclk_lcdc_round_rate(struct clk_hw *hw, unsigned long rate,
-               unsigned long *prate)
+static long clk_mux_with_evendiv_determine_rate(struct clk_hw *div_hw, unsigned long rate,
+               unsigned long *best_parent_rate,
+               struct clk **best_parent_p)
 {
-       long ret = 0;
-       if (rate == 27 * MHZ) {
-               ret = clk_divider_round_rate(hw, rate, prate);
-       } else {
-               ret = clk_divider_round_rate(hw, rate, prate);
+       struct clk *clk = div_hw->clk, *parent = NULL, *best_parent = NULL;
+       int i, num_parents;
+       unsigned long parent_rate = 0, best_prate = 0, best = 0, now = 0;
+
+
+       parent = __clk_get_parent(clk);
+       if(!parent){
+               best = __clk_get_rate(clk);
+               goto out;
        }
-       return ret;
+
+       /* if NO_REPARENT flag set, pass through to current parent */
+       if (clk->flags & CLK_SET_RATE_NO_REPARENT) {
+               best_prate = __clk_get_rate(parent);
+               best = clk_div_round_rate_even(div_hw, rate, &best_prate);
+               goto out;
+       }
+
+       /* find the parent that can provide the fastest rate <= rate */
+       num_parents = clk->num_parents;
+       for (i = 0; i < num_parents; i++) {
+               parent = clk_get_parent_by_index(clk, i);
+               if (!parent)
+                       continue;
+
+               parent_rate = __clk_get_rate(parent);
+               now = clk_div_round_rate_even(div_hw, rate, &parent_rate);
+
+               if (now <= rate && now > best) {
+                       best_parent = parent;
+                       best_prate = parent_rate;
+                       best = now;
+               }
+       }
+
+out:
+       if(best_prate)
+               *best_parent_rate = best_prate;
+
+       if (best_parent)
+               *best_parent_p = best_parent;
+
+       clk_debug("clk name = %s, determine rate = %lu, best = %lu\n"
+                       "\tbest_parent name = %s, best_prate = %lu\n",
+                       clk->name, rate, best,
+                       __clk_get_name(*best_parent_p), *best_parent_rate);
+
+       return best;
 }
 
-static int dclk_lcdc_set_rate(struct clk_hw *hw, unsigned long rate,
-               unsigned long parent_rate)
+static long dclk_lcdc_round_rate(struct clk_hw *hw, unsigned long rate,
+               unsigned long *prate)
 {
-       return clk_divider_set_rate(hw, rate, parent_rate);
+       return clk_div_round_rate_even(hw, rate, prate);
 }
 
 const struct clk_ops clkops_rate_dclk_lcdc = {
        .recalc_rate    = clk_divider_recalc_rate,
+       .set_rate       = clk_divider_set_rate,
        .round_rate     = dclk_lcdc_round_rate,
-       .set_rate       = dclk_lcdc_set_rate,
-       .determine_rate = clk_mux_with_div_determine_rate,
+       .determine_rate = clk_mux_with_evendiv_determine_rate,
 };
 
-#if 0
 static int clk_i2s_fracdiv_set_rate(struct clk_hw *hw, unsigned long rate,
                unsigned long parent_rate)
 {
        u32 numerator, denominator;
-       struct clk *clk_parent;
-       int i = 10;
        struct clk_divider *div = to_clk_divider(hw);
+       int i = 10;
+
 
-       clk_parent = hw->clk->parent;
        if(clk_fracdiv_get_config(rate, parent_rate,
                                &numerator, &denominator) == 0) {
-
-               clk_parent->ops->set_rate(clk_parent->hw,
-                               clk_parent->parent->rate,
-                               clk_parent->parent->rate);
                while (i--) {
                        writel((numerator - 1) << 16 | denominator, div->reg);
                        mdelay(1);
                        writel(numerator << 16 | denominator, div->reg);
                        mdelay(1);
                }
-               clk_err("%s set rate=%lu,is ok\n", hw->clk->name, rate);
-
+               clk_debug("%s set rate=%lu,is ok\n", hw->clk->name, rate);
        } else {
-               clk_err("%s: can't get rate=%lu,%s\n", __func__, rate, hw->clk->name);
-               return -ENOENT;
+               clk_err("clk_frac_div name=%s can't get rate=%lu\n",
+                               hw->clk->name, rate);
+               return -EINVAL;
        }
+
        return 0;
 }
-#endif
 
 const struct clk_ops clkops_rate_frac = {
        .recalc_rate    = clk_fracdiv_recalc,
@@ -307,7 +338,7 @@ const struct clk_ops clkops_rate_frac = {
 const struct clk_ops clkops_rate_i2s_frac = {
        .recalc_rate    = clk_fracdiv_recalc,
        .round_rate     = clk_fracdiv_round_rate,
-       .set_rate       = clk_fracdiv_set_rate,
+       .set_rate       = clk_i2s_fracdiv_set_rate,
 };
 
 static unsigned long clk_core_recalc_rate(struct clk_hw *hw,