diff options
author | Alex Elder <elder@linaro.org> | 2014-05-27 12:56:56 -0400 |
---|---|---|
committer | Mike Turquette <mturquette@linaro.org> | 2014-05-27 20:34:32 -0400 |
commit | c2152d0e4de54f4f5a9cff2316d7cfb04fdfad45 (patch) | |
tree | 872f3e409db58b828e9796d43c27aff57717ed0a /drivers/clk/bcm | |
parent | 63a00269cba5a0795365467e2f6be073d984c565 (diff) |
clk: bcm/kona: implement determine_rate()
Implement the clk->determine_rate method for Broadcom Kona peripheral
clocks. This allows a peripheral clock to be re-parented in order to
satisfy a rate change request. This takes the place of the previous
kona_peri_clk_round_rate() functionality, though that function remains
because it is used by the new one.
The parent clock that allows the peripheral clock to produce a rate
closest to the one requested is the one selected, though the current
parent is used by default.
Signed-off-by: Alex Elder <elder@linaro.org>
Signed-off-by: Mike Turquette <mturquette@linaro.org>
Diffstat (limited to 'drivers/clk/bcm')
-rw-r--r-- | drivers/clk/bcm/clk-kona.c | 54 |
1 files changed, 53 insertions, 1 deletions
diff --git a/drivers/clk/bcm/clk-kona.c b/drivers/clk/bcm/clk-kona.c index d603c4e22fca..95af2e665dd3 100644 --- a/drivers/clk/bcm/clk-kona.c +++ b/drivers/clk/bcm/clk-kona.c | |||
@@ -1031,6 +1031,58 @@ static long kona_peri_clk_round_rate(struct clk_hw *hw, unsigned long rate, | |||
1031 | rate ? rate : 1, *parent_rate, NULL); | 1031 | rate ? rate : 1, *parent_rate, NULL); |
1032 | } | 1032 | } |
1033 | 1033 | ||
1034 | static long kona_peri_clk_determine_rate(struct clk_hw *hw, unsigned long rate, | ||
1035 | unsigned long *best_parent_rate, struct clk **best_parent) | ||
1036 | { | ||
1037 | struct kona_clk *bcm_clk = to_kona_clk(hw); | ||
1038 | struct clk *clk = hw->clk; | ||
1039 | struct clk *current_parent; | ||
1040 | unsigned long parent_rate; | ||
1041 | unsigned long best_delta; | ||
1042 | unsigned long best_rate; | ||
1043 | u32 parent_count; | ||
1044 | u32 which; | ||
1045 | |||
1046 | /* | ||
1047 | * If there is no other parent to choose, use the current one. | ||
1048 | * Note: We don't honor (or use) CLK_SET_RATE_NO_REPARENT. | ||
1049 | */ | ||
1050 | WARN_ON_ONCE(bcm_clk->init_data.flags & CLK_SET_RATE_NO_REPARENT); | ||
1051 | parent_count = (u32)bcm_clk->init_data.num_parents; | ||
1052 | if (parent_count < 2) | ||
1053 | return kona_peri_clk_round_rate(hw, rate, best_parent_rate); | ||
1054 | |||
1055 | /* Unless we can do better, stick with current parent */ | ||
1056 | current_parent = clk_get_parent(clk); | ||
1057 | parent_rate = __clk_get_rate(current_parent); | ||
1058 | best_rate = kona_peri_clk_round_rate(hw, rate, &parent_rate); | ||
1059 | best_delta = abs(best_rate - rate); | ||
1060 | |||
1061 | /* Check whether any other parent clock can produce a better result */ | ||
1062 | for (which = 0; which < parent_count; which++) { | ||
1063 | struct clk *parent = clk_get_parent_by_index(clk, which); | ||
1064 | unsigned long delta; | ||
1065 | unsigned long other_rate; | ||
1066 | |||
1067 | BUG_ON(!parent); | ||
1068 | if (parent == current_parent) | ||
1069 | continue; | ||
1070 | |||
1071 | /* We don't support CLK_SET_RATE_PARENT */ | ||
1072 | parent_rate = __clk_get_rate(parent); | ||
1073 | other_rate = kona_peri_clk_round_rate(hw, rate, &parent_rate); | ||
1074 | delta = abs(other_rate - rate); | ||
1075 | if (delta < best_delta) { | ||
1076 | best_delta = delta; | ||
1077 | best_rate = other_rate; | ||
1078 | *best_parent = parent; | ||
1079 | *best_parent_rate = parent_rate; | ||
1080 | } | ||
1081 | } | ||
1082 | |||
1083 | return best_rate; | ||
1084 | } | ||
1085 | |||
1034 | static int kona_peri_clk_set_parent(struct clk_hw *hw, u8 index) | 1086 | static int kona_peri_clk_set_parent(struct clk_hw *hw, u8 index) |
1035 | { | 1087 | { |
1036 | struct kona_clk *bcm_clk = to_kona_clk(hw); | 1088 | struct kona_clk *bcm_clk = to_kona_clk(hw); |
@@ -1135,7 +1187,7 @@ struct clk_ops kona_peri_clk_ops = { | |||
1135 | .disable = kona_peri_clk_disable, | 1187 | .disable = kona_peri_clk_disable, |
1136 | .is_enabled = kona_peri_clk_is_enabled, | 1188 | .is_enabled = kona_peri_clk_is_enabled, |
1137 | .recalc_rate = kona_peri_clk_recalc_rate, | 1189 | .recalc_rate = kona_peri_clk_recalc_rate, |
1138 | .round_rate = kona_peri_clk_round_rate, | 1190 | .determine_rate = kona_peri_clk_determine_rate, |
1139 | .set_parent = kona_peri_clk_set_parent, | 1191 | .set_parent = kona_peri_clk_set_parent, |
1140 | .get_parent = kona_peri_clk_get_parent, | 1192 | .get_parent = kona_peri_clk_get_parent, |
1141 | .set_rate = kona_peri_clk_set_rate, | 1193 | .set_rate = kona_peri_clk_set_rate, |