diff options
Diffstat (limited to 'drivers/media/i2c/smiapp-pll.c')
-rw-r--r-- | drivers/media/i2c/smiapp-pll.c | 219 |
1 files changed, 122 insertions, 97 deletions
diff --git a/drivers/media/i2c/smiapp-pll.c b/drivers/media/i2c/smiapp-pll.c index a577614bd84f..d8d5da7c52db 100644 --- a/drivers/media/i2c/smiapp-pll.c +++ b/drivers/media/i2c/smiapp-pll.c | |||
@@ -4,7 +4,7 @@ | |||
4 | * Generic driver for SMIA/SMIA++ compliant camera modules | 4 | * Generic driver for SMIA/SMIA++ compliant camera modules |
5 | * | 5 | * |
6 | * Copyright (C) 2011--2012 Nokia Corporation | 6 | * Copyright (C) 2011--2012 Nokia Corporation |
7 | * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> | 7 | * Contact: Sakari Ailus <sakari.ailus@iki.fi> |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or | 9 | * This program is free software; you can redistribute it and/or |
10 | * modify it under the terms of the GNU General Public License | 10 | * modify it under the terms of the GNU General Public License |
@@ -58,7 +58,7 @@ static int bounds_check(struct device *dev, uint32_t val, | |||
58 | if (val >= min && val <= max) | 58 | if (val >= min && val <= max) |
59 | return 0; | 59 | return 0; |
60 | 60 | ||
61 | dev_warn(dev, "%s out of bounds: %d (%d--%d)\n", str, val, min, max); | 61 | dev_dbg(dev, "%s out of bounds: %d (%d--%d)\n", str, val, min, max); |
62 | 62 | ||
63 | return -EINVAL; | 63 | return -EINVAL; |
64 | } | 64 | } |
@@ -87,14 +87,14 @@ static void print_pll(struct device *dev, struct smiapp_pll *pll) | |||
87 | dev_dbg(dev, "vt_pix_clk_freq_hz \t%d\n", pll->vt_pix_clk_freq_hz); | 87 | dev_dbg(dev, "vt_pix_clk_freq_hz \t%d\n", pll->vt_pix_clk_freq_hz); |
88 | } | 88 | } |
89 | 89 | ||
90 | int smiapp_pll_calculate(struct device *dev, struct smiapp_pll_limits *limits, | 90 | static int __smiapp_pll_calculate(struct device *dev, |
91 | struct smiapp_pll *pll) | 91 | const struct smiapp_pll_limits *limits, |
92 | struct smiapp_pll *pll, uint32_t mul, | ||
93 | uint32_t div, uint32_t lane_op_clock_ratio) | ||
92 | { | 94 | { |
93 | uint32_t sys_div; | 95 | uint32_t sys_div; |
94 | uint32_t best_pix_div = INT_MAX >> 1; | 96 | uint32_t best_pix_div = INT_MAX >> 1; |
95 | uint32_t vt_op_binning_div; | 97 | uint32_t vt_op_binning_div; |
96 | uint32_t lane_op_clock_ratio; | ||
97 | uint32_t mul, div; | ||
98 | uint32_t more_mul_min, more_mul_max; | 98 | uint32_t more_mul_min, more_mul_max; |
99 | uint32_t more_mul_factor; | 99 | uint32_t more_mul_factor; |
100 | uint32_t min_vt_div, max_vt_div, vt_div; | 100 | uint32_t min_vt_div, max_vt_div, vt_div; |
@@ -102,54 +102,6 @@ int smiapp_pll_calculate(struct device *dev, struct smiapp_pll_limits *limits, | |||
102 | unsigned int i; | 102 | unsigned int i; |
103 | int rval; | 103 | int rval; |
104 | 104 | ||
105 | if (pll->flags & SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE) | ||
106 | lane_op_clock_ratio = pll->lanes; | ||
107 | else | ||
108 | lane_op_clock_ratio = 1; | ||
109 | dev_dbg(dev, "lane_op_clock_ratio: %d\n", lane_op_clock_ratio); | ||
110 | |||
111 | dev_dbg(dev, "binning: %dx%d\n", pll->binning_horizontal, | ||
112 | pll->binning_vertical); | ||
113 | |||
114 | /* CSI transfers 2 bits per clock per lane; thus times 2 */ | ||
115 | pll->pll_op_clk_freq_hz = pll->link_freq * 2 | ||
116 | * (pll->lanes / lane_op_clock_ratio); | ||
117 | |||
118 | /* Figure out limits for pre-pll divider based on extclk */ | ||
119 | dev_dbg(dev, "min / max pre_pll_clk_div: %d / %d\n", | ||
120 | limits->min_pre_pll_clk_div, limits->max_pre_pll_clk_div); | ||
121 | limits->max_pre_pll_clk_div = | ||
122 | min_t(uint16_t, limits->max_pre_pll_clk_div, | ||
123 | clk_div_even(pll->ext_clk_freq_hz / | ||
124 | limits->min_pll_ip_freq_hz)); | ||
125 | limits->min_pre_pll_clk_div = | ||
126 | max_t(uint16_t, limits->min_pre_pll_clk_div, | ||
127 | clk_div_even_up( | ||
128 | DIV_ROUND_UP(pll->ext_clk_freq_hz, | ||
129 | limits->max_pll_ip_freq_hz))); | ||
130 | dev_dbg(dev, "pre-pll check: min / max pre_pll_clk_div: %d / %d\n", | ||
131 | limits->min_pre_pll_clk_div, limits->max_pre_pll_clk_div); | ||
132 | |||
133 | i = gcd(pll->pll_op_clk_freq_hz, pll->ext_clk_freq_hz); | ||
134 | mul = div_u64(pll->pll_op_clk_freq_hz, i); | ||
135 | div = pll->ext_clk_freq_hz / i; | ||
136 | dev_dbg(dev, "mul %d / div %d\n", mul, div); | ||
137 | |||
138 | limits->min_pre_pll_clk_div = | ||
139 | max_t(uint16_t, limits->min_pre_pll_clk_div, | ||
140 | clk_div_even_up( | ||
141 | DIV_ROUND_UP(mul * pll->ext_clk_freq_hz, | ||
142 | limits->max_pll_op_freq_hz))); | ||
143 | dev_dbg(dev, "pll_op check: min / max pre_pll_clk_div: %d / %d\n", | ||
144 | limits->min_pre_pll_clk_div, limits->max_pre_pll_clk_div); | ||
145 | |||
146 | if (limits->min_pre_pll_clk_div > limits->max_pre_pll_clk_div) { | ||
147 | dev_err(dev, "unable to compute pre_pll divisor\n"); | ||
148 | return -EINVAL; | ||
149 | } | ||
150 | |||
151 | pll->pre_pll_clk_div = limits->min_pre_pll_clk_div; | ||
152 | |||
153 | /* | 105 | /* |
154 | * Get pre_pll_clk_div so that our pll_op_clk_freq_hz won't be | 106 | * Get pre_pll_clk_div so that our pll_op_clk_freq_hz won't be |
155 | * too high. | 107 | * too high. |
@@ -162,7 +114,7 @@ int smiapp_pll_calculate(struct device *dev, struct smiapp_pll_limits *limits, | |||
162 | more_mul_max); | 114 | more_mul_max); |
163 | /* Don't go above max pll op frequency. */ | 115 | /* Don't go above max pll op frequency. */ |
164 | more_mul_max = | 116 | more_mul_max = |
165 | min_t(int, | 117 | min_t(uint32_t, |
166 | more_mul_max, | 118 | more_mul_max, |
167 | limits->max_pll_op_freq_hz | 119 | limits->max_pll_op_freq_hz |
168 | / (pll->ext_clk_freq_hz / pll->pre_pll_clk_div * mul)); | 120 | / (pll->ext_clk_freq_hz / pll->pre_pll_clk_div * mul)); |
@@ -170,7 +122,7 @@ int smiapp_pll_calculate(struct device *dev, struct smiapp_pll_limits *limits, | |||
170 | more_mul_max); | 122 | more_mul_max); |
171 | /* Don't go above the division capability of op sys clock divider. */ | 123 | /* Don't go above the division capability of op sys clock divider. */ |
172 | more_mul_max = min(more_mul_max, | 124 | more_mul_max = min(more_mul_max, |
173 | limits->max_op_sys_clk_div * pll->pre_pll_clk_div | 125 | limits->op.max_sys_clk_div * pll->pre_pll_clk_div |
174 | / div); | 126 | / div); |
175 | dev_dbg(dev, "more_mul_max: max_op_sys_clk_div check: %d\n", | 127 | dev_dbg(dev, "more_mul_max: max_op_sys_clk_div check: %d\n", |
176 | more_mul_max); | 128 | more_mul_max); |
@@ -193,14 +145,14 @@ int smiapp_pll_calculate(struct device *dev, struct smiapp_pll_limits *limits, | |||
193 | more_mul_min); | 145 | more_mul_min); |
194 | 146 | ||
195 | if (more_mul_min > more_mul_max) { | 147 | if (more_mul_min > more_mul_max) { |
196 | dev_warn(dev, | 148 | dev_dbg(dev, |
197 | "unable to compute more_mul_min and more_mul_max"); | 149 | "unable to compute more_mul_min and more_mul_max\n"); |
198 | return -EINVAL; | 150 | return -EINVAL; |
199 | } | 151 | } |
200 | 152 | ||
201 | more_mul_factor = lcm(div, pll->pre_pll_clk_div) / div; | 153 | more_mul_factor = lcm(div, pll->pre_pll_clk_div) / div; |
202 | dev_dbg(dev, "more_mul_factor: %d\n", more_mul_factor); | 154 | dev_dbg(dev, "more_mul_factor: %d\n", more_mul_factor); |
203 | more_mul_factor = lcm(more_mul_factor, limits->min_op_sys_clk_div); | 155 | more_mul_factor = lcm(more_mul_factor, limits->op.min_sys_clk_div); |
204 | dev_dbg(dev, "more_mul_factor: min_op_sys_clk_div: %d\n", | 156 | dev_dbg(dev, "more_mul_factor: min_op_sys_clk_div: %d\n", |
205 | more_mul_factor); | 157 | more_mul_factor); |
206 | i = roundup(more_mul_min, more_mul_factor); | 158 | i = roundup(more_mul_min, more_mul_factor); |
@@ -209,7 +161,7 @@ int smiapp_pll_calculate(struct device *dev, struct smiapp_pll_limits *limits, | |||
209 | 161 | ||
210 | dev_dbg(dev, "final more_mul: %d\n", i); | 162 | dev_dbg(dev, "final more_mul: %d\n", i); |
211 | if (i > more_mul_max) { | 163 | if (i > more_mul_max) { |
212 | dev_warn(dev, "final more_mul is bad, max %d", more_mul_max); | 164 | dev_dbg(dev, "final more_mul is bad, max %d\n", more_mul_max); |
213 | return -EINVAL; | 165 | return -EINVAL; |
214 | } | 166 | } |
215 | 167 | ||
@@ -268,19 +220,19 @@ int smiapp_pll_calculate(struct device *dev, struct smiapp_pll_limits *limits, | |||
268 | dev_dbg(dev, "min_vt_div: %d\n", min_vt_div); | 220 | dev_dbg(dev, "min_vt_div: %d\n", min_vt_div); |
269 | min_vt_div = max(min_vt_div, | 221 | min_vt_div = max(min_vt_div, |
270 | DIV_ROUND_UP(pll->pll_op_clk_freq_hz, | 222 | DIV_ROUND_UP(pll->pll_op_clk_freq_hz, |
271 | limits->max_vt_pix_clk_freq_hz)); | 223 | limits->vt.max_pix_clk_freq_hz)); |
272 | dev_dbg(dev, "min_vt_div: max_vt_pix_clk_freq_hz: %d\n", | 224 | dev_dbg(dev, "min_vt_div: max_vt_pix_clk_freq_hz: %d\n", |
273 | min_vt_div); | 225 | min_vt_div); |
274 | min_vt_div = max_t(uint32_t, min_vt_div, | 226 | min_vt_div = max_t(uint32_t, min_vt_div, |
275 | limits->min_vt_pix_clk_div | 227 | limits->vt.min_pix_clk_div |
276 | * limits->min_vt_sys_clk_div); | 228 | * limits->vt.min_sys_clk_div); |
277 | dev_dbg(dev, "min_vt_div: min_vt_clk_div: %d\n", min_vt_div); | 229 | dev_dbg(dev, "min_vt_div: min_vt_clk_div: %d\n", min_vt_div); |
278 | 230 | ||
279 | max_vt_div = limits->max_vt_sys_clk_div * limits->max_vt_pix_clk_div; | 231 | max_vt_div = limits->vt.max_sys_clk_div * limits->vt.max_pix_clk_div; |
280 | dev_dbg(dev, "max_vt_div: %d\n", max_vt_div); | 232 | dev_dbg(dev, "max_vt_div: %d\n", max_vt_div); |
281 | max_vt_div = min(max_vt_div, | 233 | max_vt_div = min(max_vt_div, |
282 | DIV_ROUND_UP(pll->pll_op_clk_freq_hz, | 234 | DIV_ROUND_UP(pll->pll_op_clk_freq_hz, |
283 | limits->min_vt_pix_clk_freq_hz)); | 235 | limits->vt.min_pix_clk_freq_hz)); |
284 | dev_dbg(dev, "max_vt_div: min_vt_pix_clk_freq_hz: %d\n", | 236 | dev_dbg(dev, "max_vt_div: min_vt_pix_clk_freq_hz: %d\n", |
285 | max_vt_div); | 237 | max_vt_div); |
286 | 238 | ||
@@ -288,28 +240,28 @@ int smiapp_pll_calculate(struct device *dev, struct smiapp_pll_limits *limits, | |||
288 | * Find limitsits for sys_clk_div. Not all values are possible | 240 | * Find limitsits for sys_clk_div. Not all values are possible |
289 | * with all values of pix_clk_div. | 241 | * with all values of pix_clk_div. |
290 | */ | 242 | */ |
291 | min_sys_div = limits->min_vt_sys_clk_div; | 243 | min_sys_div = limits->vt.min_sys_clk_div; |
292 | dev_dbg(dev, "min_sys_div: %d\n", min_sys_div); | 244 | dev_dbg(dev, "min_sys_div: %d\n", min_sys_div); |
293 | min_sys_div = max(min_sys_div, | 245 | min_sys_div = max(min_sys_div, |
294 | DIV_ROUND_UP(min_vt_div, | 246 | DIV_ROUND_UP(min_vt_div, |
295 | limits->max_vt_pix_clk_div)); | 247 | limits->vt.max_pix_clk_div)); |
296 | dev_dbg(dev, "min_sys_div: max_vt_pix_clk_div: %d\n", min_sys_div); | 248 | dev_dbg(dev, "min_sys_div: max_vt_pix_clk_div: %d\n", min_sys_div); |
297 | min_sys_div = max(min_sys_div, | 249 | min_sys_div = max(min_sys_div, |
298 | pll->pll_op_clk_freq_hz | 250 | pll->pll_op_clk_freq_hz |
299 | / limits->max_vt_sys_clk_freq_hz); | 251 | / limits->vt.max_sys_clk_freq_hz); |
300 | dev_dbg(dev, "min_sys_div: max_pll_op_clk_freq_hz: %d\n", min_sys_div); | 252 | dev_dbg(dev, "min_sys_div: max_pll_op_clk_freq_hz: %d\n", min_sys_div); |
301 | min_sys_div = clk_div_even_up(min_sys_div); | 253 | min_sys_div = clk_div_even_up(min_sys_div); |
302 | dev_dbg(dev, "min_sys_div: one or even: %d\n", min_sys_div); | 254 | dev_dbg(dev, "min_sys_div: one or even: %d\n", min_sys_div); |
303 | 255 | ||
304 | max_sys_div = limits->max_vt_sys_clk_div; | 256 | max_sys_div = limits->vt.max_sys_clk_div; |
305 | dev_dbg(dev, "max_sys_div: %d\n", max_sys_div); | 257 | dev_dbg(dev, "max_sys_div: %d\n", max_sys_div); |
306 | max_sys_div = min(max_sys_div, | 258 | max_sys_div = min(max_sys_div, |
307 | DIV_ROUND_UP(max_vt_div, | 259 | DIV_ROUND_UP(max_vt_div, |
308 | limits->min_vt_pix_clk_div)); | 260 | limits->vt.min_pix_clk_div)); |
309 | dev_dbg(dev, "max_sys_div: min_vt_pix_clk_div: %d\n", max_sys_div); | 261 | dev_dbg(dev, "max_sys_div: min_vt_pix_clk_div: %d\n", max_sys_div); |
310 | max_sys_div = min(max_sys_div, | 262 | max_sys_div = min(max_sys_div, |
311 | DIV_ROUND_UP(pll->pll_op_clk_freq_hz, | 263 | DIV_ROUND_UP(pll->pll_op_clk_freq_hz, |
312 | limits->min_vt_pix_clk_freq_hz)); | 264 | limits->vt.min_pix_clk_freq_hz)); |
313 | dev_dbg(dev, "max_sys_div: min_vt_pix_clk_freq_hz: %d\n", max_sys_div); | 265 | dev_dbg(dev, "max_sys_div: min_vt_pix_clk_freq_hz: %d\n", max_sys_div); |
314 | 266 | ||
315 | /* | 267 | /* |
@@ -322,15 +274,15 @@ int smiapp_pll_calculate(struct device *dev, struct smiapp_pll_limits *limits, | |||
322 | for (sys_div = min_sys_div; | 274 | for (sys_div = min_sys_div; |
323 | sys_div <= max_sys_div; | 275 | sys_div <= max_sys_div; |
324 | sys_div += 2 - (sys_div & 1)) { | 276 | sys_div += 2 - (sys_div & 1)) { |
325 | int pix_div = DIV_ROUND_UP(vt_div, sys_div); | 277 | uint16_t pix_div = DIV_ROUND_UP(vt_div, sys_div); |
326 | 278 | ||
327 | if (pix_div < limits->min_vt_pix_clk_div | 279 | if (pix_div < limits->vt.min_pix_clk_div |
328 | || pix_div > limits->max_vt_pix_clk_div) { | 280 | || pix_div > limits->vt.max_pix_clk_div) { |
329 | dev_dbg(dev, | 281 | dev_dbg(dev, |
330 | "pix_div %d too small or too big (%d--%d)\n", | 282 | "pix_div %d too small or too big (%d--%d)\n", |
331 | pix_div, | 283 | pix_div, |
332 | limits->min_vt_pix_clk_div, | 284 | limits->vt.min_pix_clk_div, |
333 | limits->max_vt_pix_clk_div); | 285 | limits->vt.max_pix_clk_div); |
334 | continue; | 286 | continue; |
335 | } | 287 | } |
336 | 288 | ||
@@ -354,16 +306,10 @@ int smiapp_pll_calculate(struct device *dev, struct smiapp_pll_limits *limits, | |||
354 | pll->pixel_rate_csi = | 306 | pll->pixel_rate_csi = |
355 | pll->op_pix_clk_freq_hz * lane_op_clock_ratio; | 307 | pll->op_pix_clk_freq_hz * lane_op_clock_ratio; |
356 | 308 | ||
357 | print_pll(dev, pll); | 309 | rval = bounds_check(dev, pll->pll_ip_clk_freq_hz, |
358 | 310 | limits->min_pll_ip_freq_hz, | |
359 | rval = bounds_check(dev, pll->pre_pll_clk_div, | 311 | limits->max_pll_ip_freq_hz, |
360 | limits->min_pre_pll_clk_div, | 312 | "pll_ip_clk_freq_hz"); |
361 | limits->max_pre_pll_clk_div, "pre_pll_clk_div"); | ||
362 | if (!rval) | ||
363 | rval = bounds_check( | ||
364 | dev, pll->pll_ip_clk_freq_hz, | ||
365 | limits->min_pll_ip_freq_hz, limits->max_pll_ip_freq_hz, | ||
366 | "pll_ip_clk_freq_hz"); | ||
367 | if (!rval) | 313 | if (!rval) |
368 | rval = bounds_check( | 314 | rval = bounds_check( |
369 | dev, pll->pll_multiplier, | 315 | dev, pll->pll_multiplier, |
@@ -377,42 +323,121 @@ int smiapp_pll_calculate(struct device *dev, struct smiapp_pll_limits *limits, | |||
377 | if (!rval) | 323 | if (!rval) |
378 | rval = bounds_check( | 324 | rval = bounds_check( |
379 | dev, pll->op_sys_clk_div, | 325 | dev, pll->op_sys_clk_div, |
380 | limits->min_op_sys_clk_div, limits->max_op_sys_clk_div, | 326 | limits->op.min_sys_clk_div, limits->op.max_sys_clk_div, |
381 | "op_sys_clk_div"); | 327 | "op_sys_clk_div"); |
382 | if (!rval) | 328 | if (!rval) |
383 | rval = bounds_check( | 329 | rval = bounds_check( |
384 | dev, pll->op_pix_clk_div, | 330 | dev, pll->op_pix_clk_div, |
385 | limits->min_op_pix_clk_div, limits->max_op_pix_clk_div, | 331 | limits->op.min_pix_clk_div, limits->op.max_pix_clk_div, |
386 | "op_pix_clk_div"); | 332 | "op_pix_clk_div"); |
387 | if (!rval) | 333 | if (!rval) |
388 | rval = bounds_check( | 334 | rval = bounds_check( |
389 | dev, pll->op_sys_clk_freq_hz, | 335 | dev, pll->op_sys_clk_freq_hz, |
390 | limits->min_op_sys_clk_freq_hz, | 336 | limits->op.min_sys_clk_freq_hz, |
391 | limits->max_op_sys_clk_freq_hz, | 337 | limits->op.max_sys_clk_freq_hz, |
392 | "op_sys_clk_freq_hz"); | 338 | "op_sys_clk_freq_hz"); |
393 | if (!rval) | 339 | if (!rval) |
394 | rval = bounds_check( | 340 | rval = bounds_check( |
395 | dev, pll->op_pix_clk_freq_hz, | 341 | dev, pll->op_pix_clk_freq_hz, |
396 | limits->min_op_pix_clk_freq_hz, | 342 | limits->op.min_pix_clk_freq_hz, |
397 | limits->max_op_pix_clk_freq_hz, | 343 | limits->op.max_pix_clk_freq_hz, |
398 | "op_pix_clk_freq_hz"); | 344 | "op_pix_clk_freq_hz"); |
399 | if (!rval) | 345 | if (!rval) |
400 | rval = bounds_check( | 346 | rval = bounds_check( |
401 | dev, pll->vt_sys_clk_freq_hz, | 347 | dev, pll->vt_sys_clk_freq_hz, |
402 | limits->min_vt_sys_clk_freq_hz, | 348 | limits->vt.min_sys_clk_freq_hz, |
403 | limits->max_vt_sys_clk_freq_hz, | 349 | limits->vt.max_sys_clk_freq_hz, |
404 | "vt_sys_clk_freq_hz"); | 350 | "vt_sys_clk_freq_hz"); |
405 | if (!rval) | 351 | if (!rval) |
406 | rval = bounds_check( | 352 | rval = bounds_check( |
407 | dev, pll->vt_pix_clk_freq_hz, | 353 | dev, pll->vt_pix_clk_freq_hz, |
408 | limits->min_vt_pix_clk_freq_hz, | 354 | limits->vt.min_pix_clk_freq_hz, |
409 | limits->max_vt_pix_clk_freq_hz, | 355 | limits->vt.max_pix_clk_freq_hz, |
410 | "vt_pix_clk_freq_hz"); | 356 | "vt_pix_clk_freq_hz"); |
411 | 357 | ||
412 | return rval; | 358 | return rval; |
413 | } | 359 | } |
360 | |||
361 | int smiapp_pll_calculate(struct device *dev, | ||
362 | const struct smiapp_pll_limits *limits, | ||
363 | struct smiapp_pll *pll) | ||
364 | { | ||
365 | uint16_t min_pre_pll_clk_div; | ||
366 | uint16_t max_pre_pll_clk_div; | ||
367 | uint32_t lane_op_clock_ratio; | ||
368 | uint32_t mul, div; | ||
369 | unsigned int i; | ||
370 | int rval = -EINVAL; | ||
371 | |||
372 | if (pll->flags & SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE) | ||
373 | lane_op_clock_ratio = pll->csi2.lanes; | ||
374 | else | ||
375 | lane_op_clock_ratio = 1; | ||
376 | dev_dbg(dev, "lane_op_clock_ratio: %d\n", lane_op_clock_ratio); | ||
377 | |||
378 | dev_dbg(dev, "binning: %dx%d\n", pll->binning_horizontal, | ||
379 | pll->binning_vertical); | ||
380 | |||
381 | switch (pll->bus_type) { | ||
382 | case SMIAPP_PLL_BUS_TYPE_CSI2: | ||
383 | /* CSI transfers 2 bits per clock per lane; thus times 2 */ | ||
384 | pll->pll_op_clk_freq_hz = pll->link_freq * 2 | ||
385 | * (pll->csi2.lanes / lane_op_clock_ratio); | ||
386 | break; | ||
387 | case SMIAPP_PLL_BUS_TYPE_PARALLEL: | ||
388 | pll->pll_op_clk_freq_hz = pll->link_freq * pll->bits_per_pixel | ||
389 | / DIV_ROUND_UP(pll->bits_per_pixel, | ||
390 | pll->parallel.bus_width); | ||
391 | break; | ||
392 | default: | ||
393 | return -EINVAL; | ||
394 | } | ||
395 | |||
396 | /* Figure out limits for pre-pll divider based on extclk */ | ||
397 | dev_dbg(dev, "min / max pre_pll_clk_div: %d / %d\n", | ||
398 | limits->min_pre_pll_clk_div, limits->max_pre_pll_clk_div); | ||
399 | max_pre_pll_clk_div = | ||
400 | min_t(uint16_t, limits->max_pre_pll_clk_div, | ||
401 | clk_div_even(pll->ext_clk_freq_hz / | ||
402 | limits->min_pll_ip_freq_hz)); | ||
403 | min_pre_pll_clk_div = | ||
404 | max_t(uint16_t, limits->min_pre_pll_clk_div, | ||
405 | clk_div_even_up( | ||
406 | DIV_ROUND_UP(pll->ext_clk_freq_hz, | ||
407 | limits->max_pll_ip_freq_hz))); | ||
408 | dev_dbg(dev, "pre-pll check: min / max pre_pll_clk_div: %d / %d\n", | ||
409 | min_pre_pll_clk_div, max_pre_pll_clk_div); | ||
410 | |||
411 | i = gcd(pll->pll_op_clk_freq_hz, pll->ext_clk_freq_hz); | ||
412 | mul = div_u64(pll->pll_op_clk_freq_hz, i); | ||
413 | div = pll->ext_clk_freq_hz / i; | ||
414 | dev_dbg(dev, "mul %d / div %d\n", mul, div); | ||
415 | |||
416 | min_pre_pll_clk_div = | ||
417 | max_t(uint16_t, min_pre_pll_clk_div, | ||
418 | clk_div_even_up( | ||
419 | DIV_ROUND_UP(mul * pll->ext_clk_freq_hz, | ||
420 | limits->max_pll_op_freq_hz))); | ||
421 | dev_dbg(dev, "pll_op check: min / max pre_pll_clk_div: %d / %d\n", | ||
422 | min_pre_pll_clk_div, max_pre_pll_clk_div); | ||
423 | |||
424 | for (pll->pre_pll_clk_div = min_pre_pll_clk_div; | ||
425 | pll->pre_pll_clk_div <= max_pre_pll_clk_div; | ||
426 | pll->pre_pll_clk_div += 2 - (pll->pre_pll_clk_div & 1)) { | ||
427 | rval = __smiapp_pll_calculate(dev, limits, pll, mul, div, | ||
428 | lane_op_clock_ratio); | ||
429 | if (rval) | ||
430 | continue; | ||
431 | |||
432 | print_pll(dev, pll); | ||
433 | return 0; | ||
434 | } | ||
435 | |||
436 | dev_info(dev, "unable to compute pre_pll divisor\n"); | ||
437 | return rval; | ||
438 | } | ||
414 | EXPORT_SYMBOL_GPL(smiapp_pll_calculate); | 439 | EXPORT_SYMBOL_GPL(smiapp_pll_calculate); |
415 | 440 | ||
416 | MODULE_AUTHOR("Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>"); | 441 | MODULE_AUTHOR("Sakari Ailus <sakari.ailus@iki.fi>"); |
417 | MODULE_DESCRIPTION("Generic SMIA/SMIA++ PLL calculator"); | 442 | MODULE_DESCRIPTION("Generic SMIA/SMIA++ PLL calculator"); |
418 | MODULE_LICENSE("GPL"); | 443 | MODULE_LICENSE("GPL"); |