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) tuner_dbg("bufs is: %*ph\n", 6, buf); 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); }
// Initialization as described in "MT203x Programming Procedures", Rev 1.2, Feb.2001 static 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); }
// Initalization as described in "MT203x Programming Procedures", Rev 1.2, Feb.2001 static int mt2032_init(struct i2c_client *c) { struct tuner *t = i2c_get_clientdata(c); 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=i2c_master_send(c,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=i2c_master_send(c,buf+5,6); buf[12]=13; // Index register 13 buf[13]=0x32; ret=i2c_master_send(c,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; i2c_master_send(c,buf,1); i2c_master_recv(c,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=i2c_master_send(c,buf,2); if (ret!=2) tuner_warn("i2c i/o error: rc == %d (should be 2)\n",ret); } while (xok != 1 ); t->xogc=xogc; t->tv_freq = mt2032_set_tv_freq; t->radio_freq = mt2032_set_radio_freq; return(1); }
static int mt2032_check_lo_lock(struct dvb_frontend *fe) { struct microtune_priv *priv = fe->tuner_priv; int try,lock=0; unsigned char buf[2]; for(try=0;try<10;try++) { buf[0]=0x0e; tuner_i2c_xfer_send(&priv->i2c_props,buf,1); tuner_i2c_xfer_recv(&priv->i2c_props,buf,1); tuner_dbg("mt2032 Reg.E=0x%02x\n",buf[0]); lock=buf[0] &0x06; if (lock==6) break; tuner_dbg("mt2032: pll wait 1ms for lock (0x%2x)\n",buf[0]); udelay(1000); } return lock; } static int mt2032_optimize_vco(struct dvb_frontend *fe,int sel,int lock) { struct microtune_priv *priv = fe->tuner_priv; unsigned char buf[2]; int tad1; buf[0]=0x0f; tuner_i2c_xfer_send(&priv->i2c_props,buf,1); tuner_i2c_xfer_recv(&priv->i2c_props,buf,1); tuner_dbg("mt2032 Reg.F=0x%02x\n",buf[0]); tad1=buf[0]&0x07; if(tad1 ==0) return lock; if(tad1 ==1) return lock; if(tad1==2) { if(sel==0) return lock; else sel--; } else { if(sel<4) sel++; else return lock; } tuner_dbg("mt2032 optimize_vco: sel=%d\n",sel); buf[0]=0x0f; buf[1]=sel; tuner_i2c_xfer_send(&priv->i2c_props,buf,2); lock=mt2032_check_lo_lock(fe); return lock; } static void mt2032_set_if_freq(struct dvb_frontend *fe, unsigned int rfin, unsigned int if1, unsigned int if2, unsigned int from, unsigned int to) { unsigned char buf[21]; int lint_try,ret,sel,lock=0; struct microtune_priv *priv = fe->tuner_priv; tuner_dbg("mt2032_set_if_freq rfin=%d if1=%d if2=%d from=%d to=%d\n", rfin,if1,if2,from,to); buf[0]=0; ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,1); tuner_i2c_xfer_recv(&priv->i2c_props,buf,21); buf[0]=0; ret=mt2032_compute_freq(fe,rfin,if1,if2,from,to,&buf[1],&sel,priv->xogc); if (ret<0) return; // send only the relevant registers per Rev. 1.2 buf[0]=0; ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,4); buf[5]=5; ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+5,4); buf[11]=11; ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+11,3); if(ret!=3) tuner_warn("i2c i/o error: rc == %d (should be 3)\n",ret); // wait for PLLs to lock (per manual), retry LINT if not. for(lint_try=0; lint_try<2; lint_try++) { lock=mt2032_check_lo_lock(fe); if(optimize_vco) lock=mt2032_optimize_vco(fe,sel,lock); if(lock==6) break; tuner_dbg("mt2032: re-init PLLs by LINT\n"); buf[0]=7; buf[1]=0x80 +8+priv->xogc; // set LINT to re-init PLLs tuner_i2c_xfer_send(&priv->i2c_props,buf,2); mdelay(10); buf[1]=8+priv->xogc; tuner_i2c_xfer_send(&priv->i2c_props,buf,2); } if (lock!=6) tuner_warn("MT2032 Fatal Error: PLLs didn't lock.\n"); buf[0]=2; buf[1]=0x20; // LOGC for optimal phase noise 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); }
int microtune_init(struct i2c_client *c) { struct tuner *t = i2c_get_clientdata(c); char *name; unsigned char buf[21]; int company_code; memset(buf,0,sizeof(buf)); t->tv_freq = NULL; t->radio_freq = NULL; name = "unknown"; i2c_master_send(c,buf,1); i2c_master_recv(c,buf,21); if (tuner_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 0 /* seems to cause more problems than it solves ... */ switch (company_code) { case 0x30bf: case 0x3cbf: case 0x3dbf: case 0x4d54: case 0x8e81: case 0x8e91: /* ok (?) */ break; default: tuner_warn("tuner: microtune: unknown companycode\n"); return 0; } #endif if (buf[0x13] < ARRAY_SIZE(microtune_part) && NULL != microtune_part[buf[0x13]]) name = microtune_part[buf[0x13]]; switch (buf[0x13]) { case MT2032: mt2032_init(c); break; case MT2050: mt2050_init(c); break; default: tuner_info("microtune %s found, not (yet?) supported, sorry :-/\n", name); return 0; } strlcpy(c->name, name, sizeof(c->name)); tuner_info("microtune %s found, OK\n",name); return 0; }
static void mt2050_set_if_freq(struct i2c_client *c,unsigned int freq, unsigned int if2) { struct tuner *t = i2c_get_clientdata(c); 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 (tuner_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 (tuner_debug > 1) { int i; tuner_dbg("bufs is: "); for(i=0;i<6;i++) printk("%x ",buf[i]); printk("\n"); } ret=i2c_master_send(c,buf,6); if (ret!=6) tuner_warn("i2c i/o error: rc == %d (should be 6)\n",ret); }
static void tda8290_init_tuner(struct dvb_frontend *fe) { struct tda8290_priv *priv = fe->analog_demod_priv; unsigned char tda8275_init[] = { 0x00, 0x00, 0x00, 0x40, 0xdC, 0x04, 0xAf, 0x3F, 0x2A, 0x04, 0xFF, 0x00, 0x00, 0x40 }; unsigned char tda8275a_init[] = { 0x00, 0x00, 0x00, 0x00, 0xdC, 0x05, 0x8b, 0x0c, 0x04, 0x20, 0xFF, 0x00, 0x00, 0x4b }; struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0, .buf=tda8275_init, .len = 14}; if (priv->ver & TDA8275A) msg.buf = tda8275a_init; tda8290_i2c_bridge(fe, 1); i2c_transfer(priv->i2c_props.adap, &msg, 1); tda8290_i2c_bridge(fe, 0); } /*---------------------------------------------------------------------*/ static void tda829x_release(struct dvb_frontend *fe) { struct tda8290_priv *priv = fe->analog_demod_priv; /* only try to release the tuner if we've * attached it from within this module */ if (priv->ver & (TDA18271 | TDA8275 | TDA8275A)) if (fe->ops.tuner_ops.release) fe->ops.tuner_ops.release(fe); kfree(fe->analog_demod_priv); fe->analog_demod_priv = NULL; } static struct tda18271_config tda829x_tda18271_config = { .gate = TDA18271_GATE_ANALOG, }; static int tda829x_find_tuner(struct dvb_frontend *fe) { struct tda8290_priv *priv = fe->analog_demod_priv; struct analog_demod_ops *analog_ops = &fe->ops.analog_ops; int i, ret, tuners_found; u32 tuner_addrs; u8 data; struct i2c_msg msg = { .flags = I2C_M_RD, .buf = &data, .len = 1 }; if (!analog_ops->i2c_gate_ctrl) { printk(KERN_ERR "tda8290: no gate control were provided!\n"); return -EINVAL; } analog_ops->i2c_gate_ctrl(fe, 1); /* probe for tuner chip */ tuners_found = 0; tuner_addrs = 0; for (i = 0x60; i <= 0x63; i++) { msg.addr = i; ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); if (ret == 1) { tuners_found++; tuner_addrs = (tuner_addrs << 8) + i; } } /* if there is more than one tuner, we expect the right one is behind the bridge and we choose the highest address that doesn't give a response now */ analog_ops->i2c_gate_ctrl(fe, 0); if (tuners_found > 1) for (i = 0; i < tuners_found; i++) { msg.addr = tuner_addrs & 0xff; ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); if (ret == 1) tuner_addrs = tuner_addrs >> 8; else break; } if (tuner_addrs == 0) { tuner_addrs = 0x60; tuner_info("could not clearly identify tuner address, " "defaulting to %x\n", tuner_addrs); } else { tuner_addrs = tuner_addrs & 0xff; tuner_info("setting tuner address to %x\n", tuner_addrs); } priv->tda827x_addr = tuner_addrs; msg.addr = tuner_addrs; analog_ops->i2c_gate_ctrl(fe, 1); ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); if (ret != 1) { tuner_warn("tuner access failed!\n"); analog_ops->i2c_gate_ctrl(fe, 0); return -EREMOTEIO; } if ((data == 0x83) || (data == 0x84)) { priv->ver |= TDA18271; tda829x_tda18271_config.config = priv->cfg.config; dvb_attach(tda18271_attach, fe, priv->tda827x_addr, priv->i2c_props.adap, &tda829x_tda18271_config); } else { if ((data & 0x3c) == 0) priv->ver |= TDA8275; else priv->ver |= TDA8275A; dvb_attach(tda827x_attach, fe, priv->tda827x_addr, priv->i2c_props.adap, &priv->cfg); priv->cfg.switch_addr = priv->i2c_props.addr; } if (fe->ops.tuner_ops.init) fe->ops.tuner_ops.init(fe); if (fe->ops.tuner_ops.sleep) fe->ops.tuner_ops.sleep(fe); analog_ops->i2c_gate_ctrl(fe, 0); return 0; } static int tda8290_probe(struct tuner_i2c_props *i2c_props) { #define TDA8290_ID 0x89 unsigned char tda8290_id[] = { 0x1f, 0x00 }; /* detect tda8290 */ tuner_i2c_xfer_send(i2c_props, &tda8290_id[0], 1); tuner_i2c_xfer_recv(i2c_props, &tda8290_id[1], 1); if (tda8290_id[1] == TDA8290_ID) { if (debug) printk(KERN_DEBUG "%s: tda8290 detected @ %d-%04x\n", __func__, i2c_adapter_id(i2c_props->adap), i2c_props->addr); return 0; } return -ENODEV; }