@@ -43,6 +43,17 @@ static unsigned int _get_table_maxdiv(const struct clk_div_table *table)
43
43
return maxdiv ;
44
44
}
45
45
46
+ static unsigned int _get_table_mindiv (const struct clk_div_table * table )
47
+ {
48
+ unsigned int mindiv = UINT_MAX ;
49
+ const struct clk_div_table * clkt ;
50
+
51
+ for (clkt = table ; clkt -> div ; clkt ++ )
52
+ if (clkt -> div < mindiv )
53
+ mindiv = clkt -> div ;
54
+ return mindiv ;
55
+ }
56
+
46
57
static unsigned int _get_maxdiv (struct clk_divider * divider )
47
58
{
48
59
if (divider -> flags & CLK_DIVIDER_ONE_BASED )
@@ -162,6 +173,24 @@ static int _round_up_table(const struct clk_div_table *table, int div)
162
173
return up ;
163
174
}
164
175
176
+ static int _round_down_table (const struct clk_div_table * table , int div )
177
+ {
178
+ const struct clk_div_table * clkt ;
179
+ int down = _get_table_mindiv (table );
180
+
181
+ for (clkt = table ; clkt -> div ; clkt ++ ) {
182
+ if (clkt -> div == div )
183
+ return clkt -> div ;
184
+ else if (clkt -> div > div )
185
+ continue ;
186
+
187
+ if ((div - clkt -> div ) < (div - down ))
188
+ down = clkt -> div ;
189
+ }
190
+
191
+ return down ;
192
+ }
193
+
165
194
static int _div_round_up (struct clk_divider * divider ,
166
195
unsigned long parent_rate , unsigned long rate )
167
196
{
@@ -175,6 +204,42 @@ static int _div_round_up(struct clk_divider *divider,
175
204
return div ;
176
205
}
177
206
207
+ static int _div_round_closest (struct clk_divider * divider ,
208
+ unsigned long parent_rate , unsigned long rate )
209
+ {
210
+ int up , down , div ;
211
+
212
+ up = down = div = DIV_ROUND_CLOSEST (parent_rate , rate );
213
+
214
+ if (divider -> flags & CLK_DIVIDER_POWER_OF_TWO ) {
215
+ up = __roundup_pow_of_two (div );
216
+ down = __rounddown_pow_of_two (div );
217
+ } else if (divider -> table ) {
218
+ up = _round_up_table (divider -> table , div );
219
+ down = _round_down_table (divider -> table , div );
220
+ }
221
+
222
+ return (up - div ) <= (div - down ) ? up : down ;
223
+ }
224
+
225
+ static int _div_round (struct clk_divider * divider , unsigned long parent_rate ,
226
+ unsigned long rate )
227
+ {
228
+ if (divider -> flags & CLK_DIVIDER_ROUND_CLOSEST )
229
+ return _div_round_closest (divider , parent_rate , rate );
230
+
231
+ return _div_round_up (divider , parent_rate , rate );
232
+ }
233
+
234
+ static bool _is_best_div (struct clk_divider * divider ,
235
+ int rate , int now , int best )
236
+ {
237
+ if (divider -> flags & CLK_DIVIDER_ROUND_CLOSEST )
238
+ return abs (rate - now ) < abs (rate - best );
239
+
240
+ return now <= rate && now > best ;
241
+ }
242
+
178
243
static int clk_divider_bestdiv (struct clk_hw * hw , unsigned long rate ,
179
244
unsigned long * best_parent_rate )
180
245
{
@@ -190,7 +255,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
190
255
191
256
if (!(__clk_get_flags (hw -> clk ) & CLK_SET_RATE_PARENT )) {
192
257
parent_rate = * best_parent_rate ;
193
- bestdiv = _div_round_up (divider , parent_rate , rate );
258
+ bestdiv = _div_round (divider , parent_rate , rate );
194
259
bestdiv = bestdiv == 0 ? 1 : bestdiv ;
195
260
bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv ;
196
261
return bestdiv ;
@@ -217,7 +282,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
217
282
parent_rate = __clk_round_rate (__clk_get_parent (hw -> clk ),
218
283
MULT_ROUND_UP (rate , i ));
219
284
now = DIV_ROUND_UP (parent_rate , i );
220
- if (now <= rate && now > best ) {
285
+ if (_is_best_div ( divider , rate , now , best ) ) {
221
286
bestdiv = i ;
222
287
best = now ;
223
288
* best_parent_rate = parent_rate ;
0 commit comments