📄 mt20xx.c
字号:
// per Manual for FM tuning: first if center freq. 1085 MHz mt2032_set_if_freq(fe, params->frequency * 125 / 2, 1085*1000*1000,if2,if2,if2); return 0;}static int mt2032_set_params(struct dvb_frontend *fe, struct analog_parameters *params){ struct microtune_priv *priv = fe->tuner_priv; int ret = -EINVAL; switch (params->mode) { case V4L2_TUNER_RADIO: ret = mt2032_set_radio_freq(fe, params); priv->frequency = params->frequency * 125 / 2; break; case V4L2_TUNER_ANALOG_TV: case V4L2_TUNER_DIGITAL_TV: ret = mt2032_set_tv_freq(fe, params); priv->frequency = params->frequency * 62500; break; } return ret;}static struct dvb_tuner_ops mt2032_tuner_ops = { .set_analog_params = mt2032_set_params, .release = microtune_release, .get_frequency = microtune_get_frequency,};// Initalization as described in "MT203x Programming Procedures", Rev 1.2, Feb.2001static int mt2032_init(struct dvb_frontend *fe){ struct microtune_priv *priv = fe->tuner_priv; unsigned char buf[21]; int ret,xogc,xok=0; // Initialize Registers per spec. buf[1]=2; // Index to register 2 buf[2]=0xff; buf[3]=0x0f; buf[4]=0x1f; ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+1,4); buf[5]=6; // Index register 6 buf[6]=0xe4; buf[7]=0x8f; buf[8]=0xc3; buf[9]=0x4e; buf[10]=0xec; ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+5,6); buf[12]=13; // Index register 13 buf[13]=0x32; ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+12,2); // Adjust XOGC (register 7), wait for XOK xogc=7; do { tuner_dbg("mt2032: xogc = 0x%02x\n",xogc&0x07); mdelay(10); buf[0]=0x0e; tuner_i2c_xfer_send(&priv->i2c_props,buf,1); tuner_i2c_xfer_recv(&priv->i2c_props,buf,1); xok=buf[0]&0x01; tuner_dbg("mt2032: xok = 0x%02x\n",xok); if (xok == 1) break; xogc--; tuner_dbg("mt2032: xogc = 0x%02x\n",xogc&0x07); if (xogc == 3) { xogc=4; // min. 4 per spec break; } buf[0]=0x07; buf[1]=0x88 + xogc; ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); if (ret!=2) tuner_warn("i2c i/o error: rc == %d (should be 2)\n",ret); } while (xok != 1 ); priv->xogc=xogc; memcpy(&fe->ops.tuner_ops, &mt2032_tuner_ops, sizeof(struct dvb_tuner_ops)); return(1);}static void mt2050_set_antenna(struct dvb_frontend *fe, unsigned char antenna){ struct microtune_priv *priv = fe->tuner_priv; unsigned char buf[2]; int ret; buf[0] = 6; buf[1] = antenna ? 0x11 : 0x10; ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); tuner_dbg("mt2050: enabled antenna connector %d\n", antenna);}static void mt2050_set_if_freq(struct dvb_frontend *fe,unsigned int freq, unsigned int if2){ struct microtune_priv *priv = fe->tuner_priv; unsigned int if1=1218*1000*1000; unsigned int f_lo1,f_lo2,lo1,lo2,f_lo1_modulo,f_lo2_modulo,num1,num2,div1a,div1b,div2a,div2b; int ret; unsigned char buf[6]; tuner_dbg("mt2050_set_if_freq freq=%d if1=%d if2=%d\n", freq,if1,if2); f_lo1=freq+if1; f_lo1=(f_lo1/1000000)*1000000; f_lo2=f_lo1-freq-if2; f_lo2=(f_lo2/50000)*50000; lo1=f_lo1/4000000; lo2=f_lo2/4000000; f_lo1_modulo= f_lo1-(lo1*4000000); f_lo2_modulo= f_lo2-(lo2*4000000); num1=4*f_lo1_modulo/4000000; num2=4096*(f_lo2_modulo/1000)/4000; // todo spurchecks div1a=(lo1/12)-1; div1b=lo1-(div1a+1)*12; div2a=(lo2/8)-1; div2b=lo2-(div2a+1)*8; if (debug > 1) { tuner_dbg("lo1 lo2 = %d %d\n", lo1, lo2); tuner_dbg("num1 num2 div1a div1b div2a div2b= %x %x %x %x %x %x\n", num1,num2,div1a,div1b,div2a,div2b); } buf[0]=1; buf[1]= 4*div1b + num1; if(freq<275*1000*1000) buf[1] = buf[1]|0x80; buf[2]=div1a; buf[3]=32*div2b + num2/256; buf[4]=num2-(num2/256)*256; buf[5]=div2a; if(num2!=0) buf[5]=buf[5]|0x40; if (debug > 1) { int i; tuner_dbg("bufs is: "); for(i=0;i<6;i++) printk("%x ",buf[i]); printk("\n"); } ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,6); if (ret!=6) tuner_warn("i2c i/o error: rc == %d (should be 6)\n",ret);}static int mt2050_set_tv_freq(struct dvb_frontend *fe, struct analog_parameters *params){ unsigned int if2; if (params->std & V4L2_STD_525_60) { // NTSC if2 = 45750*1000; } else { // PAL if2 = 38900*1000; } if (V4L2_TUNER_DIGITAL_TV == params->mode) { // DVB (pinnacle 300i) if2 = 36150*1000; } mt2050_set_if_freq(fe, params->frequency*62500, if2); mt2050_set_antenna(fe, tv_antenna); return 0;}static int mt2050_set_radio_freq(struct dvb_frontend *fe, struct analog_parameters *params){ struct microtune_priv *priv = fe->tuner_priv; int if2; if (params->std & V4L2_STD_525_60) { tuner_dbg("pinnacle ntsc\n"); if2 = 41300 * 1000; } else { tuner_dbg("pinnacle pal\n"); if2 = 33300 * 1000; } mt2050_set_if_freq(fe, params->frequency * 125 / 2, if2); mt2050_set_antenna(fe, radio_antenna); return 0;}static int mt2050_set_params(struct dvb_frontend *fe, struct analog_parameters *params){ struct microtune_priv *priv = fe->tuner_priv; int ret = -EINVAL; switch (params->mode) { case V4L2_TUNER_RADIO: ret = mt2050_set_radio_freq(fe, params); priv->frequency = params->frequency * 125 / 2; break; case V4L2_TUNER_ANALOG_TV: case V4L2_TUNER_DIGITAL_TV: ret = mt2050_set_tv_freq(fe, params); priv->frequency = params->frequency * 62500; break; } return ret;}static struct dvb_tuner_ops mt2050_tuner_ops = { .set_analog_params = mt2050_set_params, .release = microtune_release, .get_frequency = microtune_get_frequency,};static int mt2050_init(struct dvb_frontend *fe){ struct microtune_priv *priv = fe->tuner_priv; unsigned char buf[2]; int ret; buf[0]=6; buf[1]=0x10; ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); // power buf[0]=0x0f; buf[1]=0x0f; ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); // m1lo buf[0]=0x0d; ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,1); tuner_i2c_xfer_recv(&priv->i2c_props,buf,1); tuner_dbg("mt2050: sro is %x\n",buf[0]); memcpy(&fe->ops.tuner_ops, &mt2050_tuner_ops, sizeof(struct dvb_tuner_ops)); return 0;}struct dvb_frontend *microtune_attach(struct dvb_frontend *fe, struct i2c_adapter* i2c_adap, u8 i2c_addr){ struct microtune_priv *priv = NULL; char *name; unsigned char buf[21]; int company_code; priv = kzalloc(sizeof(struct microtune_priv), GFP_KERNEL); if (priv == NULL) return NULL; fe->tuner_priv = priv; priv->i2c_props.addr = i2c_addr; priv->i2c_props.adap = i2c_adap; //priv->radio_if2 = 10700 * 1000; /* 10.7MHz - FM radio */ memset(buf,0,sizeof(buf)); name = "unknown"; tuner_i2c_xfer_send(&priv->i2c_props,buf,1); tuner_i2c_xfer_recv(&priv->i2c_props,buf,21); if (debug) { int i; tuner_dbg("MT20xx hexdump:"); for(i=0;i<21;i++) { printk(" %02x",buf[i]); if(((i+1)%8)==0) printk(" "); } printk("\n"); } company_code = buf[0x11] << 8 | buf[0x12]; tuner_info("microtune: companycode=%04x part=%02x rev=%02x\n", company_code,buf[0x13],buf[0x14]); if (buf[0x13] < ARRAY_SIZE(microtune_part) && NULL != microtune_part[buf[0x13]]) name = microtune_part[buf[0x13]]; switch (buf[0x13]) { case MT2032: mt2032_init(fe); break; case MT2050: mt2050_init(fe); break; default: tuner_info("microtune %s found, not (yet?) supported, sorry :-/\n", name); return 0; } strlcpy(fe->ops.tuner_ops.info.name, name, sizeof(fe->ops.tuner_ops.info.name)); tuner_info("microtune %s found, OK\n",name); return fe;}EXPORT_SYMBOL_GPL(microtune_attach);MODULE_DESCRIPTION("Microtune tuner driver");MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");MODULE_LICENSE("GPL");/* * Overrides for Emacs so that we follow Linus's tabbing style. * --------------------------------------------------------------------------- * Local variables: * c-basic-offset: 8 * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -