From 08225f45ae332b54524912ff4c27fb9debb06c9a Mon Sep 17 00:00:00 2001 From: dkl Date: Mon, 24 Feb 2014 14:51:59 +0800 Subject: [PATCH] clk: rk: add aclk_lcdc init, fix dclk_lcdc/i2s clk ops 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 | 2 + arch/arm/boot/dts/rk3188.dtsi | 3 +- drivers/clk/rockchip/clk-ops.c | 103 +++++++++++++++++---------- 3 files changed, 71 insertions(+), 37 deletions(-) diff --git a/arch/arm/boot/dts/rk3188-clocks.dtsi b/arch/arm/boot/dts/rk3188-clocks.dtsi index 4ca1c32a94cb..36e26483dd0e 100755 --- a/arch/arm/boot/dts/rk3188-clocks.dtsi +++ b/arch/arm/boot/dts/rk3188-clocks.dtsi @@ -1014,6 +1014,7 @@ 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 { @@ -1035,6 +1036,7 @@ clocks = <&clk_cpll>, <&clk_gpll>; clock-output-names = "aclk_lcdc1"; #clock-cells = <0>; + #clock-init-cells = <1>; }; }; diff --git a/arch/arm/boot/dts/rk3188.dtsi b/arch/arm/boot/dts/rk3188.dtsi index 5242cf46b129..b41084451c92 100755 --- a/arch/arm/boot/dts/rk3188.dtsi +++ b/arch/arm/boot/dts/rk3188.dtsi @@ -372,7 +372,8 @@ <&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{ diff --git a/drivers/clk/rockchip/clk-ops.c b/drivers/clk/rockchip/clk-ops.c index e895f55fda7c..681ec552063f 100644 --- a/drivers/clk/rockchip/clk-ops.c +++ b/drivers/clk/rockchip/clk-ops.c @@ -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, -- 2.34.1