2 #ifdef HAVE_XORG_CONFIG_H
3 #include <xorg-config.h>
19 const FI1236_parameters tuner_parms
[NUM_TUNERS
] =
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},*/
27 { 623 ,16*48.75 ,16*855.25 ,16*170 ,16*450 ,0xA0 ,0x90, 0x30, 0x8e },
29 { 623 ,16*45.75 ,16*855.25 ,16*169 ,16*454 ,0xA0 ,0x90, 0x30, 0x8e },
31 { 733 ,768 ,13760 , 0 , 0 , 0 , 0, 0, 0 },
33 { 623 ,16*45.75 ,16*855.25 ,16*170 ,16*450 ,0xA0 ,0x90, 0x30, 0x8e },
35 { 623 ,16*49.75 ,16*863.25 ,16*170 ,16*450 ,0xA0 ,0x90, 0x30, 0x8e },
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 },
40 { 623 ,16*48.25 ,16*863.25 ,16*158.00 ,16*442.00 ,0x1 ,0x2, 0x4, 0x8e }
44 FI1236Ptr
Detect_FI1236(I2CBusPtr b
, I2CSlaveAddr addr
)
49 f
= xcalloc(1,sizeof(FI1236Rec
));
50 if(f
== NULL
) return NULL
;
51 f
->d
.DevName
= strdup("FI12xx Tuner");
52 f
->d
.SlaveAddr
= addr
;
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
;
64 if(!I2C_WriteRead(&(f
->d
), NULL
, 0, &a
, 1))
69 FI1236_set_tuner_type(f
, TUNER_TYPE_FI1236
);
70 if(!I2CDevInit(&(f
->d
)))
78 static void MT2032_dump_parameters(FI1236Ptr f
, MT2032_parameters
*m
)
80 xf86DrvMsg(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
);
83 xf86DrvMsg(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
);
88 static void MT2032_getid(FI1236Ptr f
)
94 I2C_WriteRead(&(f
->d
), (I2CByte
*)&in
, 1, out
, 4);
95 xf86DrvMsg(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]);
102 static void MT2032_shutdown(FI1236Ptr f
)
106 data
[0]=0x00; /* start with register 0x00 */
111 I2C_WriteRead(&(f
->d
), (I2CByte
*)data
, 4, NULL
, 0);
113 data
[0]=0x05; /* now start with register 0x05 */
117 I2C_WriteRead(&(f
->d
), (I2CByte
*)data
, 4, NULL
, 0);
119 data
[0]=0x0B; /* now start with register 0x05 */
123 I2C_WriteRead(&(f
->d
), (I2CByte
*)data
, 4, NULL
, 0);
129 static void MT2032_dump_status(FI1236Ptr f
);
131 static void MT2032_init(FI1236Ptr f
)
139 data
[0]=0x02; /* start with register 0x02 */
144 I2C_WriteRead(&(f
->d
), (I2CByte
*)data
, 4, NULL
, 0);
146 data
[0]=0x06; /* now start with register 0x06 */
152 I2C_WriteRead(&(f
->d
), (I2CByte
*)data
, 6, NULL
, 0);
154 data
[0]=0x0d; /* now start with register 0x0d */
156 I2C_WriteRead(&(f
->d
), (I2CByte
*)data
, 2, NULL
, 0);
159 usleep(15000); /* wait 15 milliseconds */
161 data
[0]=0x0e; /* register number 7, status */
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);
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");
174 break; /* XOGC has reached 4.. stop */
177 xf86DrvMsg(f
->d
.pI2CBus
->scrnIndex
, X_INFO
, "MT2032: try XOGC=%d\n", xogc
);
179 data
[0]=0x07; /* register number 7, control byte 2 */
181 I2C_WriteRead(&(f
->d
), (I2CByte
*)data
, 2, NULL
, 0);
184 /* wait before continuing */
185 usleep(15000); /* wait 50 milliseconds */
186 MT2032_dump_status(f
);
189 static int MT2032_no_spur_in_band(MT2032_parameters
*m
)
197 f_test
=n1
*(m
->f_lo1
-m
->f_lo2
);
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;
205 /* this line in the manual is bogus. I say it is faster
206 and more correct to go over all harmonics.. */
208 if(f_test
<(m
->f_lo2
-m
->f_if2
-m
->f_ifbw
))break;
212 if(n1
>=n_max
)return 1;
217 static 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
)
228 m
->LO1I
=(int)floor((m
->f_lo1
/f_ref
)+0.5);
229 m
->f_lo1
=f_ref
*m
->LO1I
;
231 m
->f_lo2
=m
->f_lo1
-f_rf
-f_if2
;
233 /* check for spurs */
236 if(MT2032_no_spur_in_band(m
))break;
237 if(m
->f_lo1
<(f_rf
+f_if1
)){
242 m
->f_lo1
=m
->LO1I
*f_ref
;
243 m
->f_lo2
=m
->f_lo1
-f_rf
-f_if2
;
246 /* xf86DrvMsg(0, X_INFO, "MT2032: n=%d\n", n); */
249 /* m->f_lo1>1100.0 */
250 if(m
->f_lo1
<1370.0)m
->SEL
=4;
252 if(m
->f_lo1
<1530.0)m
->SEL
=3;
254 if(m
->f_lo1
<1720.0)m
->SEL
=2;
256 if(m
->f_lo1
<1890.0)m
->SEL
=1;
257 else /* m->f_lo1 < 1958.0 */
260 /* calculate the rest of the registers */
261 m
->LO2I
=(int)floor(m
->f_lo2
/f_ref
);
262 m
->STEP
=(int)floor(3780.0*f_step
/f_ref
);
263 m
->NUM
=(int)floor(3780.0*(m
->f_lo2
/f_ref
-m
->LO2I
));
264 m
->NUM
=m
->STEP
*(int)floor((1.0*m
->NUM
)/(1.0*m
->STEP
)+0.5);
267 static int MT2032_wait_for_lock(FI1236Ptr f
)
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;
284 xf86DrvMsg(f
->d
.pI2CBus
->scrnIndex
, X_INFO
, "MT2032: failed to set frequency\n");
290 static void MT2032_implement_settings(FI1236Ptr f
, MT2032_parameters
*m
)
295 data
[0]=0x00; /* start with register 0x00 */
296 data
[1]=(m
->LO1I
>>3)-1;
297 data
[2]=(m
->SEL
<<4)|(m
->LO1I
& 0x7);
299 I2C_WriteRead(&(f
->d
), (I2CByte
*)data
, 4, NULL
, 0);
301 data
[0]=0x05; /* start with register 0x05 */
302 data
[1]=((m
->LO2I
& 0x7)<<5)|((m
->LO2I
>>3)-1);
303 if(m
->f_rf
<400.0)data
[2]=0xe4;
305 I2C_WriteRead(&(f
->d
), (I2CByte
*)data
, 3, NULL
, 0);
307 data
[0]=0x07; /* register number 7, control byte 2 */
308 I2C_WriteRead(&(f
->d
), (I2CByte
*)data
, 1, &value
, 1);
309 xf86DrvMsg(f
->d
.pI2CBus
->scrnIndex
, X_INFO
, "MT2032: using XOGC=%d\n", (value
& 0x07));
310 data
[1]=8 | (value
& 0x7);
311 I2C_WriteRead(&(f
->d
), (I2CByte
*)data
, 2, NULL
, 0);
313 data
[0]=0x0b; /* start with register 0x0b */
314 data
[1]=m
->NUM
& 0xff;
315 data
[2]=(1<<7)|((m
->NUM
>> 8) & 0x0f);
316 I2C_WriteRead(&(f
->d
), (I2CByte
*)data
, 3, NULL
, 0);
318 MT2032_wait_for_lock(f
);
321 static void MT2032_optimize_VCO(FI1236Ptr f
, MT2032_parameters
*m
)
327 data
[0]=0x0f; /* register number 7, status */
328 I2C_WriteRead(&(f
->d
), (I2CByte
*)data
, 1, &value
, 1);
330 xf86DrvMsg(f
->d
.pI2CBus
->scrnIndex
, X_INFO
, "MT2032: TAD1=%d SEL=%d\n", TAD1
, m
->SEL
);
339 data
[0]=0x01; /* start with register 1 */
340 data
[1]=(m
->SEL
<<4)|(m
->LO1I
& 0x7);
341 I2C_WriteRead(&(f
->d
), (I2CByte
*)data
, 2, NULL
, 0);
345 static int FI1236_get_afc_hint(FI1236Ptr f
)
350 if ((f
->type
== TUNER_TYPE_FM1216ME
) || (f
->type
== TUNER_TYPE_FI1236W
))
352 TDA9885Ptr t
= (TDA9885Ptr
)f
->afc_source
;
356 tda9885_getstatus(t
);
357 tda9885_dumpstatus(t
);
358 AFC
= t
->afc_status
& 0x0f;
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
;
368 I2C_WriteRead(&(f
->d
), NULL
, 0, &out
, 1);
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
;
379 static int MT2032_get_afc_hint(FI1236Ptr f
)
385 I2C_WriteRead(&(f
->d
), (I2CByte
*)&in
, 1, out
, 2);
386 AFC
=(out
[0]>>4) & 0x7;
388 xf86DrvMsg(f
->d
.pI2CBus
->scrnIndex
, X_INFO
, "AFC=%d TAD1=%d TAD2=%d\n", AFC
, out
[1] & 0x7, (out
[1]>>4)& 0x07);
390 if(AFC
==2)return TUNER_TUNED
;
391 if(AFC
==3)return TUNER_JUST_BELOW
;
392 if(AFC
==1)return TUNER_JUST_ABOVE
;
396 /* this function is for external use only */
397 int TUNER_get_afc_hint(FI1236Ptr f
)
399 if(f
->afc_timer_installed
)return TUNER_STILL_TUNING
;
400 return f
->last_afc_hint
;
401 if(f
->type
==TUNER_TYPE_MT2032
)
402 return MT2032_get_afc_hint(f
);
404 return FI1236_get_afc_hint(f
);
407 static void MT2032_dump_status(FI1236Ptr f
)
413 CARD8 LO1LK
, LO2LK
, XOK
;
417 I2C_WriteRead(&(f
->d
), (I2CByte
*)&in
, 1, out
, 2);
419 LO1LK
=(out
[0]>>2) &1;
420 LO2LK
=(out
[0]>>1) &1;
421 LDONrb
=(out
[0]>>3) &1;
423 AFC
=(out
[0]>>4) & 0x7;
426 TAD2
=(out
[1]>>4) & 0x7;
428 xf86DrvMsg(f
->d
.pI2CBus
->scrnIndex
, X_INFO
, "MT2032: status: XOK=%d LO1LK=%d LO2LK=%d LDONrb=%d AFC=%d TAD1=%d TAD2=%d\n",
429 XOK
, LO1LK
, LO2LK
, LDONrb
, AFC
, TAD1
, TAD2
);
430 xf86DrvMsg(f
->d
.pI2CBus
->scrnIndex
, X_INFO
, "MT2032: status: OSCILLATOR:%s PLL1:%s PLL2:%s\n",
431 XOK
? "ok":"off", LO1LK
? "locked" : "off" , LO2LK
? "locked" : "off");
435 static void MT2032_tune(FI1236Ptr f
, double freq
, double step
)
440 /* NTSC IF is 44mhz.. but 733/16=45.8125 and all TDAXXXX docs mention
441 45.75, 39, 58.75 and 30. */
443 MT2032_calculate_register_settings(&m
, freq
, 1090.0, 45.125, 5.25, 6.0, step
);
444 MT2032_calculate_register_settings(&m
, freq
, 1090.0, 45.74, 5.25, 6.0, step
);
446 MT2032_calculate_register_settings(&m
, freq
, 1090.0, f
->video_if
, 5.25, 3.0, step
);
447 MT2032_dump_parameters(f
, &m
);
448 MT2032_implement_settings(f
, &m
);
449 /* MT2032_dump_parameters(f, &m); */
451 MT2032_optimize_VCO(f
, &m
);
452 if(MT2032_wait_for_lock(f
)){
453 data
[0]=0x02; /* LO Gain control register 0x02 */
455 I2C_WriteRead(&(f
->d
), (I2CByte
*)data
, 2, NULL
, 0);
459 data
[1]=0x88|f
->xogc
;
460 I2C_WriteRead(&(f
->d
), (I2CByte
*)data
, 2, NULL
, 0);
462 data
[1]=0x08|f
->xogc
;
463 I2C_WriteRead(&(f
->d
), (I2CByte
*)data
, 2, NULL
, 0);
465 xf86DrvMsg(f
->d
.pI2CBus
->scrnIndex
, X_INFO
, "MT2032: failed to set frequency\n");
468 void FI1236_set_tuner_type(FI1236Ptr f
, int type
)
471 if(type
>=NUM_TUNERS
)type
= NUM_TUNERS
-1;
473 memcpy(&(f
->parm
), &(tuner_parms
[type
]), sizeof(FI1236_parameters
));
474 f
->original_frequency
=f
->parm
.min_freq
;
476 if(type
==TUNER_TYPE_MT2032
){
483 static CARD32
AFC_TimerCallback(OsTimerPtr timer
, CARD32 time
, pointer data
){
484 FI1236Ptr f
=(FI1236Ptr
)data
;
485 if(FI1236_AFC(f
))return 150;
487 f
->afc_timer_installed
=FALSE
;
493 void FI1236_tune(FI1236Ptr f
, CARD32 frequency
)
498 if(frequency
< f
->parm
.min_freq
) frequency
= f
->parm
.min_freq
;
499 if(frequency
> f
->parm
.max_freq
) frequency
= f
->parm
.max_freq
;
501 divider
= (f
->parm
.fcar
+(CARD16
)frequency
) & 0x7fff;
502 f
->tuner_data
.div1
= (CARD8
)((divider
>>8)&0x7f);
503 f
->tuner_data
.div2
= (CARD8
)(divider
& 0xff);
504 f
->tuner_data
.control
= f
->parm
.control
;
506 if(frequency
< f
->parm
.threshold1
)
508 f
->tuner_data
.band
= f
->parm
.band_low
;
510 else if (frequency
< f
->parm
.threshold2
)
512 f
->tuner_data
.band
= f
->parm
.band_mid
;
516 f
->tuner_data
.band
= f
->parm
.band_high
;
519 xf86DrvMsg(f
->d
.pI2CBus
->scrnIndex
, X_INFO
, "Setting tuner band to %d\n", f
->tuner_data
.band
);
521 xf86DrvMsg(f
->d
.pI2CBus
->scrnIndex
, X_INFO
, "Setting tuner frequency to %d\n", (int)frequency
);
523 if ((f
->type
== TUNER_TYPE_FM1216ME
) || (f
->type
== TUNER_TYPE_FI1236W
))
525 f
->tuner_data
.aux
= 0x20;
526 I2C_WriteRead(&(f
->d
), (I2CByte
*)&(f
->tuner_data
), 5, NULL
, 0);
527 I2C_WriteRead(&(f
->d
), NULL
, 0, &data
, 1);
528 xf86DrvMsg(f
->d
.pI2CBus
->scrnIndex
, X_INFO
, "Tuner status %x\n", data
);
532 I2C_WriteRead(&(f
->d
), (I2CByte
*)&(f
->tuner_data
), 4, NULL
, 0);
535 void TUNER_set_frequency(FI1236Ptr f
, CARD32 frequency
)
537 if(frequency
< f
->parm
.min_freq
) frequency
= f
->parm
.min_freq
;
538 if(frequency
> f
->parm
.max_freq
) frequency
= f
->parm
.max_freq
;
541 f
->original_frequency
=frequency
;
543 if(f
->type
==TUNER_TYPE_MT2032
)
545 MT2032_tune(f
, (1.0*frequency
)/16.0, 0.0625);
548 FI1236_tune(f
, frequency
);
551 if(!f
->afc_timer_installed
)
553 f
->afc_timer_installed
=TRUE
;
554 /* RegisterBlockAndWakeupHandlers(FI1236_BlockHandler, AFCWakeup, f); */
555 TimerSet(NULL
, 0, 300, AFC_TimerCallback
, f
);
561 int FI1236_AFC(FI1236Ptr f
)
564 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
);
567 if(f
->type
==TUNER_TYPE_MT2032
)
569 f
->last_afc_hint
=MT2032_get_afc_hint(f
);
570 xf86DrvMsg(f
->d
.pI2CBus
->scrnIndex
, X_INFO
, "AFC: afc_hint=%d\n", f
->last_afc_hint
);
571 if(f
->last_afc_hint
==TUNER_TUNED
)return 0;
572 if(f
->afc_count
>3)f
->last_afc_hint
=TUNER_OFF
;
573 if(f
->last_afc_hint
==TUNER_OFF
)
577 f
->afc_delta
+=f
->last_afc_hint
;
578 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);
579 MT2032_tune(f
, (1.0*f
->original_frequency
+0.5*f
->afc_delta
)/16.0, 0.03125);
580 if(f
->last_afc_hint
==TUNER_OFF
)return 0;
581 return 1; /* call me again */
584 f
->last_afc_hint
=FI1236_get_afc_hint(f
);
585 if(f
->last_afc_hint
==TUNER_TUNED
)
587 xf86DrvMsg(f
->d
.pI2CBus
->scrnIndex
, X_INFO
, "AFC: TUNER_TUNNED\n");
590 if(f
->afc_count
>3)f
->last_afc_hint
=TUNER_OFF
;
591 if(f
->last_afc_hint
==TUNER_OFF
)
595 f
->afc_delta
+=f
->last_afc_hint
;
596 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);
597 FI1236_tune(f
, f
->original_frequency
+f
->afc_delta
);
598 if(f
->last_afc_hint
==TUNER_OFF
)return 0;
599 return 1; /* call me again */
604 void fi1236_dump_status(FI1236Ptr f
)
606 if(f
->type
==TUNER_TYPE_MT2032
){
607 MT2032_dump_status(f
);