aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clk/bcm
diff options
context:
space:
mode:
authorBoris Brezillon <boris.brezillon@free-electrons.com>2015-07-07 14:48:08 -0400
committerStephen Boyd <sboyd@codeaurora.org>2015-07-27 21:12:01 -0400
commit0817b62cc037a56c5e4238c7eb7522299ea27aef (patch)
treee49a8eaceb710fd2873c93c86ef71bf4ff502902 /drivers/clk/bcm
parentd770e558e21961ad6cfdf0ff7df0eb5d7d4f0754 (diff)
clk: change clk_ops' ->determine_rate() prototype
Clock rates are stored in an unsigned long field, but ->determine_rate() (which returns a rounded rate from a requested one) returns a long value (errors are reported using negative error codes), which can lead to long overflow if the clock rate exceed 2Ghz. Change ->determine_rate() prototype to return 0 or an error code, and pass a pointer to a clk_rate_request structure containing the expected target rate and the rate constraints imposed by clk users. The clk_rate_request structure might be extended in the future to contain other kind of constraints like the rounding policy, the maximum clock inaccuracy or other things that are not yet supported by the CCF (power consumption constraints ?). Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com> CC: Jonathan Corbet <corbet@lwn.net> CC: Tony Lindgren <tony@atomide.com> CC: Ralf Baechle <ralf@linux-mips.org> CC: "Emilio López" <emilio@elopez.com.ar> CC: Maxime Ripard <maxime.ripard@free-electrons.com> Acked-by: Tero Kristo <t-kristo@ti.com> CC: Peter De Schrijver <pdeschrijver@nvidia.com> CC: Prashant Gaikwad <pgaikwad@nvidia.com> CC: Stephen Warren <swarren@wwwdotorg.org> CC: Thierry Reding <thierry.reding@gmail.com> CC: Alexandre Courbot <gnurou@gmail.com> CC: linux-doc@vger.kernel.org CC: linux-kernel@vger.kernel.org CC: linux-arm-kernel@lists.infradead.org CC: linux-omap@vger.kernel.org CC: linux-mips@linux-mips.org CC: linux-tegra@vger.kernel.org [sboyd@codeaurora.org: Fix parent dereference problem in __clk_determine_rate()] Signed-off-by: Stephen Boyd <sboyd@codeaurora.org> Tested-by: Romain Perier <romain.perier@gmail.com> Signed-off-by: Heiko Stuebner <heiko@sntech.de> [sboyd@codeaurora.org: Folded in fix from Heiko for fixed-rate clocks without parents or a rate determining op] Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
Diffstat (limited to 'drivers/clk/bcm')
-rw-r--r--drivers/clk/bcm/clk-kona.c34
1 files changed, 21 insertions, 13 deletions
diff --git a/drivers/clk/bcm/clk-kona.c b/drivers/clk/bcm/clk-kona.c
index 79a98506c433..d9c039c1902c 100644
--- a/drivers/clk/bcm/clk-kona.c
+++ b/drivers/clk/bcm/clk-kona.c
@@ -1017,10 +1017,8 @@ static long kona_peri_clk_round_rate(struct clk_hw *hw, unsigned long rate,
1017 rate ? rate : 1, *parent_rate, NULL); 1017 rate ? rate : 1, *parent_rate, NULL);
1018} 1018}
1019 1019
1020static long kona_peri_clk_determine_rate(struct clk_hw *hw, unsigned long rate, 1020static int kona_peri_clk_determine_rate(struct clk_hw *hw,
1021 unsigned long min_rate, 1021 struct clk_rate_request *req)
1022 unsigned long max_rate,
1023 unsigned long *best_parent_rate, struct clk_hw **best_parent)
1024{ 1022{
1025 struct kona_clk *bcm_clk = to_kona_clk(hw); 1023 struct kona_clk *bcm_clk = to_kona_clk(hw);
1026 struct clk *clk = hw->clk; 1024 struct clk *clk = hw->clk;
@@ -1029,6 +1027,7 @@ static long kona_peri_clk_determine_rate(struct clk_hw *hw, unsigned long rate,
1029 unsigned long best_delta; 1027 unsigned long best_delta;
1030 unsigned long best_rate; 1028 unsigned long best_rate;
1031 u32 parent_count; 1029 u32 parent_count;
1030 long rate;
1032 u32 which; 1031 u32 which;
1033 1032
1034 /* 1033 /*
@@ -1037,14 +1036,21 @@ static long kona_peri_clk_determine_rate(struct clk_hw *hw, unsigned long rate,
1037 */ 1036 */
1038 WARN_ON_ONCE(bcm_clk->init_data.flags & CLK_SET_RATE_NO_REPARENT); 1037 WARN_ON_ONCE(bcm_clk->init_data.flags & CLK_SET_RATE_NO_REPARENT);
1039 parent_count = (u32)bcm_clk->init_data.num_parents; 1038 parent_count = (u32)bcm_clk->init_data.num_parents;
1040 if (parent_count < 2) 1039 if (parent_count < 2) {
1041 return kona_peri_clk_round_rate(hw, rate, best_parent_rate); 1040 rate = kona_peri_clk_round_rate(hw, req->rate,
1041 &req->best_parent_rate);
1042 if (rate < 0)
1043 return rate;
1044
1045 req->rate = rate;
1046 return 0;
1047 }
1042 1048
1043 /* Unless we can do better, stick with current parent */ 1049 /* Unless we can do better, stick with current parent */
1044 current_parent = clk_get_parent(clk); 1050 current_parent = clk_get_parent(clk);
1045 parent_rate = __clk_get_rate(current_parent); 1051 parent_rate = __clk_get_rate(current_parent);
1046 best_rate = kona_peri_clk_round_rate(hw, rate, &parent_rate); 1052 best_rate = kona_peri_clk_round_rate(hw, req->rate, &parent_rate);
1047 best_delta = abs(best_rate - rate); 1053 best_delta = abs(best_rate - req->rate);
1048 1054
1049 /* Check whether any other parent clock can produce a better result */ 1055 /* Check whether any other parent clock can produce a better result */
1050 for (which = 0; which < parent_count; which++) { 1056 for (which = 0; which < parent_count; which++) {
@@ -1058,17 +1064,19 @@ static long kona_peri_clk_determine_rate(struct clk_hw *hw, unsigned long rate,
1058 1064
1059 /* We don't support CLK_SET_RATE_PARENT */ 1065 /* We don't support CLK_SET_RATE_PARENT */
1060 parent_rate = __clk_get_rate(parent); 1066 parent_rate = __clk_get_rate(parent);
1061 other_rate = kona_peri_clk_round_rate(hw, rate, &parent_rate); 1067 other_rate = kona_peri_clk_round_rate(hw, req->rate,
1062 delta = abs(other_rate - rate); 1068 &parent_rate);
1069 delta = abs(other_rate - req->rate);
1063 if (delta < best_delta) { 1070 if (delta < best_delta) {
1064 best_delta = delta; 1071 best_delta = delta;
1065 best_rate = other_rate; 1072 best_rate = other_rate;
1066 *best_parent = __clk_get_hw(parent); 1073 req->best_parent_hw = __clk_get_hw(parent);
1067 *best_parent_rate = parent_rate; 1074 req->best_parent_rate = parent_rate;
1068 } 1075 }
1069 } 1076 }
1070 1077
1071 return best_rate; 1078 req->rate = best_rate;
1079 return 0;
1072} 1080}
1073 1081
1074static int kona_peri_clk_set_parent(struct clk_hw *hw, u8 index) 1082static int kona_peri_clk_set_parent(struct clk_hw *hw, u8 index)