aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTony Lindgren <tony@atomide.com>2015-03-16 21:04:20 -0400
committerTero Kristo <t-kristo@ti.com>2015-03-24 14:26:05 -0400
commitcafeb002cf2cd8b0f8796b59130f9c1b91da4fcf (patch)
tree0f957ea927d32ea9691dee48a663581d7ca341c3
parent33ca29c99e8680b4c921c6eafb9fc1603c5b9779 (diff)
clk: ti: Implement FAPLL set_rate for the synthesizer
We can pretty much get any rate out of the FAPLL because of the fractional divider. Let's first try just adjusting the post divider, and if that is not enough, then reprogram both the fractional divider and the post divider. Let's also add a define for the fixed SYNTH_PHASE_K instead of using 8. Cc: Brian Hutchinson <b.hutchman@gmail.com> Cc: Matthijs van Duin <matthijsvanduin@gmail.com> Cc: Tero Kristo <t-kristo@ti.com> Signed-off-by: Tony Lindgren <tony@atomide.com> Signed-off-by: Tero Kristo <t-kristo@ti.com>
-rw-r--r--drivers/clk/ti/fapll.c134
1 files changed, 132 insertions, 2 deletions
diff --git a/drivers/clk/ti/fapll.c b/drivers/clk/ti/fapll.c
index 97138c106a67..fc06abe5eaaf 100644
--- a/drivers/clk/ti/fapll.c
+++ b/drivers/clk/ti/fapll.c
@@ -12,6 +12,7 @@
12#include <linux/clk-provider.h> 12#include <linux/clk-provider.h>
13#include <linux/delay.h> 13#include <linux/delay.h>
14#include <linux/err.h> 14#include <linux/err.h>
15#include <linux/math64.h>
15#include <linux/of.h> 16#include <linux/of.h>
16#include <linux/of_address.h> 17#include <linux/of_address.h>
17#include <linux/clk/ti.h> 18#include <linux/clk/ti.h>
@@ -47,6 +48,8 @@
47/* Synthesizer frequency register */ 48/* Synthesizer frequency register */
48#define SYNTH_LDFREQ BIT(31) 49#define SYNTH_LDFREQ BIT(31)
49 50
51#define SYNTH_PHASE_K 8
52#define SYNTH_MAX_INT_DIV 0xf
50#define SYNTH_MAX_DIV_M 0xff 53#define SYNTH_MAX_DIV_M 0xff
51 54
52struct fapll_data { 55struct fapll_data {
@@ -204,7 +207,7 @@ static unsigned long ti_fapll_synth_recalc_rate(struct clk_hw *hw,
204 /* 207 /*
205 * Synth frequency integer and fractional divider. 208 * Synth frequency integer and fractional divider.
206 * Note that the phase output K is 8, so the result needs 209 * Note that the phase output K is 8, so the result needs
207 * to be multiplied by 8. 210 * to be multiplied by SYNTH_PHASE_K.
208 */ 211 */
209 if (synth->freq) { 212 if (synth->freq) {
210 u32 v, synth_int_div, synth_frac_div, synth_div_freq; 213 u32 v, synth_int_div, synth_frac_div, synth_div_freq;
@@ -215,7 +218,7 @@ static unsigned long ti_fapll_synth_recalc_rate(struct clk_hw *hw,
215 synth_div_freq = (synth_int_div * 10000000) + synth_frac_div; 218 synth_div_freq = (synth_int_div * 10000000) + synth_frac_div;
216 rate *= 10000000; 219 rate *= 10000000;
217 do_div(rate, synth_div_freq); 220 do_div(rate, synth_div_freq);
218 rate *= 8; 221 rate *= SYNTH_PHASE_K;
219 } 222 }
220 223
221 /* Synth post-divider M */ 224 /* Synth post-divider M */
@@ -224,11 +227,138 @@ static unsigned long ti_fapll_synth_recalc_rate(struct clk_hw *hw,
224 return DIV_ROUND_UP_ULL(rate, synth_div_m); 227 return DIV_ROUND_UP_ULL(rate, synth_div_m);
225} 228}
226 229
230static unsigned long ti_fapll_synth_get_frac_rate(struct clk_hw *hw,
231 unsigned long parent_rate)
232{
233 struct fapll_synth *synth = to_synth(hw);
234 unsigned long current_rate, frac_rate;
235 u32 post_div_m;
236
237 current_rate = ti_fapll_synth_recalc_rate(hw, parent_rate);
238 post_div_m = readl_relaxed(synth->div) & SYNTH_MAX_DIV_M;
239 frac_rate = current_rate * post_div_m;
240
241 return frac_rate;
242}
243
244static u32 ti_fapll_synth_set_frac_rate(struct fapll_synth *synth,
245 unsigned long rate,
246 unsigned long parent_rate)
247{
248 u32 post_div_m, synth_int_div = 0, synth_frac_div = 0, v;
249
250 post_div_m = DIV_ROUND_UP_ULL((u64)parent_rate * SYNTH_PHASE_K, rate);
251 post_div_m = post_div_m / SYNTH_MAX_INT_DIV;
252 if (post_div_m > SYNTH_MAX_DIV_M)
253 return -EINVAL;
254 if (!post_div_m)
255 post_div_m = 1;
256
257 for (; post_div_m < SYNTH_MAX_DIV_M; post_div_m++) {
258 synth_int_div = DIV_ROUND_UP_ULL((u64)parent_rate *
259 SYNTH_PHASE_K *
260 10000000,
261 rate * post_div_m);
262 synth_frac_div = synth_int_div % 10000000;
263 synth_int_div /= 10000000;
264
265 if (synth_int_div <= SYNTH_MAX_INT_DIV)
266 break;
267 }
268
269 if (synth_int_div > SYNTH_MAX_INT_DIV)
270 return -EINVAL;
271
272 v = readl_relaxed(synth->freq);
273 v &= ~0x1fffffff;
274 v |= (synth_int_div & SYNTH_MAX_INT_DIV) << 24;
275 v |= (synth_frac_div & 0xffffff);
276 v |= SYNTH_LDFREQ;
277 writel_relaxed(v, synth->freq);
278
279 return post_div_m;
280}
281
282static long ti_fapll_synth_round_rate(struct clk_hw *hw, unsigned long rate,
283 unsigned long *parent_rate)
284{
285 struct fapll_synth *synth = to_synth(hw);
286 struct fapll_data *fd = synth->fd;
287 unsigned long r;
288
289 if (ti_fapll_clock_is_bypass(fd) || !synth->div || !rate)
290 return -EINVAL;
291
292 /* Only post divider m available with no fractional divider? */
293 if (!synth->freq) {
294 unsigned long frac_rate;
295 u32 synth_post_div_m;
296
297 frac_rate = ti_fapll_synth_get_frac_rate(hw, *parent_rate);
298 synth_post_div_m = DIV_ROUND_UP(frac_rate, rate);
299 r = DIV_ROUND_UP(frac_rate, synth_post_div_m);
300 goto out;
301 }
302
303 r = *parent_rate * SYNTH_PHASE_K;
304 if (rate > r)
305 goto out;
306
307 r = DIV_ROUND_UP_ULL(r, SYNTH_MAX_INT_DIV * SYNTH_MAX_DIV_M);
308 if (rate < r)
309 goto out;
310
311 r = rate;
312out:
313 return r;
314}
315
316static int ti_fapll_synth_set_rate(struct clk_hw *hw, unsigned long rate,
317 unsigned long parent_rate)
318{
319 struct fapll_synth *synth = to_synth(hw);
320 struct fapll_data *fd = synth->fd;
321 unsigned long frac_rate, post_rate = 0;
322 u32 post_div_m = 0, v;
323
324 if (ti_fapll_clock_is_bypass(fd) || !synth->div || !rate)
325 return -EINVAL;
326
327 /* Produce the rate with just post divider M? */
328 frac_rate = ti_fapll_synth_get_frac_rate(hw, parent_rate);
329 if (frac_rate < rate) {
330 if (!synth->freq)
331 return -EINVAL;
332 } else {
333 post_div_m = DIV_ROUND_UP(frac_rate, rate);
334 if (post_div_m && (post_div_m <= SYNTH_MAX_DIV_M))
335 post_rate = DIV_ROUND_UP(frac_rate, post_div_m);
336 if (!synth->freq && !post_rate)
337 return -EINVAL;
338 }
339
340 /* Need to recalculate the fractional divider? */
341 if ((post_rate != rate) && synth->freq)
342 post_div_m = ti_fapll_synth_set_frac_rate(synth,
343 rate,
344 parent_rate);
345
346 v = readl_relaxed(synth->div);
347 v &= ~SYNTH_MAX_DIV_M;
348 v |= post_div_m;
349 v |= SYNTH_LDMDIV1;
350 writel_relaxed(v, synth->div);
351
352 return 0;
353}
354
227static struct clk_ops ti_fapll_synt_ops = { 355static struct clk_ops ti_fapll_synt_ops = {
228 .enable = ti_fapll_synth_enable, 356 .enable = ti_fapll_synth_enable,
229 .disable = ti_fapll_synth_disable, 357 .disable = ti_fapll_synth_disable,
230 .is_enabled = ti_fapll_synth_is_enabled, 358 .is_enabled = ti_fapll_synth_is_enabled,
231 .recalc_rate = ti_fapll_synth_recalc_rate, 359 .recalc_rate = ti_fapll_synth_recalc_rate,
360 .round_rate = ti_fapll_synth_round_rate,
361 .set_rate = ti_fapll_synth_set_rate,
232}; 362};
233 363
234static struct clk * __init ti_fapll_synth_setup(struct fapll_data *fd, 364static struct clk * __init ti_fapll_synth_setup(struct fapll_data *fd,