xserver-multidpi/hw/xfree86/i2c/fi1236.c
Paulo Cesar Pereira de Andrade 49f77fff14 Rework symbol visibility for easier maintenance
Save in a few special cases, _X_EXPORT should not be used in C source
files. Instead, it should be used in headers, and the proper C source
include that header. Some special cases are symbols that need to be
shared between modules, but not expected to be used by external drivers,
and symbols that are accessible via LoaderSymbol/dlopen.

  This patch also adds conditionally some new sdk header files, depending
on extensions enabled. These files were added to match pattern for
other extensions/modules, that is, have the headers "deciding" symbol
visibility in the sdk. These headers are:
o Xext/panoramiXsrv.h, Xext/panoramiX.h
o fbpict.h (unconditionally)
o vidmodeproc.h
o mioverlay.h (unconditionally, used only by xaa)
o xfixes.h (unconditionally, symbols required by dri2)

  LoaderSymbol and similar functions now don't have different prototypes,
in loaderProcs.h and xf86Module.h, so that both headers can be included,
without the need of defining IN_LOADER.

  xf86NewInputDevice() device prototype readded to xf86Xinput.h, but
not exported (and with a comment about it).
2008-12-03 05:43:34 -02:00

610 lines
16 KiB
C

#ifdef HAVE_XORG_CONFIG_H
#include <xorg-config.h>
#endif
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "xf86.h"
#include "xf86i2c.h"
#include "fi1236.h"
#include "tda9885.h"
#include "i2c_def.h"
#define NUM_TUNERS 8
const FI1236_parameters tuner_parms[NUM_TUNERS] =
{
/* 0 - FI1236 */
{ 733 ,884 ,12820 ,2516 ,7220 ,0xA2 ,0x94, 0x34, 0x8e },
/* !!!based on documentation - it should be:
{733 ,16*55.25 ,16*801.25 ,16*160 ,16*454 ,0xA0 ,0x90, 0x30, 0x8e},*/
/* 1 - FI1216 */
{ 623 ,16*48.75 ,16*855.25 ,16*170 ,16*450 ,0xA0 ,0x90, 0x30, 0x8e },
/* 2 - TEMIC FN5AL */
{ 623 ,16*45.75 ,16*855.25 ,16*169 ,16*454 ,0xA0 ,0x90, 0x30, 0x8e },
/* 3 - MT2032.. */
{ 733 ,768 ,13760 , 0 , 0 , 0 , 0, 0, 0 },
/* 4 - FI1246 */
{ 623 ,16*45.75 ,16*855.25 ,16*170 ,16*450 ,0xA0 ,0x90, 0x30, 0x8e },
/* 5 - FI1256 */
{ 623 ,16*49.75 ,16*863.25 ,16*170 ,16*450 ,0xA0 ,0x90, 0x30, 0x8e },
/* 6 - FI1236W */
/*{ 733 ,884 ,12820 ,2516 ,7220 ,0x1 ,0x2, 0x4, 0x8e },*/
{ 732, 16*55.25, 16*801.25, 16*160, 16*442, 0x1, 0x2, 0x4, 0x8e },
/* 7 - FM1216ME */
{ 623 ,16*48.25 ,16*863.25 ,16*158.00 ,16*442.00 ,0x1 ,0x2, 0x4, 0x8e }
};
FI1236Ptr Detect_FI1236(I2CBusPtr b, I2CSlaveAddr addr)
{
FI1236Ptr f;
I2CByte a;
f = xcalloc(1,sizeof(FI1236Rec));
if(f == NULL) return NULL;
f->d.DevName = strdup("FI12xx Tuner");
f->d.SlaveAddr = addr;
f->d.pI2CBus = b;
f->d.NextDev = NULL;
f->d.StartTimeout = b->StartTimeout;
f->d.BitTimeout = b->BitTimeout;
f->d.AcknTimeout = b->AcknTimeout;
f->d.ByteTimeout = b->ByteTimeout;
f->type=TUNER_TYPE_FI1236;
f->afc_timer_installed=FALSE;
f->last_afc_hint=TUNER_OFF;
f->video_if=45.7812;
if(!I2C_WriteRead(&(f->d), NULL, 0, &a, 1))
{
free(f);
return NULL;
}
FI1236_set_tuner_type(f, TUNER_TYPE_FI1236);
if(!I2CDevInit(&(f->d)))
{
free(f);
return NULL;
}
return f;
}
static void MT2032_dump_parameters(FI1236Ptr f, MT2032_parameters *m)
{
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",
m->f_rf, m->f_if1, m->f_if2, m->f_ref, m->f_ifbw, m->f_step);
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",
m->f_lo1, m->f_lo2, m->LO1I, m->LO2I, m->SEL, m->STEP, m->NUM);
}
static void MT2032_getid(FI1236Ptr f)
{
CARD8 out[4];
CARD8 in;
in=0x11;
I2C_WriteRead(&(f->d), (I2CByte *)&in, 1, out, 4);
xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "MT2032: Company code 0x%02x%02x, part code 0x%02x, revision code 0x%02x\n",
out[0], out[1], out[2], out[3]);
}
/* might be buggy */
#if 0
static void MT2032_shutdown(FI1236Ptr f)
{
CARD8 data[10];
data[0]=0x00; /* start with register 0x00 */
data[1]=0x1A;
data[2]=0x44;
data[3]=0x20;
I2C_WriteRead(&(f->d), (I2CByte *)data, 4, NULL, 0);
data[0]=0x05; /* now start with register 0x05 */
data[1]=0xD7;
data[2]=0x14;
data[3]=0x05;
I2C_WriteRead(&(f->d), (I2CByte *)data, 4, NULL, 0);
data[0]=0x0B; /* now start with register 0x05 */
data[1]=0x8F;
data[2]=0x07;
data[3]=0x43;
I2C_WriteRead(&(f->d), (I2CByte *)data, 4, NULL, 0);
usleep(15000);
}
#endif
static void MT2032_dump_status(FI1236Ptr f);
static void MT2032_init(FI1236Ptr f)
{
CARD8 data[10];
CARD8 value;
CARD8 xogc = 0x00;
MT2032_getid(f);
data[0]=0x02; /* start with register 0x02 */
data[1]=0xFF;
data[2]=0x0F;
data[3]=0x1F;
I2C_WriteRead(&(f->d), (I2CByte *)data, 4, NULL, 0);
data[0]=0x06; /* now start with register 0x06 */
data[1]=0xE4;
data[2]=0x8F;
data[3]=0xC3;
data[4]=0x4E;
data[5]=0xEC;
I2C_WriteRead(&(f->d), (I2CByte *)data, 6, NULL, 0);
data[0]=0x0d; /* now start with register 0x0d */
data[1]=0x32;
I2C_WriteRead(&(f->d), (I2CByte *)data, 2, NULL, 0);
while(1) {
usleep(15000); /* wait 15 milliseconds */
data[0]=0x0e; /* register number 7, status */
value=0xFF;
if(!I2C_WriteRead(&(f->d), (I2CByte *)data, 1, &value, 1))
xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "MT2032: failed to read XOK\n");
xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "MT2032: XOK=%d\n", value & 0x01);
if(value & 1) break;
data[0]=0x07;
if(!I2C_WriteRead(&(f->d), (I2CByte *)data, 1, &value, 1))
xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "MT2032: failed to read XOGC\n");
xogc=value & 0x7;
if(xogc==4){
break; /* XOGC has reached 4.. stop */
}
xogc--;
xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "MT2032: try XOGC=%d\n", xogc);
usleep(15000);
data[0]=0x07; /* register number 7, control byte 2 */
data[1]=0x08 | xogc;
I2C_WriteRead(&(f->d), (I2CByte *)data, 2, NULL, 0);
}
f->xogc=xogc;
/* wait before continuing */
usleep(15000); /* wait 50 milliseconds */
MT2032_dump_status(f);
}
static int MT2032_no_spur_in_band(MT2032_parameters *m)
{
int n_max, n1, n2;
double f_test;
n_max=5;
n1=1;
while(1){
n2=-n1;
f_test=n1*(m->f_lo1-m->f_lo2);
while(1){
n2--;
f_test=f_test-m->f_lo2;
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);
xf86DrvMsg(0, X_INFO, "d_f=%g f_ifbw=%g\n",fabs(fabs(f_test)-m->f_if2), m->f_ifbw);
if((fabs(fabs(f_test)-m->f_if2)*2.0)<=m->f_ifbw)return 0;
if(n2<=-n_max)break;
/* this line in the manual is bogus. I say it is faster
and more correct to go over all harmonics.. */
#if 0
if(f_test<(m->f_lo2-m->f_if2-m->f_ifbw))break;
#endif
}
n1++;
if(n1>=n_max)return 1;
}
}
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)
{
int n;
m->f_rf=f_rf;
m->f_if1=f_if1;
m->f_if2=f_if2;
m->f_ref=f_ref;
m->f_ifbw=f_ifbw;
m->f_step=f_step;
m->f_lo1=f_rf+f_if1;
m->LO1I=(int)floor((m->f_lo1/f_ref)+0.5);
m->f_lo1=f_ref*m->LO1I;
m->f_lo2=m->f_lo1-f_rf-f_if2;
/* check for spurs */
n=1;
while(n<3){
if(MT2032_no_spur_in_band(m))break;
if(m->f_lo1<(f_rf+f_if1)){
m->LO1I+=n;
} else {
m->LO1I-=n;
}
m->f_lo1=m->LO1I*f_ref;
m->f_lo2=m->f_lo1-f_rf-f_if2;
n++;
}
/* xf86DrvMsg(0, X_INFO, "MT2032: n=%d\n", n); */
/* select VCO */
/* m->f_lo1>1100.0 */
if(m->f_lo1<1370.0)m->SEL=4;
else
if(m->f_lo1<1530.0)m->SEL=3;
else
if(m->f_lo1<1720.0)m->SEL=2;
else
if(m->f_lo1<1890.0)m->SEL=1;
else /* m->f_lo1 < 1958.0 */
m->SEL=0;
/* calculate the rest of the registers */
m->LO2I=(int)floor(m->f_lo2/f_ref);
m->STEP=(int)floor(3780.0*f_step/f_ref);
m->NUM=(int)floor(3780.0*(m->f_lo2/f_ref-m->LO2I));
m->NUM=m->STEP*(int)floor((1.0*m->NUM)/(1.0*m->STEP)+0.5);
}
static int MT2032_wait_for_lock(FI1236Ptr f)
{
int n;
CARD8 data[10];
CARD8 value;
n=12;
while(1){
data[0]=0x0e; /* register number 7, status */
I2C_WriteRead(&(f->d), (I2CByte *)data, 1, &value, 1);
/* xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "MT2032: LO1LK=%d LO2LK=%d\n", (value & 0x04)>>2, (value & 0x02)>>1); */
if((value & 6)==6) break;
usleep(1500);
n--;
if(n<0)break;
}
if(n<0){
xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "MT2032: failed to set frequency\n");
return 0;
}
return 1;
}
static void MT2032_implement_settings(FI1236Ptr f, MT2032_parameters *m)
{
CARD8 data[10];
CARD8 value;
data[0]=0x00; /* start with register 0x00 */
data[1]=(m->LO1I>>3)-1;
data[2]=(m->SEL<<4)|(m->LO1I & 0x7);
data[3]=0x86;
I2C_WriteRead(&(f->d), (I2CByte *)data, 4, NULL, 0);
data[0]=0x05; /* start with register 0x05 */
data[1]=((m->LO2I & 0x7)<<5)|((m->LO2I>>3)-1);
if(m->f_rf<400.0)data[2]=0xe4;
else data[2]=0xf4;
I2C_WriteRead(&(f->d), (I2CByte *)data, 3, NULL, 0);
data[0]=0x07; /* register number 7, control byte 2 */
I2C_WriteRead(&(f->d), (I2CByte *)data, 1, &value, 1);
xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "MT2032: using XOGC=%d\n", (value & 0x07));
data[1]=8 | (value & 0x7);
I2C_WriteRead(&(f->d), (I2CByte *)data, 2, NULL, 0);
data[0]=0x0b; /* start with register 0x0b */
data[1]=m->NUM & 0xff;
data[2]=(1<<7)|((m->NUM >> 8) & 0x0f);
I2C_WriteRead(&(f->d), (I2CByte *)data, 3, NULL, 0);
MT2032_wait_for_lock(f);
}
static void MT2032_optimize_VCO(FI1236Ptr f, MT2032_parameters *m)
{
CARD8 data[10];
CARD8 value;
CARD8 TAD1;
data[0]=0x0f; /* register number 7, status */
I2C_WriteRead(&(f->d), (I2CByte *)data, 1, &value, 1);
TAD1=value & 0x07;
xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "MT2032: TAD1=%d SEL=%d\n", TAD1, m->SEL);
if(TAD1 < 2)return;
if(TAD1==2){
if(m->SEL==0)return;
m->SEL--;
} else {
if(m->SEL>=4)return;
m->SEL++;
}
data[0]=0x01; /* start with register 1 */
data[1]=(m->SEL<<4)|(m->LO1I & 0x7);
I2C_WriteRead(&(f->d), (I2CByte *)data, 2, NULL, 0);
}
static int FI1236_get_afc_hint(FI1236Ptr f)
{
CARD8 out;
CARD8 AFC;
if ((f->type == TUNER_TYPE_FM1216ME) || (f->type == TUNER_TYPE_FI1236W))
{
TDA9885Ptr t = (TDA9885Ptr)f->afc_source;
if (t == NULL)
return TUNER_OFF;
tda9885_getstatus(t);
tda9885_dumpstatus(t);
AFC = t->afc_status & 0x0f;
xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "AFC: FI1236_get_afc_hint: %i\n", AFC);
if (AFC == 0) return TUNER_TUNED;
else if (AFC <= 0x07)return TUNER_JUST_BELOW;
else if (AFC < 0x0f )return TUNER_JUST_ABOVE;
else if (AFC == 0x0f)return TUNER_TUNED;
}
else
{
I2C_WriteRead(&(f->d), NULL, 0, &out, 1);
AFC=out & 0x7;
xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "AFC: FI1236_get_afc_hint: %i\n", AFC);
if(AFC==2)return TUNER_TUNED;
if(AFC==3)return TUNER_JUST_BELOW;
if(AFC==1)return TUNER_JUST_ABOVE;
return TUNER_OFF;
}
return TUNER_OFF;
}
static int MT2032_get_afc_hint(FI1236Ptr f)
{
CARD8 in;
CARD8 out[2];
CARD8 AFC;
in=0x0e;
I2C_WriteRead(&(f->d), (I2CByte *)&in, 1, out, 2);
AFC=(out[0]>>4) & 0x7;
#if 0
xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "AFC=%d TAD1=%d TAD2=%d\n", AFC, out[1] & 0x7, (out[1]>>4)& 0x07);
#endif
if(AFC==2)return TUNER_TUNED;
if(AFC==3)return TUNER_JUST_BELOW;
if(AFC==1)return TUNER_JUST_ABOVE;
return TUNER_OFF;
}
/* this function is for external use only */
int TUNER_get_afc_hint(FI1236Ptr f)
{
if(f->afc_timer_installed)return TUNER_STILL_TUNING;
return f->last_afc_hint;
if(f->type==TUNER_TYPE_MT2032)
return MT2032_get_afc_hint(f);
else
return FI1236_get_afc_hint(f);
}
static void MT2032_dump_status(FI1236Ptr f)
{
CARD8 in;
CARD8 out[2];
CARD8 AFC;
CARD8 LDONrb;
CARD8 LO1LK, LO2LK, XOK;
CARD8 TAD2, TAD1;
in=0x0e;
I2C_WriteRead(&(f->d), (I2CByte *)&in, 1, out, 2);
XOK=out[0] & 1;
LO1LK=(out[0]>>2) &1;
LO2LK=(out[0]>>1) &1;
LDONrb=(out[0]>>3) &1;
AFC=(out[0]>>4) & 0x7;
TAD1=(out[1] & 0x7);
TAD2=(out[1]>>4) & 0x7;
xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "MT2032: status: XOK=%d LO1LK=%d LO2LK=%d LDONrb=%d AFC=%d TAD1=%d TAD2=%d\n",
XOK, LO1LK, LO2LK, LDONrb, AFC, TAD1, TAD2);
xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "MT2032: status: OSCILLATOR:%s PLL1:%s PLL2:%s\n",
XOK ? "ok":"off", LO1LK ? "locked" : "off" , LO2LK ? "locked" : "off");
}
static void MT2032_tune(FI1236Ptr f, double freq, double step)
{
MT2032_parameters m;
CARD8 data[10];
int i;
/* NTSC IF is 44mhz.. but 733/16=45.8125 and all TDAXXXX docs mention
45.75, 39, 58.75 and 30. */
#if 0
MT2032_calculate_register_settings(&m, freq, 1090.0, 45.125, 5.25, 6.0, step);
MT2032_calculate_register_settings(&m, freq, 1090.0, 45.74, 5.25, 6.0, step);
#endif
MT2032_calculate_register_settings(&m, freq, 1090.0, f->video_if, 5.25, 3.0, step);
MT2032_dump_parameters(f, &m);
MT2032_implement_settings(f, &m);
/* MT2032_dump_parameters(f, &m); */
for(i=0;i<3;i++){
MT2032_optimize_VCO(f, &m);
if(MT2032_wait_for_lock(f)){
data[0]=0x02; /* LO Gain control register 0x02 */
data[1]=0x20;
I2C_WriteRead(&(f->d), (I2CByte *)data, 2, NULL, 0);
return;
}
data[0]=0x07;
data[1]=0x88|f->xogc;
I2C_WriteRead(&(f->d), (I2CByte *)data, 2, NULL, 0);
usleep(15000);
data[1]=0x08|f->xogc;
I2C_WriteRead(&(f->d), (I2CByte *)data, 2, NULL, 0);
}
xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "MT2032: failed to set frequency\n");
}
void FI1236_set_tuner_type(FI1236Ptr f, int type)
{
f->type=type;
if(type>=NUM_TUNERS)type = NUM_TUNERS-1;
if(type<0)type = 0;
memcpy(&(f->parm), &(tuner_parms[type]), sizeof(FI1236_parameters));
f->original_frequency=f->parm.min_freq;
f->afc_delta=0;
if(type==TUNER_TYPE_MT2032){
MT2032_init(f);
return;
}
}
static CARD32 AFC_TimerCallback(OsTimerPtr timer, CARD32 time, pointer data){
FI1236Ptr f=(FI1236Ptr)data;
if(FI1236_AFC(f))return 150;
else {
f->afc_timer_installed=FALSE;
f->afc_count=0;
return 0;
}
}
void FI1236_tune(FI1236Ptr f, CARD32 frequency)
{
CARD16 divider;
CARD8 data;
if(frequency < f->parm.min_freq) frequency = f->parm.min_freq;
if(frequency > f->parm.max_freq) frequency = f->parm.max_freq;
divider = (f->parm.fcar+(CARD16)frequency) & 0x7fff;
f->tuner_data.div1 = (CARD8)((divider>>8)&0x7f);
f->tuner_data.div2 = (CARD8)(divider & 0xff);
f->tuner_data.control = f->parm.control;
if(frequency < f->parm.threshold1)
{
f->tuner_data.band = f->parm.band_low;
}
else if (frequency < f->parm.threshold2)
{
f->tuner_data.band = f->parm.band_mid;
}
else
{
f->tuner_data.band = f->parm.band_high;
}
xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "Setting tuner band to %d\n", f->tuner_data.band);
xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "Setting tuner frequency to %d\n", (int)frequency);
if ((f->type == TUNER_TYPE_FM1216ME) || (f->type == TUNER_TYPE_FI1236W))
{
f->tuner_data.aux = 0x20;
I2C_WriteRead(&(f->d), (I2CByte *)&(f->tuner_data), 5, NULL, 0);
I2C_WriteRead(&(f->d), NULL, 0, &data, 1);
xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "Tuner status %x\n", data);
}
else
I2C_WriteRead(&(f->d), (I2CByte *)&(f->tuner_data), 4, NULL, 0);
}
void TUNER_set_frequency(FI1236Ptr f, CARD32 frequency)
{
if(frequency < f->parm.min_freq) frequency = f->parm.min_freq;
if(frequency > f->parm.max_freq) frequency = f->parm.max_freq;
f->afc_delta=0;
f->original_frequency=frequency;
if(f->type==TUNER_TYPE_MT2032)
{
MT2032_tune(f, (1.0*frequency)/16.0, 0.0625);
} else
{
FI1236_tune(f, frequency);
}
if(!f->afc_timer_installed)
{
f->afc_timer_installed=TRUE;
/* RegisterBlockAndWakeupHandlers(FI1236_BlockHandler, AFCWakeup, f); */
TimerSet(NULL, 0, 300, AFC_TimerCallback, f);
}
}
int FI1236_AFC(FI1236Ptr f)
{
#if 0
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);
#endif
f->afc_count++;
if(f->type==TUNER_TYPE_MT2032)
{
f->last_afc_hint=MT2032_get_afc_hint(f);
xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "AFC: afc_hint=%d\n", f->last_afc_hint);
if(f->last_afc_hint==TUNER_TUNED)return 0;
if(f->afc_count>3)f->last_afc_hint=TUNER_OFF;
if(f->last_afc_hint==TUNER_OFF)
{
f->afc_delta=0;
} else
f->afc_delta+=f->last_afc_hint;
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);
MT2032_tune(f, (1.0*f->original_frequency+0.5*f->afc_delta)/16.0, 0.03125);
if(f->last_afc_hint==TUNER_OFF)return 0;
return 1; /* call me again */
} else
{
f->last_afc_hint=FI1236_get_afc_hint(f);
if(f->last_afc_hint==TUNER_TUNED)
{
xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "AFC: TUNER_TUNNED\n");
return 0;
}
if(f->afc_count>3)f->last_afc_hint=TUNER_OFF;
if(f->last_afc_hint==TUNER_OFF)
{
f->afc_delta=0;
} else
f->afc_delta+=f->last_afc_hint;
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);
FI1236_tune(f, f->original_frequency+f->afc_delta);
if(f->last_afc_hint==TUNER_OFF)return 0;
return 1; /* call me again */
}
return 0; /* done */
}
void fi1236_dump_status(FI1236Ptr f)
{
if(f->type==TUNER_TYPE_MT2032){
MT2032_dump_status(f);
}
}