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