Lines Matching +full:pll +full:- +full:1
2 * drivers/media/i2c/smiapp-pll.c
6 * Copyright (C) 2011--2012 Nokia Corporation
24 #include "smiapp-pll.h"
29 return max_t(uint32_t, 1, a & ~1); in clk_div_even()
35 if (a == 1) in clk_div_even_up()
36 return 1; in clk_div_even_up()
37 return (a + 1) & ~1; in clk_div_even_up()
42 if (a == 1) in is_one_or_even()
43 return 1; in is_one_or_even()
44 if (a & 1) in is_one_or_even()
47 return 1; in is_one_or_even()
56 dev_dbg(dev, "%s out of bounds: %d (%d--%d)\n", str, val, min, max); in bounds_check()
58 return -EINVAL; in bounds_check()
61 static void print_pll(struct device *dev, struct smiapp_pll *pll) in print_pll() argument
63 dev_dbg(dev, "pre_pll_clk_div\t%u\n", pll->pre_pll_clk_div); in print_pll()
64 dev_dbg(dev, "pll_multiplier \t%u\n", pll->pll_multiplier); in print_pll()
65 if (!(pll->flags & SMIAPP_PLL_FLAG_NO_OP_CLOCKS)) { in print_pll()
66 dev_dbg(dev, "op_sys_clk_div \t%u\n", pll->op.sys_clk_div); in print_pll()
67 dev_dbg(dev, "op_pix_clk_div \t%u\n", pll->op.pix_clk_div); in print_pll()
69 dev_dbg(dev, "vt_sys_clk_div \t%u\n", pll->vt.sys_clk_div); in print_pll()
70 dev_dbg(dev, "vt_pix_clk_div \t%u\n", pll->vt.pix_clk_div); in print_pll()
72 dev_dbg(dev, "ext_clk_freq_hz \t%u\n", pll->ext_clk_freq_hz); in print_pll()
73 dev_dbg(dev, "pll_ip_clk_freq_hz \t%u\n", pll->pll_ip_clk_freq_hz); in print_pll()
74 dev_dbg(dev, "pll_op_clk_freq_hz \t%u\n", pll->pll_op_clk_freq_hz); in print_pll()
75 if (!(pll->flags & SMIAPP_PLL_FLAG_NO_OP_CLOCKS)) { in print_pll()
77 pll->op.sys_clk_freq_hz); in print_pll()
79 pll->op.pix_clk_freq_hz); in print_pll()
81 dev_dbg(dev, "vt_sys_clk_freq_hz \t%u\n", pll->vt.sys_clk_freq_hz); in print_pll()
82 dev_dbg(dev, "vt_pix_clk_freq_hz \t%u\n", pll->vt.pix_clk_freq_hz); in print_pll()
88 struct smiapp_pll *pll, in check_all_bounds() argument
93 rval = bounds_check(dev, pll->pll_ip_clk_freq_hz, in check_all_bounds()
94 limits->min_pll_ip_freq_hz, in check_all_bounds()
95 limits->max_pll_ip_freq_hz, in check_all_bounds()
99 dev, pll->pll_multiplier, in check_all_bounds()
100 limits->min_pll_multiplier, limits->max_pll_multiplier, in check_all_bounds()
104 dev, pll->pll_op_clk_freq_hz, in check_all_bounds()
105 limits->min_pll_op_freq_hz, limits->max_pll_op_freq_hz, in check_all_bounds()
109 dev, op_pll->sys_clk_div, in check_all_bounds()
110 op_limits->min_sys_clk_div, op_limits->max_sys_clk_div, in check_all_bounds()
114 dev, op_pll->sys_clk_freq_hz, in check_all_bounds()
115 op_limits->min_sys_clk_freq_hz, in check_all_bounds()
116 op_limits->max_sys_clk_freq_hz, in check_all_bounds()
120 dev, op_pll->pix_clk_freq_hz, in check_all_bounds()
121 op_limits->min_pix_clk_freq_hz, in check_all_bounds()
122 op_limits->max_pix_clk_freq_hz, in check_all_bounds()
129 if (pll->flags & SMIAPP_PLL_FLAG_NO_OP_CLOCKS) in check_all_bounds()
134 dev, pll->vt.sys_clk_freq_hz, in check_all_bounds()
135 limits->vt.min_sys_clk_freq_hz, in check_all_bounds()
136 limits->vt.max_sys_clk_freq_hz, in check_all_bounds()
140 dev, pll->vt.pix_clk_freq_hz, in check_all_bounds()
141 limits->vt.min_pix_clk_freq_hz, in check_all_bounds()
142 limits->vt.max_pix_clk_freq_hz, in check_all_bounds()
149 * Heuristically guess the PLL tree for a given common multiplier and
153 * @mul is the PLL multiplier and @div is the common divisor
154 * (pre_pll_clk_div and op_sys_clk_div combined). The final PLL
162 struct smiapp_pll *pll, struct smiapp_pll_branch *op_pll, uint32_t mul, in __smiapp_pll_calculate() argument
166 uint32_t best_pix_div = INT_MAX >> 1; in __smiapp_pll_calculate()
184 dev_dbg(dev, "pre_pll_clk_div %u\n", pll->pre_pll_clk_div); in __smiapp_pll_calculate()
186 /* Don't go above max pll multiplier. */ in __smiapp_pll_calculate()
187 more_mul_max = limits->max_pll_multiplier / mul; in __smiapp_pll_calculate()
190 /* Don't go above max pll op frequency. */ in __smiapp_pll_calculate()
194 limits->max_pll_op_freq_hz in __smiapp_pll_calculate()
195 / (pll->ext_clk_freq_hz / pll->pre_pll_clk_div * mul)); in __smiapp_pll_calculate()
200 op_limits->max_sys_clk_div * pll->pre_pll_clk_div in __smiapp_pll_calculate()
206 DIV_ROUND_UP(limits->max_pll_multiplier, mul)); in __smiapp_pll_calculate()
211 more_mul_min = DIV_ROUND_UP(limits->min_pll_op_freq_hz, in __smiapp_pll_calculate()
212 pll->ext_clk_freq_hz / pll->pre_pll_clk_div in __smiapp_pll_calculate()
218 DIV_ROUND_UP(limits->min_pll_multiplier, mul)); in __smiapp_pll_calculate()
225 return -EINVAL; in __smiapp_pll_calculate()
228 more_mul_factor = lcm(div, pll->pre_pll_clk_div) / div; in __smiapp_pll_calculate()
230 more_mul_factor = lcm(more_mul_factor, op_limits->min_sys_clk_div); in __smiapp_pll_calculate()
235 i <<= 1; in __smiapp_pll_calculate()
240 return -EINVAL; in __smiapp_pll_calculate()
243 pll->pll_multiplier = mul * i; in __smiapp_pll_calculate()
244 op_pll->sys_clk_div = div * i / pll->pre_pll_clk_div; in __smiapp_pll_calculate()
245 dev_dbg(dev, "op_sys_clk_div: %u\n", op_pll->sys_clk_div); in __smiapp_pll_calculate()
247 pll->pll_ip_clk_freq_hz = pll->ext_clk_freq_hz in __smiapp_pll_calculate()
248 / pll->pre_pll_clk_div; in __smiapp_pll_calculate()
250 pll->pll_op_clk_freq_hz = pll->pll_ip_clk_freq_hz in __smiapp_pll_calculate()
251 * pll->pll_multiplier; in __smiapp_pll_calculate()
254 op_pll->sys_clk_freq_hz = in __smiapp_pll_calculate()
255 pll->pll_op_clk_freq_hz / op_pll->sys_clk_div; in __smiapp_pll_calculate()
257 op_pll->pix_clk_div = pll->bits_per_pixel; in __smiapp_pll_calculate()
258 dev_dbg(dev, "op_pix_clk_div: %u\n", op_pll->pix_clk_div); in __smiapp_pll_calculate()
260 op_pll->pix_clk_freq_hz = in __smiapp_pll_calculate()
261 op_pll->sys_clk_freq_hz / op_pll->pix_clk_div; in __smiapp_pll_calculate()
263 if (pll->flags & SMIAPP_PLL_FLAG_NO_OP_CLOCKS) { in __smiapp_pll_calculate()
264 /* No OP clocks --- VT clocks are used instead. */ in __smiapp_pll_calculate()
275 if (limits->min_line_length_pck_bin > limits->min_line_length_pck in __smiapp_pll_calculate()
276 / pll->binning_horizontal) in __smiapp_pll_calculate()
277 vt_op_binning_div = pll->binning_horizontal; in __smiapp_pll_calculate()
279 vt_op_binning_div = 1; in __smiapp_pll_calculate()
287 * enough to accommodate the CSI-2 sync codes. in __smiapp_pll_calculate()
293 dev_dbg(dev, "scale_m: %u\n", pll->scale_m); in __smiapp_pll_calculate()
294 min_vt_div = DIV_ROUND_UP(op_pll->pix_clk_div * op_pll->sys_clk_div in __smiapp_pll_calculate()
295 * pll->scale_n, in __smiapp_pll_calculate()
297 * pll->scale_m); in __smiapp_pll_calculate()
302 DIV_ROUND_UP(pll->pll_op_clk_freq_hz, in __smiapp_pll_calculate()
303 limits->vt.max_pix_clk_freq_hz)); in __smiapp_pll_calculate()
307 limits->vt.min_pix_clk_div in __smiapp_pll_calculate()
308 * limits->vt.min_sys_clk_div); in __smiapp_pll_calculate()
311 max_vt_div = limits->vt.max_sys_clk_div * limits->vt.max_pix_clk_div; in __smiapp_pll_calculate()
314 DIV_ROUND_UP(pll->pll_op_clk_freq_hz, in __smiapp_pll_calculate()
315 limits->vt.min_pix_clk_freq_hz)); in __smiapp_pll_calculate()
323 min_sys_div = limits->vt.min_sys_clk_div; in __smiapp_pll_calculate()
327 limits->vt.max_pix_clk_div)); in __smiapp_pll_calculate()
330 pll->pll_op_clk_freq_hz in __smiapp_pll_calculate()
331 / limits->vt.max_sys_clk_freq_hz); in __smiapp_pll_calculate()
336 max_sys_div = limits->vt.max_sys_clk_div; in __smiapp_pll_calculate()
340 limits->vt.min_pix_clk_div)); in __smiapp_pll_calculate()
343 DIV_ROUND_UP(pll->pll_op_clk_freq_hz, in __smiapp_pll_calculate()
344 limits->vt.min_pix_clk_freq_hz)); in __smiapp_pll_calculate()
353 vt_div += 2 - (vt_div & 1)) { in __smiapp_pll_calculate()
356 sys_div += 2 - (sys_div & 1)) { in __smiapp_pll_calculate()
359 if (pix_div < limits->vt.min_pix_clk_div in __smiapp_pll_calculate()
360 || pix_div > limits->vt.max_pix_clk_div) { in __smiapp_pll_calculate()
362 "pix_div %u too small or too big (%u--%u)\n", in __smiapp_pll_calculate()
364 limits->vt.min_pix_clk_div, in __smiapp_pll_calculate()
365 limits->vt.max_pix_clk_div); in __smiapp_pll_calculate()
374 if (best_pix_div < INT_MAX >> 1) in __smiapp_pll_calculate()
378 pll->vt.sys_clk_div = DIV_ROUND_UP(min_vt_div, best_pix_div); in __smiapp_pll_calculate()
379 pll->vt.pix_clk_div = best_pix_div; in __smiapp_pll_calculate()
381 pll->vt.sys_clk_freq_hz = in __smiapp_pll_calculate()
382 pll->pll_op_clk_freq_hz / pll->vt.sys_clk_div; in __smiapp_pll_calculate()
383 pll->vt.pix_clk_freq_hz = in __smiapp_pll_calculate()
384 pll->vt.sys_clk_freq_hz / pll->vt.pix_clk_div; in __smiapp_pll_calculate()
387 pll->pixel_rate_csi = in __smiapp_pll_calculate()
388 op_pll->pix_clk_freq_hz * lane_op_clock_ratio; in __smiapp_pll_calculate()
389 pll->pixel_rate_pixel_array = pll->vt.pix_clk_freq_hz; in __smiapp_pll_calculate()
391 return check_all_bounds(dev, limits, op_limits, pll, op_pll); in __smiapp_pll_calculate()
396 struct smiapp_pll *pll) in smiapp_pll_calculate() argument
398 const struct smiapp_pll_branch_limits *op_limits = &limits->op; in smiapp_pll_calculate()
399 struct smiapp_pll_branch *op_pll = &pll->op; in smiapp_pll_calculate()
405 int rval = -EINVAL; in smiapp_pll_calculate()
407 if (pll->flags & SMIAPP_PLL_FLAG_NO_OP_CLOCKS) { in smiapp_pll_calculate()
409 * If there's no OP PLL at all, use the VT values in smiapp_pll_calculate()
411 * the PLL calculation. in smiapp_pll_calculate()
413 op_limits = &limits->vt; in smiapp_pll_calculate()
414 op_pll = &pll->vt; in smiapp_pll_calculate()
417 if (pll->flags & SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE) in smiapp_pll_calculate()
418 lane_op_clock_ratio = pll->csi2.lanes; in smiapp_pll_calculate()
420 lane_op_clock_ratio = 1; in smiapp_pll_calculate()
423 dev_dbg(dev, "binning: %ux%u\n", pll->binning_horizontal, in smiapp_pll_calculate()
424 pll->binning_vertical); in smiapp_pll_calculate()
426 switch (pll->bus_type) { in smiapp_pll_calculate()
429 pll->pll_op_clk_freq_hz = pll->link_freq * 2 in smiapp_pll_calculate()
430 * (pll->csi2.lanes / lane_op_clock_ratio); in smiapp_pll_calculate()
433 pll->pll_op_clk_freq_hz = pll->link_freq * pll->bits_per_pixel in smiapp_pll_calculate()
434 / DIV_ROUND_UP(pll->bits_per_pixel, in smiapp_pll_calculate()
435 pll->parallel.bus_width); in smiapp_pll_calculate()
438 return -EINVAL; in smiapp_pll_calculate()
441 /* Figure out limits for pre-pll divider based on extclk */ in smiapp_pll_calculate()
443 limits->min_pre_pll_clk_div, limits->max_pre_pll_clk_div); in smiapp_pll_calculate()
445 min_t(uint16_t, limits->max_pre_pll_clk_div, in smiapp_pll_calculate()
446 clk_div_even(pll->ext_clk_freq_hz / in smiapp_pll_calculate()
447 limits->min_pll_ip_freq_hz)); in smiapp_pll_calculate()
449 max_t(uint16_t, limits->min_pre_pll_clk_div, in smiapp_pll_calculate()
451 DIV_ROUND_UP(pll->ext_clk_freq_hz, in smiapp_pll_calculate()
452 limits->max_pll_ip_freq_hz))); in smiapp_pll_calculate()
453 dev_dbg(dev, "pre-pll check: min / max pre_pll_clk_div: %u / %u\n", in smiapp_pll_calculate()
456 i = gcd(pll->pll_op_clk_freq_hz, pll->ext_clk_freq_hz); in smiapp_pll_calculate()
457 mul = div_u64(pll->pll_op_clk_freq_hz, i); in smiapp_pll_calculate()
458 div = pll->ext_clk_freq_hz / i; in smiapp_pll_calculate()
464 DIV_ROUND_UP(mul * pll->ext_clk_freq_hz, in smiapp_pll_calculate()
465 limits->max_pll_op_freq_hz))); in smiapp_pll_calculate()
469 for (pll->pre_pll_clk_div = min_pre_pll_clk_div; in smiapp_pll_calculate()
470 pll->pre_pll_clk_div <= max_pre_pll_clk_div; in smiapp_pll_calculate()
471 pll->pre_pll_clk_div += 2 - (pll->pre_pll_clk_div & 1)) { in smiapp_pll_calculate()
472 rval = __smiapp_pll_calculate(dev, limits, op_limits, pll, in smiapp_pll_calculate()
478 print_pll(dev, pll); in smiapp_pll_calculate()
489 MODULE_DESCRIPTION("Generic SMIA/SMIA++ PLL calculator");