Commit | Line | Data |
---|---|---|
a09e091a JB |
1 | #ifdef HAVE_XORG_CONFIG_H |
2 | #include <xorg-config.h> | |
3 | #endif | |
4 | ||
5 | #include <unistd.h> | |
6 | #include <stdlib.h> | |
7 | #include <string.h> | |
8 | #include <math.h> | |
9 | ||
10 | #include "xf86.h" | |
11 | #include "xf86i2c.h" | |
12 | #include "fi1236.h" | |
13 | #include "tda9885.h" | |
14 | #include "i2c_def.h" | |
15 | ||
16 | #define NUM_TUNERS 8 | |
17 | ||
18 | const FI1236_parameters tuner_parms[NUM_TUNERS] = { | |
19 | /* 0 - FI1236 */ | |
20 | {733, 884, 12820, 2516, 7220, 0xA2, 0x94, 0x34, 0x8e}, | |
21 | /* !!!based on documentation - it should be: | |
22 | {733, 16*55.25, 16*801.25, 16*160, 16*454, 0xA0, 0x90, 0x30, 0x8e}, */ | |
23 | ||
24 | /* 1 - FI1216 */ | |
25 | {623, 16 * 48.75, 16 * 855.25, 16 * 170, 16 * 450, 0xA0, 0x90, 0x30, 0x8e}, | |
26 | /* 2 - TEMIC FN5AL */ | |
27 | {623, 16 * 45.75, 16 * 855.25, 16 * 169, 16 * 454, 0xA0, 0x90, 0x30, 0x8e}, | |
28 | /* 3 - MT2032.. */ | |
29 | {733, 768, 13760, 0, 0, 0, 0, 0, 0}, | |
30 | /* 4 - FI1246 */ | |
31 | {623, 16 * 45.75, 16 * 855.25, 16 * 170, 16 * 450, 0xA0, 0x90, 0x30, 0x8e}, | |
32 | /* 5 - FI1256 */ | |
33 | {623, 16 * 49.75, 16 * 863.25, 16 * 170, 16 * 450, 0xA0, 0x90, 0x30, 0x8e}, | |
34 | /* 6 - FI1236W */ | |
35 | /*{ 733, 884, 12820, 2516, 7220, 0x1, 0x2, 0x4, 0x8e }, */ | |
36 | {732, 16 * 55.25, 16 * 801.25, 16 * 160, 16 * 442, 0x1, 0x2, 0x4, 0x8e}, | |
37 | /* 7 - FM1216ME */ | |
38 | {623, 16 * 48.25, 16 * 863.25, 16 * 158.00, 16 * 442.00, 0x1, 0x2, 0x4, 0x8e} | |
39 | }; | |
40 | ||
41 | FI1236Ptr | |
42 | Detect_FI1236(I2CBusPtr b, I2CSlaveAddr addr) | |
43 | { | |
44 | FI1236Ptr f; | |
45 | I2CByte a; | |
46 | ||
47 | f = calloc(1, sizeof(FI1236Rec)); | |
48 | if (f == NULL) | |
49 | return NULL; | |
50 | f->d.DevName = strdup("FI12xx Tuner"); | |
51 | f->d.SlaveAddr = addr; | |
52 | f->d.pI2CBus = b; | |
53 | f->d.NextDev = NULL; | |
54 | f->d.StartTimeout = b->StartTimeout; | |
55 | f->d.BitTimeout = b->BitTimeout; | |
56 | f->d.AcknTimeout = b->AcknTimeout; | |
57 | f->d.ByteTimeout = b->ByteTimeout; | |
58 | f->type = TUNER_TYPE_FI1236; | |
59 | f->afc_timer_installed = FALSE; | |
60 | f->last_afc_hint = TUNER_OFF; | |
61 | f->video_if = 45.7812; | |
62 | ||
63 | if (!I2C_WriteRead(&(f->d), NULL, 0, &a, 1)) { | |
64 | free(f); | |
65 | return NULL; | |
66 | } | |
67 | FI1236_set_tuner_type(f, TUNER_TYPE_FI1236); | |
68 | if (!I2CDevInit(&(f->d))) { | |
69 | free(f); | |
70 | return NULL; | |
71 | } | |
72 | return f; | |
73 | } | |
74 | ||
75 | static void | |
76 | MT2032_dump_parameters(FI1236Ptr f, MT2032_parameters * m) | |
77 | { | |
78 | xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, | |
79 | "MT2032: input f_rf=%g f_if1=%g f_if2=%g f_ref=%g f_ifbw=%g f_step=%g\n", | |
80 | m->f_rf, m->f_if1, m->f_if2, m->f_ref, m->f_ifbw, m->f_step); | |
81 | ||
82 | xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, | |
83 | "MT2032: computed f_lo1=%g f_lo2=%g LO1I=%d LO2I=%d SEL=%d STEP=%d NUM=%d\n", | |
84 | m->f_lo1, m->f_lo2, m->LO1I, m->LO2I, m->SEL, m->STEP, m->NUM); | |
85 | } | |
86 | ||
87 | static void | |
88 | MT2032_getid(FI1236Ptr f) | |
89 | { | |
90 | CARD8 out[4]; | |
91 | CARD8 in; | |
92 | ||
93 | in = 0x11; | |
94 | I2C_WriteRead(&(f->d), (I2CByte *) &in, 1, out, 4); | |
95 | xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, | |
96 | "MT2032: Company code 0x%02x%02x, part code 0x%02x, revision code 0x%02x\n", | |
97 | out[0], out[1], out[2], out[3]); | |
98 | ||
99 | } | |
100 | ||
101 | /* might be buggy */ | |
102 | #if 0 | |
103 | static void | |
104 | MT2032_shutdown(FI1236Ptr f) | |
105 | { | |
106 | CARD8 data[10]; | |
107 | ||
108 | data[0] = 0x00; /* start with register 0x00 */ | |
109 | data[1] = 0x1A; | |
110 | data[2] = 0x44; | |
111 | data[3] = 0x20; | |
112 | ||
113 | I2C_WriteRead(&(f->d), (I2CByte *) data, 4, NULL, 0); | |
114 | ||
115 | data[0] = 0x05; /* now start with register 0x05 */ | |
116 | data[1] = 0xD7; | |
117 | data[2] = 0x14; | |
118 | data[3] = 0x05; | |
119 | I2C_WriteRead(&(f->d), (I2CByte *) data, 4, NULL, 0); | |
120 | ||
121 | data[0] = 0x0B; /* now start with register 0x05 */ | |
122 | data[1] = 0x8F; | |
123 | data[2] = 0x07; | |
124 | data[3] = 0x43; | |
125 | I2C_WriteRead(&(f->d), (I2CByte *) data, 4, NULL, 0); | |
126 | ||
127 | usleep(15000); | |
128 | } | |
129 | #endif | |
130 | ||
131 | static void MT2032_dump_status(FI1236Ptr f); | |
132 | ||
133 | static void | |
134 | MT2032_init(FI1236Ptr f) | |
135 | { | |
136 | CARD8 data[10]; | |
137 | CARD8 value; | |
138 | CARD8 xogc = 0x00; | |
139 | ||
140 | MT2032_getid(f); | |
141 | ||
142 | data[0] = 0x02; /* start with register 0x02 */ | |
143 | data[1] = 0xFF; | |
144 | data[2] = 0x0F; | |
145 | data[3] = 0x1F; | |
146 | ||
147 | I2C_WriteRead(&(f->d), (I2CByte *) data, 4, NULL, 0); | |
148 | ||
149 | data[0] = 0x06; /* now start with register 0x06 */ | |
150 | data[1] = 0xE4; | |
151 | data[2] = 0x8F; | |
152 | data[3] = 0xC3; | |
153 | data[4] = 0x4E; | |
154 | data[5] = 0xEC; | |
155 | I2C_WriteRead(&(f->d), (I2CByte *) data, 6, NULL, 0); | |
156 | ||
157 | data[0] = 0x0d; /* now start with register 0x0d */ | |
158 | data[1] = 0x32; | |
159 | I2C_WriteRead(&(f->d), (I2CByte *) data, 2, NULL, 0); | |
160 | ||
161 | while (1) { | |
162 | usleep(15000); /* wait 15 milliseconds */ | |
163 | ||
164 | data[0] = 0x0e; /* register number 7, status */ | |
165 | value = 0xFF; | |
166 | if (!I2C_WriteRead(&(f->d), (I2CByte *) data, 1, &value, 1)) | |
167 | xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, | |
168 | "MT2032: failed to read XOK\n"); | |
169 | xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, | |
170 | "MT2032: XOK=%d\n", value & 0x01); | |
171 | if (value & 1) | |
172 | break; | |
173 | ||
174 | data[0] = 0x07; | |
175 | if (!I2C_WriteRead(&(f->d), (I2CByte *) data, 1, &value, 1)) | |
176 | xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, | |
177 | "MT2032: failed to read XOGC\n"); | |
178 | ||
179 | xogc = value & 0x7; | |
180 | if (xogc == 4) | |
181 | break; /* XOGC has reached 4.. stop */ | |
182 | xogc--; | |
183 | xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, | |
184 | "MT2032: try XOGC=%d\n", xogc); | |
185 | usleep(15000); | |
186 | data[0] = 0x07; /* register number 7, control byte 2 */ | |
187 | data[1] = 0x08 | xogc; | |
188 | I2C_WriteRead(&(f->d), (I2CByte *) data, 2, NULL, 0); | |
189 | } | |
190 | f->xogc = xogc; | |
191 | /* wait before continuing */ | |
192 | usleep(15000); /* wait 50 milliseconds */ | |
193 | MT2032_dump_status(f); | |
194 | } | |
195 | ||
196 | static int | |
197 | MT2032_no_spur_in_band(MT2032_parameters * m) | |
198 | { | |
199 | int n_max, n1, n2; | |
200 | double f_test; | |
201 | ||
202 | n_max = 5; | |
203 | n1 = 1; | |
204 | while (1) { | |
205 | n2 = -n1; | |
206 | f_test = n1 * (m->f_lo1 - m->f_lo2); | |
207 | while (1) { | |
208 | n2--; | |
209 | f_test = f_test - m->f_lo2; | |
210 | xf86DrvMsg(0, X_INFO, | |
211 | "testing f_test=%g n1=%d n2=%d f_lo1=%g f_lo2=%g f_if2=%g\n", | |
212 | f_test, n1, n2, m->f_lo1, m->f_lo2, m->f_if2); | |
213 | xf86DrvMsg(0, X_INFO, "d_f=%g f_ifbw=%g\n", | |
214 | fabs(fabs(f_test) - m->f_if2), m->f_ifbw); | |
215 | if ((fabs(fabs(f_test) - m->f_if2) * 2.0) <= m->f_ifbw) | |
216 | return 0; | |
217 | if (n2 <= -n_max) | |
218 | break; | |
219 | /* this line in the manual is bogus. I say it is faster | |
220 | and more correct to go over all harmonics.. */ | |
221 | #if 0 | |
222 | if (f_test < (m->f_lo2 - m->f_if2 - m->f_ifbw)) | |
223 | break; | |
224 | #endif | |
225 | } | |
226 | n1++; | |
227 | if (n1 >= n_max) | |
228 | return 1; | |
229 | } | |
230 | ||
231 | } | |
232 | ||
233 | static void | |
234 | MT2032_calculate_register_settings(MT2032_parameters * m, double f_rf, | |
235 | double f_if1, double f_if2, double f_ref, | |
236 | double f_ifbw, double f_step) | |
237 | { | |
238 | int n; | |
239 | ||
240 | m->f_rf = f_rf; | |
241 | m->f_if1 = f_if1; | |
242 | m->f_if2 = f_if2; | |
243 | m->f_ref = f_ref; | |
244 | m->f_ifbw = f_ifbw; | |
245 | m->f_step = f_step; | |
246 | ||
247 | m->f_lo1 = f_rf + f_if1; | |
248 | m->LO1I = lrint(m->f_lo1 / f_ref); | |
249 | m->f_lo1 = f_ref * m->LO1I; | |
250 | ||
251 | m->f_lo2 = m->f_lo1 - f_rf - f_if2; | |
252 | ||
253 | /* check for spurs */ | |
254 | n = 1; | |
255 | while (n < 3) { | |
256 | if (MT2032_no_spur_in_band(m)) | |
257 | break; | |
258 | ||
259 | if (m->f_lo1 < (f_rf + f_if1)) | |
260 | m->LO1I += n; | |
261 | else | |
262 | m->LO1I -= n; | |
263 | ||
264 | m->f_lo1 = m->LO1I * f_ref; | |
265 | m->f_lo2 = m->f_lo1 - f_rf - f_if2; | |
266 | n++; | |
267 | } | |
268 | /* xf86DrvMsg(0, X_INFO, "MT2032: n=%d\n", n); */ | |
269 | /* select VCO */ | |
270 | ||
271 | /* m->f_lo1>1100.0 */ | |
272 | if (m->f_lo1 < 1370.0) | |
273 | m->SEL = 4; | |
274 | else if (m->f_lo1 < 1530.0) | |
275 | m->SEL = 3; | |
276 | else if (m->f_lo1 < 1720.0) | |
277 | m->SEL = 2; | |
278 | else if (m->f_lo1 < 1890.0) | |
279 | m->SEL = 1; | |
280 | else /* m->f_lo1 < 1958.0 */ | |
281 | m->SEL = 0; | |
282 | ||
283 | /* calculate the rest of the registers */ | |
284 | m->LO2I = floor(m->f_lo2 / f_ref); | |
285 | m->STEP = floor(3780.0 * f_step / f_ref); | |
286 | m->NUM = floor(3780.0 * (m->f_lo2 / f_ref - m->LO2I)); | |
287 | m->NUM = m->STEP * lrint((1.0 * m->NUM) / (1.0 * m->STEP)); | |
288 | } | |
289 | ||
290 | static int | |
291 | MT2032_wait_for_lock(FI1236Ptr f) | |
292 | { | |
293 | int n; | |
294 | CARD8 data[10]; | |
295 | CARD8 value; | |
296 | ||
297 | n = 12; | |
298 | while (1) { | |
299 | data[0] = 0x0e; /* register number 7, status */ | |
300 | I2C_WriteRead(&(f->d), (I2CByte *) data, 1, &value, 1); | |
301 | /* xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, | |
302 | "MT2032: LO1LK=%d LO2LK=%d\n", | |
303 | (value & 0x04)>>2, (value & 0x02)>>1); */ | |
304 | if ((value & 6) == 6) | |
305 | break; | |
306 | usleep(1500); | |
307 | n--; | |
308 | if (n < 0) | |
309 | break; | |
310 | } | |
311 | if (n < 0) { | |
312 | xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, | |
313 | "MT2032: failed to set frequency\n"); | |
314 | return 0; | |
315 | } | |
316 | return 1; | |
317 | } | |
318 | ||
319 | static void | |
320 | MT2032_implement_settings(FI1236Ptr f, MT2032_parameters * m) | |
321 | { | |
322 | CARD8 data[10]; | |
323 | CARD8 value; | |
324 | ||
325 | data[0] = 0x00; /* start with register 0x00 */ | |
326 | data[1] = (m->LO1I >> 3) - 1; | |
327 | data[2] = (m->SEL << 4) | (m->LO1I & 0x7); | |
328 | data[3] = 0x86; | |
329 | I2C_WriteRead(&(f->d), (I2CByte *) data, 4, NULL, 0); | |
330 | ||
331 | data[0] = 0x05; /* start with register 0x05 */ | |
332 | data[1] = ((m->LO2I & 0x7) << 5) | ((m->LO2I >> 3) - 1); | |
333 | if (m->f_rf < 400.0) | |
334 | data[2] = 0xe4; | |
335 | else | |
336 | data[2] = 0xf4; | |
337 | I2C_WriteRead(&(f->d), (I2CByte *) data, 3, NULL, 0); | |
338 | ||
339 | data[0] = 0x07; /* register number 7, control byte 2 */ | |
340 | I2C_WriteRead(&(f->d), (I2CByte *) data, 1, &value, 1); | |
341 | xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, | |
342 | "MT2032: using XOGC=%d\n", (value & 0x07)); | |
343 | data[1] = 8 | (value & 0x7); | |
344 | I2C_WriteRead(&(f->d), (I2CByte *) data, 2, NULL, 0); | |
345 | ||
346 | data[0] = 0x0b; /* start with register 0x0b */ | |
347 | data[1] = m->NUM & 0xff; | |
348 | data[2] = (1 << 7) | ((m->NUM >> 8) & 0x0f); | |
349 | I2C_WriteRead(&(f->d), (I2CByte *) data, 3, NULL, 0); | |
350 | ||
351 | MT2032_wait_for_lock(f); | |
352 | } | |
353 | ||
354 | static void | |
355 | MT2032_optimize_VCO(FI1236Ptr f, MT2032_parameters * m) | |
356 | { | |
357 | CARD8 data[10]; | |
358 | CARD8 value; | |
359 | CARD8 TAD1; | |
360 | ||
361 | data[0] = 0x0f; /* register number 7, status */ | |
362 | I2C_WriteRead(&(f->d), (I2CByte *) data, 1, &value, 1); | |
363 | TAD1 = value & 0x07; | |
364 | xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, | |
365 | "MT2032: TAD1=%d SEL=%d\n", TAD1, m->SEL); | |
366 | if (TAD1 < 2) | |
367 | return; | |
368 | if (TAD1 == 2) { | |
369 | if (m->SEL == 0) | |
370 | return; | |
371 | m->SEL--; | |
372 | } | |
373 | else { | |
374 | if (m->SEL >= 4) | |
375 | return; | |
376 | m->SEL++; | |
377 | } | |
378 | data[0] = 0x01; /* start with register 1 */ | |
379 | data[1] = (m->SEL << 4) | (m->LO1I & 0x7); | |
380 | I2C_WriteRead(&(f->d), (I2CByte *) data, 2, NULL, 0); | |
381 | ||
382 | } | |
383 | ||
384 | static int | |
385 | FI1236_get_afc_hint(FI1236Ptr f) | |
386 | { | |
387 | CARD8 out; | |
388 | CARD8 AFC; | |
389 | ||
390 | if ((f->type == TUNER_TYPE_FM1216ME) || (f->type == TUNER_TYPE_FI1236W)) { | |
391 | TDA9885Ptr t = (TDA9885Ptr) f->afc_source; | |
392 | ||
393 | if (t == NULL) | |
394 | return TUNER_OFF; | |
395 | ||
396 | tda9885_getstatus(t); | |
397 | tda9885_dumpstatus(t); | |
398 | AFC = t->afc_status & 0x0f; | |
399 | ||
400 | xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, | |
401 | "AFC: FI1236_get_afc_hint: %i\n", AFC); | |
402 | if (AFC == 0) | |
403 | return TUNER_TUNED; | |
404 | else if (AFC <= 0x07) | |
405 | return TUNER_JUST_BELOW; | |
406 | else if (AFC < 0x0f) | |
407 | return TUNER_JUST_ABOVE; | |
408 | else if (AFC == 0x0f) | |
409 | return TUNER_TUNED; | |
410 | } | |
411 | else { | |
412 | I2C_WriteRead(&(f->d), NULL, 0, &out, 1); | |
413 | AFC = out & 0x7; | |
414 | xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, | |
415 | "AFC: FI1236_get_afc_hint: %i\n", AFC); | |
416 | if (AFC == 2) | |
417 | return TUNER_TUNED; | |
418 | if (AFC == 3) | |
419 | return TUNER_JUST_BELOW; | |
420 | if (AFC == 1) | |
421 | return TUNER_JUST_ABOVE; | |
422 | return TUNER_OFF; | |
423 | } | |
424 | return TUNER_OFF; | |
425 | } | |
426 | ||
427 | static int | |
428 | MT2032_get_afc_hint(FI1236Ptr f) | |
429 | { | |
430 | CARD8 in; | |
431 | CARD8 out[2]; | |
432 | CARD8 AFC; | |
433 | ||
434 | in = 0x0e; | |
435 | I2C_WriteRead(&(f->d), (I2CByte *) &in, 1, out, 2); | |
436 | AFC = (out[0] >> 4) & 0x7; | |
437 | #if 0 | |
438 | xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "AFC=%d TAD1=%d TAD2=%d\n", | |
439 | AFC, out[1] & 0x7, (out[1] >> 4) & 0x07); | |
440 | #endif | |
441 | if (AFC == 2) | |
442 | return TUNER_TUNED; | |
443 | if (AFC == 3) | |
444 | return TUNER_JUST_BELOW; | |
445 | if (AFC == 1) | |
446 | return TUNER_JUST_ABOVE; | |
447 | return TUNER_OFF; | |
448 | } | |
449 | ||
450 | /* this function is for external use only */ | |
451 | int | |
452 | TUNER_get_afc_hint(FI1236Ptr f) | |
453 | { | |
454 | if (f->afc_timer_installed) | |
455 | return TUNER_STILL_TUNING; | |
456 | return f->last_afc_hint; | |
457 | } | |
458 | ||
459 | static void | |
460 | MT2032_dump_status(FI1236Ptr f) | |
461 | { | |
462 | CARD8 in; | |
463 | CARD8 out[2]; | |
464 | CARD8 AFC; | |
465 | CARD8 LDONrb; | |
466 | CARD8 LO1LK, LO2LK, XOK; | |
467 | CARD8 TAD2, TAD1; | |
468 | ||
469 | in = 0x0e; | |
470 | I2C_WriteRead(&(f->d), (I2CByte *) &in, 1, out, 2); | |
471 | XOK = out[0] & 1; | |
472 | LO1LK = (out[0] >> 2) & 1; | |
473 | LO2LK = (out[0] >> 1) & 1; | |
474 | LDONrb = (out[0] >> 3) & 1; | |
475 | ||
476 | AFC = (out[0] >> 4) & 0x7; | |
477 | ||
478 | TAD1 = (out[1] & 0x7); | |
479 | TAD2 = (out[1] >> 4) & 0x7; | |
480 | ||
481 | xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, | |
482 | "MT2032: status: XOK=%d LO1LK=%d LO2LK=%d LDONrb=%d AFC=%d TAD1=%d TAD2=%d\n", | |
483 | XOK, LO1LK, LO2LK, LDONrb, AFC, TAD1, TAD2); | |
484 | xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, | |
485 | "MT2032: status: OSCILLATOR:%s PLL1:%s PLL2:%s\n", | |
486 | XOK ? "ok" : "off", | |
487 | LO1LK ? "locked" : "off", LO2LK ? "locked" : "off"); | |
488 | ||
489 | } | |
490 | ||
491 | static void | |
492 | MT2032_tune(FI1236Ptr f, double freq, double step) | |
493 | { | |
494 | MT2032_parameters m; | |
495 | CARD8 data[10]; | |
496 | int i; | |
497 | ||
498 | /* NTSC IF is 44mhz.. but 733/16=45.8125 and all TDAXXXX docs mention | |
499 | 45.75, 39, 58.75 and 30. */ | |
500 | #if 0 | |
501 | MT2032_calculate_register_settings(&m, freq, 1090.0, 45.125, 5.25, 6.0, | |
502 | step); | |
503 | MT2032_calculate_register_settings(&m, freq, 1090.0, 45.74, 5.25, 6.0, | |
504 | step); | |
505 | #endif | |
506 | MT2032_calculate_register_settings(&m, freq, 1090.0, f->video_if, 5.25, 3.0, | |
507 | step); | |
508 | MT2032_dump_parameters(f, &m); | |
509 | MT2032_implement_settings(f, &m); | |
510 | /* MT2032_dump_parameters(f, &m); */ | |
511 | for (i = 0; i < 3; i++) { | |
512 | MT2032_optimize_VCO(f, &m); | |
513 | if (MT2032_wait_for_lock(f)) { | |
514 | data[0] = 0x02; /* LO Gain control register 0x02 */ | |
515 | data[1] = 0x20; | |
516 | I2C_WriteRead(&(f->d), (I2CByte *) data, 2, NULL, 0); | |
517 | return; | |
518 | } | |
519 | data[0] = 0x07; | |
520 | data[1] = 0x88 | f->xogc; | |
521 | I2C_WriteRead(&(f->d), (I2CByte *) data, 2, NULL, 0); | |
522 | usleep(15000); | |
523 | data[1] = 0x08 | f->xogc; | |
524 | I2C_WriteRead(&(f->d), (I2CByte *) data, 2, NULL, 0); | |
525 | } | |
526 | xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, | |
527 | "MT2032: failed to set frequency\n"); | |
528 | } | |
529 | ||
530 | void | |
531 | FI1236_set_tuner_type(FI1236Ptr f, int type) | |
532 | { | |
533 | f->type = type; | |
534 | if (type >= NUM_TUNERS) | |
535 | type = NUM_TUNERS - 1; | |
536 | if (type < 0) | |
537 | type = 0; | |
538 | memcpy(&(f->parm), &(tuner_parms[type]), sizeof(FI1236_parameters)); | |
539 | f->original_frequency = f->parm.min_freq; | |
540 | f->afc_delta = 0; | |
541 | if (type == TUNER_TYPE_MT2032) { | |
542 | MT2032_init(f); | |
543 | return; | |
544 | } | |
545 | } | |
546 | ||
547 | static CARD32 | |
548 | AFC_TimerCallback(OsTimerPtr timer, CARD32 time, pointer data) | |
549 | { | |
550 | FI1236Ptr f = (FI1236Ptr) data; | |
551 | ||
552 | if (FI1236_AFC(f)) | |
553 | return 150; | |
554 | else { | |
555 | f->afc_timer_installed = FALSE; | |
556 | f->afc_count = 0; | |
557 | return 0; | |
558 | } | |
559 | } | |
560 | ||
561 | void | |
562 | FI1236_tune(FI1236Ptr f, CARD32 frequency) | |
563 | { | |
564 | CARD16 divider; | |
565 | CARD8 data; | |
566 | ||
567 | if (frequency < f->parm.min_freq) | |
568 | frequency = f->parm.min_freq; | |
569 | if (frequency > f->parm.max_freq) | |
570 | frequency = f->parm.max_freq; | |
571 | ||
572 | divider = (f->parm.fcar + (CARD16) frequency) & 0x7fff; | |
573 | f->tuner_data.div1 = (CARD8) ((divider >> 8) & 0x7f); | |
574 | f->tuner_data.div2 = (CARD8) (divider & 0xff); | |
575 | f->tuner_data.control = f->parm.control; | |
576 | ||
577 | if (frequency < f->parm.threshold1) | |
578 | f->tuner_data.band = f->parm.band_low; | |
579 | else if (frequency < f->parm.threshold2) | |
580 | f->tuner_data.band = f->parm.band_mid; | |
581 | else | |
582 | f->tuner_data.band = f->parm.band_high; | |
583 | ||
584 | xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, | |
585 | "Setting tuner band to %d\n", f->tuner_data.band); | |
586 | ||
587 | xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, | |
588 | "Setting tuner frequency to %d\n", (int) frequency); | |
589 | ||
590 | if ((f->type == TUNER_TYPE_FM1216ME) || (f->type == TUNER_TYPE_FI1236W)) { | |
591 | f->tuner_data.aux = 0x20; | |
592 | I2C_WriteRead(&(f->d), (I2CByte *) &(f->tuner_data), 5, NULL, 0); | |
593 | I2C_WriteRead(&(f->d), NULL, 0, &data, 1); | |
594 | xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "Tuner status %x\n", data); | |
595 | } | |
596 | else | |
597 | I2C_WriteRead(&(f->d), (I2CByte *) &(f->tuner_data), 4, NULL, 0); | |
598 | } | |
599 | ||
600 | void | |
601 | TUNER_set_frequency(FI1236Ptr f, CARD32 frequency) | |
602 | { | |
603 | if (frequency < f->parm.min_freq) | |
604 | frequency = f->parm.min_freq; | |
605 | if (frequency > f->parm.max_freq) | |
606 | frequency = f->parm.max_freq; | |
607 | ||
608 | f->afc_delta = 0; | |
609 | f->original_frequency = frequency; | |
610 | ||
611 | if (f->type == TUNER_TYPE_MT2032) | |
612 | MT2032_tune(f, (1.0 * frequency) / 16.0, 0.0625); | |
613 | else | |
614 | FI1236_tune(f, frequency); | |
615 | ||
616 | if (!f->afc_timer_installed) { | |
617 | f->afc_timer_installed = TRUE; | |
618 | /* RegisterBlockAndWakeupHandlers(FI1236_BlockHandler, AFCWakeup, f); */ | |
619 | TimerSet(NULL, 0, 300, AFC_TimerCallback, f); | |
620 | } | |
621 | ||
622 | } | |
623 | ||
624 | int | |
625 | FI1236_AFC(FI1236Ptr f) | |
626 | { | |
627 | #if 0 | |
628 | xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, | |
629 | "AFC: f=%p f->count=%d f->original_frequency=%d f->afc_delta=%d\n", | |
630 | f, f->afc_count, f->original_frequency, f->afc_delta); | |
631 | #endif | |
632 | f->afc_count++; | |
633 | if (f->type == TUNER_TYPE_MT2032) { | |
634 | f->last_afc_hint = MT2032_get_afc_hint(f); | |
635 | xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, | |
636 | "AFC: afc_hint=%d\n", f->last_afc_hint); | |
637 | if (f->last_afc_hint == TUNER_TUNED) | |
638 | return 0; | |
639 | if (f->afc_count > 3) | |
640 | f->last_afc_hint = TUNER_OFF; | |
641 | if (f->last_afc_hint == TUNER_OFF) | |
642 | f->afc_delta = 0; | |
643 | else | |
644 | f->afc_delta += f->last_afc_hint; | |
645 | ||
646 | xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, | |
647 | "AFC: Setting tuner frequency to %g\n", | |
648 | (0.5 * (2 * f->original_frequency + f->afc_delta)) / 16.0); | |
649 | MT2032_tune(f, | |
650 | (1.0 * f->original_frequency + 0.5 * f->afc_delta) / 16.0, | |
651 | 0.03125); | |
652 | if (f->last_afc_hint == TUNER_OFF) | |
653 | return 0; | |
654 | return 1; /* call me again */ | |
655 | } | |
656 | else { | |
657 | f->last_afc_hint = FI1236_get_afc_hint(f); | |
658 | if (f->last_afc_hint == TUNER_TUNED) { | |
659 | xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "AFC: TUNER_TUNNED\n"); | |
660 | return 0; | |
661 | } | |
662 | if (f->afc_count > 3) | |
663 | f->last_afc_hint = TUNER_OFF; | |
664 | ||
665 | if (f->last_afc_hint == TUNER_OFF) | |
666 | f->afc_delta = 0; | |
667 | else | |
668 | f->afc_delta += f->last_afc_hint; | |
669 | ||
670 | xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, | |
671 | "AFC: Setting tuner frequency to %g\n", | |
672 | (0.5 * (2 * f->original_frequency + f->afc_delta)) / 16.0); | |
673 | FI1236_tune(f, f->original_frequency + f->afc_delta); | |
674 | if (f->last_afc_hint == TUNER_OFF) | |
675 | return 0; | |
676 | return 1; /* call me again */ | |
677 | } | |
678 | return 0; /* done */ | |
679 | } | |
680 | ||
681 | void | |
682 | fi1236_dump_status(FI1236Ptr f) | |
683 | { | |
684 | if (f->type == TUNER_TYPE_MT2032) | |
685 | MT2032_dump_status(f); | |
686 | } |