Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

clk: divider: Make generic for usage elsewhere

Some devices don't use mmio to interact with dividers. Split out the
logic from the register read/write parts so that we can reuse the
division logic elsewhere.

Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
Tested-by: Kenneth Westfield <kwestfie@codeaurora.org>
Signed-off-by: Michael Turquette <mturquette@linaro.org>

authored by

Stephen Boyd and committed by
Michael Turquette
bca9690b 15a02c1f

+141 -86
+130 -86
drivers/clk/clk-divider.c
··· 30 30 31 31 #define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw) 32 32 33 - #define div_mask(d) ((1 << ((d)->width)) - 1) 33 + #define div_mask(width) ((1 << (width)) - 1) 34 34 35 35 static unsigned int _get_table_maxdiv(const struct clk_div_table *table) 36 36 { ··· 54 54 return mindiv; 55 55 } 56 56 57 - static unsigned int _get_maxdiv(struct clk_divider *divider) 57 + static unsigned int _get_maxdiv(const struct clk_div_table *table, u8 width, 58 + unsigned long flags) 58 59 { 59 - if (divider->flags & CLK_DIVIDER_ONE_BASED) 60 - return div_mask(divider); 61 - if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) 62 - return 1 << div_mask(divider); 63 - if (divider->table) 64 - return _get_table_maxdiv(divider->table); 65 - return div_mask(divider) + 1; 60 + if (flags & CLK_DIVIDER_ONE_BASED) 61 + return div_mask(width); 62 + if (flags & CLK_DIVIDER_POWER_OF_TWO) 63 + return 1 << div_mask(width); 64 + if (table) 65 + return _get_table_maxdiv(table); 66 + return div_mask(width) + 1; 66 67 } 67 68 68 69 static unsigned int _get_table_div(const struct clk_div_table *table, ··· 77 76 return 0; 78 77 } 79 78 80 - static unsigned int _get_div(struct clk_divider *divider, unsigned int val) 79 + static unsigned int _get_div(const struct clk_div_table *table, 80 + unsigned int val, unsigned long flags) 81 81 { 82 - if (divider->flags & CLK_DIVIDER_ONE_BASED) 82 + if (flags & CLK_DIVIDER_ONE_BASED) 83 83 return val; 84 - if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) 84 + if (flags & CLK_DIVIDER_POWER_OF_TWO) 85 85 return 1 << val; 86 - if (divider->table) 87 - return _get_table_div(divider->table, val); 86 + if (table) 87 + return _get_table_div(table, val); 88 88 return val + 1; 89 89 } 90 90 ··· 100 98 return 0; 101 99 } 102 100 103 - static unsigned int _get_val(struct clk_divider *divider, unsigned int div) 101 + static unsigned int _get_val(const struct clk_div_table *table, 102 + unsigned int div, unsigned long flags) 104 103 { 105 - if (divider->flags & CLK_DIVIDER_ONE_BASED) 104 + if (flags & CLK_DIVIDER_ONE_BASED) 106 105 return div; 107 - if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) 106 + if (flags & CLK_DIVIDER_POWER_OF_TWO) 108 107 return __ffs(div); 109 - if (divider->table) 110 - return _get_table_val(divider->table, div); 108 + if (table) 109 + return _get_table_val(table, div); 111 110 return div - 1; 112 111 } 113 112 114 - static unsigned long clk_divider_recalc_rate(struct clk_hw *hw, 115 - unsigned long parent_rate) 113 + unsigned long divider_recalc_rate(struct clk_hw *hw, unsigned long parent_rate, 114 + unsigned int val, 115 + const struct clk_div_table *table, 116 + unsigned long flags) 116 117 { 117 - struct clk_divider *divider = to_clk_divider(hw); 118 - unsigned int div, val; 118 + unsigned int div; 119 119 120 - val = clk_readl(divider->reg) >> divider->shift; 121 - val &= div_mask(divider); 122 - 123 - div = _get_div(divider, val); 120 + div = _get_div(table, val, flags); 124 121 if (!div) { 125 - WARN(!(divider->flags & CLK_DIVIDER_ALLOW_ZERO), 122 + WARN(!(flags & CLK_DIVIDER_ALLOW_ZERO), 126 123 "%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n", 127 124 __clk_get_name(hw->clk)); 128 125 return parent_rate; 129 126 } 130 127 131 128 return DIV_ROUND_UP(parent_rate, div); 129 + } 130 + EXPORT_SYMBOL_GPL(divider_recalc_rate); 131 + 132 + static unsigned long clk_divider_recalc_rate(struct clk_hw *hw, 133 + unsigned long parent_rate) 134 + { 135 + struct clk_divider *divider = to_clk_divider(hw); 136 + unsigned int val; 137 + 138 + val = clk_readl(divider->reg) >> divider->shift; 139 + val &= div_mask(divider->width); 140 + 141 + return divider_recalc_rate(hw, parent_rate, val, divider->table, 142 + divider->flags); 132 143 } 133 144 134 145 /* ··· 161 146 return false; 162 147 } 163 148 164 - static bool _is_valid_div(struct clk_divider *divider, unsigned int div) 149 + static bool _is_valid_div(const struct clk_div_table *table, unsigned int div, 150 + unsigned long flags) 165 151 { 166 - if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) 152 + if (flags & CLK_DIVIDER_POWER_OF_TWO) 167 153 return is_power_of_2(div); 168 - if (divider->table) 169 - return _is_valid_table_div(divider->table, div); 154 + if (table) 155 + return _is_valid_table_div(table, div); 170 156 return true; 171 157 } 172 158 ··· 207 191 return down; 208 192 } 209 193 210 - static int _div_round_up(struct clk_divider *divider, 211 - unsigned long parent_rate, unsigned long rate) 194 + static int _div_round_up(const struct clk_div_table *table, 195 + unsigned long parent_rate, unsigned long rate, 196 + unsigned long flags) 212 197 { 213 198 int div = DIV_ROUND_UP(parent_rate, rate); 214 199 215 - if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) 200 + if (flags & CLK_DIVIDER_POWER_OF_TWO) 216 201 div = __roundup_pow_of_two(div); 217 - if (divider->table) 218 - div = _round_up_table(divider->table, div); 202 + if (table) 203 + div = _round_up_table(table, div); 219 204 220 205 return div; 221 206 } 222 207 223 - static int _div_round_closest(struct clk_divider *divider, 224 - unsigned long parent_rate, unsigned long rate) 208 + static int _div_round_closest(const struct clk_div_table *table, 209 + unsigned long parent_rate, unsigned long rate, 210 + unsigned long flags) 225 211 { 226 212 int up, down, div; 227 213 228 214 up = down = div = DIV_ROUND_CLOSEST(parent_rate, rate); 229 215 230 - if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) { 216 + if (flags & CLK_DIVIDER_POWER_OF_TWO) { 231 217 up = __roundup_pow_of_two(div); 232 218 down = __rounddown_pow_of_two(div); 233 - } else if (divider->table) { 234 - up = _round_up_table(divider->table, div); 235 - down = _round_down_table(divider->table, div); 219 + } else if (table) { 220 + up = _round_up_table(table, div); 221 + down = _round_down_table(table, div); 236 222 } 237 223 238 224 return (up - div) <= (div - down) ? up : down; 239 225 } 240 226 241 - static int _div_round(struct clk_divider *divider, unsigned long parent_rate, 242 - unsigned long rate) 227 + static int _div_round(const struct clk_div_table *table, 228 + unsigned long parent_rate, unsigned long rate, 229 + unsigned long flags) 243 230 { 244 - if (divider->flags & CLK_DIVIDER_ROUND_CLOSEST) 245 - return _div_round_closest(divider, parent_rate, rate); 231 + if (flags & CLK_DIVIDER_ROUND_CLOSEST) 232 + return _div_round_closest(table, parent_rate, rate, flags); 246 233 247 - return _div_round_up(divider, parent_rate, rate); 234 + return _div_round_up(table, parent_rate, rate, flags); 248 235 } 249 236 250 - static bool _is_best_div(struct clk_divider *divider, 251 - unsigned long rate, unsigned long now, unsigned long best) 237 + static bool _is_best_div(unsigned long rate, unsigned long now, 238 + unsigned long best, unsigned long flags) 252 239 { 253 - if (divider->flags & CLK_DIVIDER_ROUND_CLOSEST) 240 + if (flags & CLK_DIVIDER_ROUND_CLOSEST) 254 241 return abs(rate - now) < abs(rate - best); 255 242 256 243 return now <= rate && now > best; 257 244 } 258 245 259 - static int _next_div(struct clk_divider *divider, int div) 246 + static int _next_div(const struct clk_div_table *table, int div, 247 + unsigned long flags) 260 248 { 261 249 div++; 262 250 263 - if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) 251 + if (flags & CLK_DIVIDER_POWER_OF_TWO) 264 252 return __roundup_pow_of_two(div); 265 - if (divider->table) 266 - return _round_up_table(divider->table, div); 253 + if (table) 254 + return _round_up_table(table, div); 267 255 268 256 return div; 269 257 } 270 258 271 259 static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, 272 - unsigned long *best_parent_rate) 260 + unsigned long *best_parent_rate, 261 + const struct clk_div_table *table, u8 width, 262 + unsigned long flags) 273 263 { 274 - struct clk_divider *divider = to_clk_divider(hw); 275 264 int i, bestdiv = 0; 276 265 unsigned long parent_rate, best = 0, now, maxdiv; 277 266 unsigned long parent_rate_saved = *best_parent_rate; ··· 284 263 if (!rate) 285 264 rate = 1; 286 265 287 - /* if read only, just return current value */ 288 - if (divider->flags & CLK_DIVIDER_READ_ONLY) { 289 - bestdiv = readl(divider->reg) >> divider->shift; 290 - bestdiv &= div_mask(divider); 291 - bestdiv = _get_div(divider, bestdiv); 292 - return bestdiv; 293 - } 294 - 295 - maxdiv = _get_maxdiv(divider); 266 + maxdiv = _get_maxdiv(table, width, flags); 296 267 297 268 if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) { 298 269 parent_rate = *best_parent_rate; 299 - bestdiv = _div_round(divider, parent_rate, rate); 270 + bestdiv = _div_round(table, parent_rate, rate, flags); 300 271 bestdiv = bestdiv == 0 ? 1 : bestdiv; 301 272 bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv; 302 273 return bestdiv; ··· 300 287 */ 301 288 maxdiv = min(ULONG_MAX / rate, maxdiv); 302 289 303 - for (i = 1; i <= maxdiv; i = _next_div(divider, i)) { 304 - if (!_is_valid_div(divider, i)) 290 + for (i = 1; i <= maxdiv; i = _next_div(table, i, flags)) { 291 + if (!_is_valid_div(table, i, flags)) 305 292 continue; 306 293 if (rate * i == parent_rate_saved) { 307 294 /* ··· 315 302 parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), 316 303 MULT_ROUND_UP(rate, i)); 317 304 now = DIV_ROUND_UP(parent_rate, i); 318 - if (_is_best_div(divider, rate, now, best)) { 305 + if (_is_best_div(rate, now, best, flags)) { 319 306 bestdiv = i; 320 307 best = now; 321 308 *best_parent_rate = parent_rate; ··· 323 310 } 324 311 325 312 if (!bestdiv) { 326 - bestdiv = _get_maxdiv(divider); 313 + bestdiv = _get_maxdiv(table, width, flags); 327 314 *best_parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), 1); 328 315 } 329 316 330 317 return bestdiv; 331 318 } 332 319 333 - static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, 334 - unsigned long *prate) 320 + long divider_round_rate(struct clk_hw *hw, unsigned long rate, 321 + unsigned long *prate, const struct clk_div_table *table, 322 + u8 width, unsigned long flags) 335 323 { 336 324 int div; 337 - div = clk_divider_bestdiv(hw, rate, prate); 325 + 326 + div = clk_divider_bestdiv(hw, rate, prate, table, width, flags); 338 327 339 328 return DIV_ROUND_UP(*prate, div); 340 329 } 330 + EXPORT_SYMBOL_GPL(divider_round_rate); 331 + 332 + static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, 333 + unsigned long *prate) 334 + { 335 + struct clk_divider *divider = to_clk_divider(hw); 336 + int bestdiv; 337 + 338 + /* if read only, just return current value */ 339 + if (divider->flags & CLK_DIVIDER_READ_ONLY) { 340 + bestdiv = readl(divider->reg) >> divider->shift; 341 + bestdiv &= div_mask(divider->width); 342 + bestdiv = _get_div(divider->table, bestdiv, divider->flags); 343 + return bestdiv; 344 + } 345 + 346 + return divider_round_rate(hw, rate, prate, divider->table, 347 + divider->width, divider->flags); 348 + } 349 + 350 + int divider_get_val(unsigned long rate, unsigned long parent_rate, 351 + const struct clk_div_table *table, u8 width, 352 + unsigned long flags) 353 + { 354 + unsigned int div, value; 355 + 356 + div = DIV_ROUND_UP(parent_rate, rate); 357 + 358 + if (!_is_valid_div(table, div, flags)) 359 + return -EINVAL; 360 + 361 + value = _get_val(table, div, flags); 362 + 363 + return min_t(unsigned int, value, div_mask(width)); 364 + } 365 + EXPORT_SYMBOL_GPL(divider_get_val); 341 366 342 367 static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, 343 368 unsigned long parent_rate) 344 369 { 345 370 struct clk_divider *divider = to_clk_divider(hw); 346 - unsigned int div, value; 371 + unsigned int value; 347 372 unsigned long flags = 0; 348 373 u32 val; 349 374 350 - div = DIV_ROUND_UP(parent_rate, rate); 351 - 352 - if (!_is_valid_div(divider, div)) 353 - return -EINVAL; 354 - 355 - value = _get_val(divider, div); 356 - 357 - if (value > div_mask(divider)) 358 - value = div_mask(divider); 375 + value = divider_get_val(rate, parent_rate, divider->table, 376 + divider->width, divider->flags); 359 377 360 378 if (divider->lock) 361 379 spin_lock_irqsave(divider->lock, flags); 362 380 363 381 if (divider->flags & CLK_DIVIDER_HIWORD_MASK) { 364 - val = div_mask(divider) << (divider->shift + 16); 382 + val = div_mask(divider->width) << (divider->shift + 16); 365 383 } else { 366 384 val = clk_readl(divider->reg); 367 - val &= ~(div_mask(divider) << divider->shift); 385 + val &= ~(div_mask(divider->width) << divider->shift); 368 386 } 369 387 val |= value << divider->shift; 370 388 clk_writel(val, divider->reg);
+11
include/linux/clk-provider.h
··· 353 353 #define CLK_DIVIDER_READ_ONLY BIT(5) 354 354 355 355 extern const struct clk_ops clk_divider_ops; 356 + 357 + unsigned long divider_recalc_rate(struct clk_hw *hw, unsigned long parent_rate, 358 + unsigned int val, const struct clk_div_table *table, 359 + unsigned long flags); 360 + long divider_round_rate(struct clk_hw *hw, unsigned long rate, 361 + unsigned long *prate, const struct clk_div_table *table, 362 + u8 width, unsigned long flags); 363 + int divider_get_val(unsigned long rate, unsigned long parent_rate, 364 + const struct clk_div_table *table, u8 width, 365 + unsigned long flags); 366 + 356 367 struct clk *clk_register_divider(struct device *dev, const char *name, 357 368 const char *parent_name, unsigned long flags, 358 369 void __iomem *reg, u8 shift, u8 width,