1
2
3
4
5
6
7
8
9
10
11#include <linux/module.h>
12#include <linux/types.h>
13#include "si5324drv.h"
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28void si5324_rate_approx(u64 f, u64 md, u32 *num, u32 *denom)
29{
30 u64 a, h[3] = { 0, 1, 0 }, k[3] = { 1, 0, 0 };
31 u64 x, d, m, n = 1;
32 int i = 0;
33
34 if (md <= 1) {
35 *denom = 1;
36 *num = (u32)(f >> 28);
37 return;
38 }
39
40 n <<= 28;
41 for (i = 0; i < 28; i++) {
42 if ((f & 0x1) == 0) {
43 n >>= 1;
44 f >>= 1;
45 } else {
46 break;
47 }
48 }
49 d = f;
50
51 for (i = 0; i < 64; i++) {
52 a = n ? (div64_u64(d, n)) : 0;
53 if (i && !a)
54 break;
55 x = d;
56 d = n;
57 div64_u64_rem(x, n, &m);
58 n = m;
59 x = a;
60 if (k[1] * a + k[0] >= md) {
61 x = div64_u64((md - k[0]), k[1]);
62 if (x * 2 >= a || k[1] >= md)
63 i = 65;
64 else
65 break;
66 }
67 h[2] = x * h[1] + h[0];
68 h[0] = h[1];
69 h[1] = h[2];
70 k[2] = x * k[1] + k[0];
71 k[0] = k[1];
72 k[1] = k[2];
73 }
74
75 *denom = (u32)k[1];
76 *num = (u32)h[1];
77}
78
79
80
81
82
83
84
85
86
87
88
89static int si5324_find_n2ls(struct si5324_settingst *settings)
90{
91 u32 result = 0;
92 u64 f3_actual;
93 u64 fosc_actual;
94 u64 fout_actual;
95 u64 delta_fout;
96 u64 n2_ls_div_n3, mult_res;
97 u32 mult;
98
99 n2_ls_div_n3 = div64_u64(div64_u64(div64_u64(settings->fosc,
100 (settings->fin >> SI5324_FIN_FOUT_SHIFT)),
101 (u64)settings->n2_hs), (u64)2);
102
103 si5324_rate_approx(n2_ls_div_n3, settings->n31_max, &settings->n2_ls,
104 &settings->n31);
105 settings->n2_ls *= 2;
106
107 if (settings->n2_ls < settings->n2_ls_min) {
108 mult = div64_u64(settings->n2_ls_min, settings->n2_ls);
109 div64_u64_rem(settings->n2_ls_min, settings->n2_ls, &mult_res);
110 mult = mult_res ? mult + 1 : mult;
111 settings->n2_ls *= mult;
112 settings->n31 *= mult;
113 }
114
115 if (settings->n31 < settings->n31_min) {
116 mult = div64_u64(settings->n31_min, settings->n31);
117 div64_u64_rem(settings->n31_min, settings->n31, &mult_res);
118 mult = mult_res ? mult + 1 : mult;
119 settings->n2_ls *= mult;
120 settings->n31 *= mult;
121 }
122 pr_debug("Trying N2_LS = %d N3 = %d.\n", settings->n2_ls,
123 settings->n31);
124
125 if (settings->n2_ls < settings->n2_ls_min ||
126 settings->n2_ls > settings->n2_ls_max) {
127 pr_info("N2_LS out of range.\n");
128 } else if ((settings->n31 < settings->n31_min) ||
129 (settings->n31 > settings->n31_max)) {
130 pr_info("N3 out of range.\n");
131 } else {
132 f3_actual = div64_u64(settings->fin, settings->n31);
133 fosc_actual = f3_actual * settings->n2_hs * settings->n2_ls;
134 fout_actual = div64_u64(fosc_actual,
135 (settings->n1_hs * settings->nc1_ls));
136 delta_fout = fout_actual - settings->fout;
137
138 if ((f3_actual < ((u64)SI5324_F3_MIN) <<
139 SI5324_FIN_FOUT_SHIFT) ||
140 (f3_actual > ((u64)SI5324_F3_MAX) <<
141 SI5324_FIN_FOUT_SHIFT)) {
142 pr_debug("F3 frequency out of range.\n");
143 } else if ((fosc_actual < ((u64)SI5324_FOSC_MIN) <<
144 SI5324_FIN_FOUT_SHIFT) ||
145 (fosc_actual > ((u64)SI5324_FOSC_MAX) <<
146 SI5324_FIN_FOUT_SHIFT)) {
147 pr_debug("Fosc frequency out of range.\n");
148 } else if ((fout_actual < ((u64)SI5324_FOUT_MIN) <<
149 SI5324_FIN_FOUT_SHIFT) ||
150 (fout_actual > ((u64)SI5324_FOUT_MAX) <<
151 SI5324_FIN_FOUT_SHIFT)) {
152 pr_debug("Fout frequency out of range.\n");
153 } else {
154 pr_debug("Found solution: fout = %dHz delta = %dHz.\n",
155 (u32)(fout_actual >> SI5324_FIN_FOUT_SHIFT),
156 (u32)(delta_fout >> SI5324_FIN_FOUT_SHIFT));
157 pr_debug("fosc = %dkHz f3 = %dHz.\n",
158 (u32)((fosc_actual >> SI5324_FIN_FOUT_SHIFT) /
159 1000),
160 (u32)(f3_actual >> SI5324_FIN_FOUT_SHIFT));
161
162 if (((u64)abs(delta_fout)) <
163 settings->best_delta_fout) {
164 settings->best_n1_hs = settings->n1_hs;
165 settings->best_nc1_ls = settings->nc1_ls;
166 settings->best_n2_hs = settings->n2_hs;
167 settings->best_n2_ls = settings->n2_ls;
168 settings->best_n3 = settings->n31;
169 settings->best_fout = fout_actual;
170 settings->best_delta_fout = abs(delta_fout);
171 if (delta_fout == 0)
172 result = 1;
173 }
174 }
175 }
176 return result;
177}
178
179
180
181
182
183
184
185
186
187
188
189
190static int si5324_find_n2(struct si5324_settingst *settings)
191{
192 u32 result = 0;
193
194 for (settings->n2_hs = SI5324_N2_HS_MAX; settings->n2_hs >=
195 SI5324_N2_HS_MIN; settings->n2_hs--) {
196 pr_debug("Trying N2_HS = %d.\n", settings->n2_hs);
197 settings->n2_ls_min = (u32)(div64_u64(settings->fosc,
198 ((u64)(SI5324_F3_MAX * settings->n2_hs)
199 << SI5324_FIN_FOUT_SHIFT)));
200
201 if (settings->n2_ls_min < SI5324_N2_LS_MIN)
202 settings->n2_ls_min = SI5324_N2_LS_MIN;
203
204 settings->n2_ls_max = (u32)(div64_u64(settings->fosc,
205 ((u64)(SI5324_F3_MIN *
206 settings->n2_hs) <<
207 SI5324_FIN_FOUT_SHIFT)));
208 if (settings->n2_ls_max > SI5324_N2_LS_MAX)
209 settings->n2_ls_max = SI5324_N2_LS_MAX;
210
211 result = si5324_find_n2ls(settings);
212 if (result)
213 break;
214 }
215 return result;
216}
217
218
219
220
221
222
223
224
225
226
227
228
229int si5324_calc_ncls_limits(struct si5324_settingst *settings)
230{
231 settings->nc1_ls_min = div64_u64(settings->n1_hs_min,
232 settings->n1_hs);
233
234 if (settings->nc1_ls_min < SI5324_NC_LS_MIN)
235 settings->nc1_ls_min = SI5324_NC_LS_MIN;
236 if (settings->nc1_ls_min > 1 && (settings->nc1_ls_min & 0x1) == 1)
237 settings->nc1_ls_min++;
238 settings->nc1_ls_max = div64_u64(settings->n1_hs_max, settings->n1_hs);
239
240 if (settings->nc1_ls_max > SI5324_NC_LS_MAX)
241 settings->nc1_ls_max = SI5324_NC_LS_MAX;
242
243 if ((settings->nc1_ls_max & 0x1) == 1)
244 settings->nc1_ls_max--;
245 if ((settings->nc1_ls_max * settings->n1_hs < settings->n1_hs_min) ||
246 (settings->nc1_ls_min * settings->n1_hs > settings->n1_hs_max))
247 return -1;
248
249 return 0;
250}
251
252
253
254
255
256
257
258
259
260
261
262
263
264static int si5324_find_ncls(struct si5324_settingst *settings)
265{
266 u64 fosc_1;
267 u32 result;
268
269 fosc_1 = settings->fout * settings->n1_hs;
270 for (settings->nc1_ls = settings->nc1_ls_min;
271 settings->nc1_ls <= settings->nc1_ls_max;) {
272 settings->fosc = fosc_1 * settings->nc1_ls;
273 pr_debug("Trying NCn_LS = %d: fosc = %dkHz.\n",
274 settings->nc1_ls,
275 (u32)(div64_u64((settings->fosc >>
276 SI5324_FIN_FOUT_SHIFT), 1000)));
277
278 result = si5324_find_n2(settings);
279 if (result)
280 break;
281 if (settings->nc1_ls == 1)
282 settings->nc1_ls++;
283 else
284 settings->nc1_ls += 2;
285 }
286 return result;
287}
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308int si5324_calcfreqsettings(u32 clkinfreq, u32 clkoutfreq, u32 *clkactual,
309 u8 *n1_hs, u32 *ncn_ls, u8 *n2_hs, u32 *n2_ls,
310 u32 *n3n, u8 *bwsel)
311{
312 struct si5324_settingst settings;
313 int result;
314
315 settings.fin = (u64)clkinfreq << SI5324_FIN_FOUT_SHIFT;
316 settings.fout = (u64)clkoutfreq << SI5324_FIN_FOUT_SHIFT;
317 settings.best_delta_fout = settings.fout;
318
319 settings.n1_hs_min = (int)(div64_u64(SI5324_FOSC_MIN, clkoutfreq));
320 if (settings.n1_hs_min < SI5324_N1_HS_MIN * SI5324_NC_LS_MIN)
321 settings.n1_hs_min = SI5324_N1_HS_MIN * SI5324_NC_LS_MIN;
322
323 settings.n1_hs_max = (int)(div64_u64(SI5324_FOSC_MAX, clkoutfreq));
324 if (settings.n1_hs_max > SI5324_N1_HS_MAX * SI5324_NC_LS_MAX)
325 settings.n1_hs_max = SI5324_N1_HS_MAX * SI5324_NC_LS_MAX;
326
327 settings.n31_min = div64_u64(clkinfreq, SI5324_F3_MAX);
328 if (settings.n31_min < SI5324_N3_MIN)
329 settings.n31_min = SI5324_N3_MIN;
330
331 settings.n31_max = div64_u64(clkinfreq, SI5324_F3_MIN);
332 if (settings.n31_max > SI5324_N3_MAX)
333 settings.n31_max = SI5324_N3_MAX;
334
335
336
337
338 for (settings.n1_hs = SI5324_N1_HS_MAX;
339 settings.n1_hs >= SI5324_N1_HS_MIN; settings.n1_hs--) {
340 pr_debug("Trying N1_HS = %d.\n", settings.n1_hs);
341
342 result = si5324_calc_ncls_limits(&settings);
343 if (result) {
344 pr_debug("No valid settings\n");
345 continue;
346 }
347 result = si5324_find_ncls(&settings);
348 if (result)
349 break;
350 }
351
352 pr_debug("Si5324: settings.best_delta_fout = %llu\n",
353 (unsigned long long)settings.best_delta_fout);
354 pr_debug("Si5324: settings.fout = %llu\n",
355 (unsigned long long)settings.fout);
356
357 if (settings.best_delta_fout == settings.fout) {
358 pr_debug("Si5324: No valid settings found.");
359 return SI5324_ERR_FREQ;
360 }
361 pr_debug("Si5324: Found solution: fout = %dHz.\n",
362 (u32)(settings.best_fout >> 28));
363
364
365 *n1_hs = (u8)settings.best_n1_hs - 4;
366 *ncn_ls = settings.best_nc1_ls - 1;
367 *n2_hs = (u8)settings.best_n2_hs - 4;
368 *n2_ls = settings.best_n2_ls - 1;
369 *n3n = settings.best_n3 - 1;
370
371
372
373
374
375
376 *bwsel = 6;
377
378 if (clkactual)
379 *clkactual = (settings.best_fout >> SI5324_FIN_FOUT_SHIFT);
380
381 return SI5324_SUCCESS;
382}
383