Branch data Line data Source code
1 : : /*
2 : : * linux/arch/arm/common/icst307.c
3 : : *
4 : : * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved.
5 : : *
6 : : * This program is free software; you can redistribute it and/or modify
7 : : * it under the terms of the GNU General Public License version 2 as
8 : : * published by the Free Software Foundation.
9 : : *
10 : : * Support functions for calculating clocks/divisors for the ICST307
11 : : * clock generators. See http://www.idt.com/ for more information
12 : : * on these devices.
13 : : *
14 : : * This is an almost identical implementation to the ICST525 clock generator.
15 : : * The s2div and idx2s files are different
16 : : */
17 : : #include <linux/module.h>
18 : : #include <linux/kernel.h>
19 : :
20 : : #include <asm/hardware/icst.h>
21 : :
22 : : /*
23 : : * Divisors for each OD setting.
24 : : */
25 : : const unsigned char icst307_s2div[8] = { 10, 2, 8, 4, 5, 7, 3, 6 };
26 : : const unsigned char icst525_s2div[8] = { 10, 2, 8, 4, 5, 7, 9, 6 };
27 : : EXPORT_SYMBOL(icst307_s2div);
28 : : EXPORT_SYMBOL(icst525_s2div);
29 : :
30 : 0 : unsigned long icst_hz(const struct icst_params *p, struct icst_vco vco)
31 : : {
32 : 0 : return p->ref * 2 * (vco.v + 8) / ((vco.r + 2) * p->s2div[vco.s]);
33 : : }
34 : :
35 : : EXPORT_SYMBOL(icst_hz);
36 : :
37 : : /*
38 : : * Ascending divisor S values.
39 : : */
40 : : const unsigned char icst307_idx2s[8] = { 1, 6, 3, 4, 7, 5, 2, 0 };
41 : : const unsigned char icst525_idx2s[8] = { 1, 3, 4, 7, 5, 2, 6, 0 };
42 : : EXPORT_SYMBOL(icst307_idx2s);
43 : : EXPORT_SYMBOL(icst525_idx2s);
44 : :
45 : : struct icst_vco
46 : 0 : icst_hz_to_vco(const struct icst_params *p, unsigned long freq)
47 : : {
48 : 0 : struct icst_vco vco = { .s = 1, .v = p->vd_max, .r = p->rd_max };
49 : : unsigned long f;
50 : : unsigned int i = 0, rd, best = (unsigned int)-1;
51 : :
52 : : /*
53 : : * First, find the PLL output divisor such
54 : : * that the PLL output is within spec.
55 : : */
56 : : do {
57 : 0 : f = freq * p->s2div[p->idx2s[i]];
58 : :
59 [ # # ][ # # ]: 0 : if (f > p->vco_min && f <= p->vco_max)
60 : : break;
61 : : } while (i < 8);
62 : :
63 : : if (i >= 8)
64 : : return vco;
65 : :
66 : : vco.s = p->idx2s[i];
67 : :
68 : : /*
69 : : * Now find the closest divisor combination
70 : : * which gives a PLL output of 'f'.
71 : : */
72 [ # # ]: 0 : for (rd = p->rd_min; rd <= p->rd_max; rd++) {
73 : : unsigned long fref_div, f_pll;
74 : : unsigned int vd;
75 : : int f_diff;
76 : :
77 : 0 : fref_div = (2 * p->ref) / rd;
78 : :
79 : 0 : vd = (f + fref_div / 2) / fref_div;
80 [ # # ][ # # ]: 0 : if (vd < p->vd_min || vd > p->vd_max)
81 : 0 : continue;
82 : :
83 : 0 : f_pll = fref_div * vd;
84 : 0 : f_diff = f_pll - f;
85 [ # # ]: 0 : if (f_diff < 0)
86 : 0 : f_diff = -f_diff;
87 : :
88 [ # # ]: 0 : if ((unsigned)f_diff < best) {
89 : 0 : vco.v = vd - 8;
90 : 0 : vco.r = rd - 2;
91 [ # # ]: 0 : if (f_diff == 0)
92 : : break;
93 : : best = f_diff;
94 : : }
95 : : }
96 : :
97 : 0 : return vco;
98 : : }
99 : :
100 : : EXPORT_SYMBOL(icst_hz_to_vco);
|