Hi, this patch autodetects mt2032/mt2050 tuners: - tested with pinnacle pctv rave PAL-BG - radio untested Gerd, please apply. The patch is relative to bttv as found in linux-2.4.23 because stand-alone bttv-0.7.10x+snapshots oops for me in i2c routines with this kernel. Regards, Gunther
--- tuner.c-orig-2.4.23 2003-11-30 14:30:40.000000000 +0100 +++ tuner.c 2003-11-30 18:32:14.000000000 +0100 @@ -59,11 +59,15 @@ // only for MT2032 unsigned int xogc; unsigned int radio_if2; + unsigned int mt_type; // we support 2032 and 2050 }; static struct i2c_driver driver; static struct i2c_client client_template; +static int mt2032_init(struct i2c_client *c); + + /* ---------------------------------------------------------------------- */ /* tv standard selection for Temic 4046 FM5 @@ -209,7 +213,7 @@ { "Samsung PAL TCPM9091PD27", Samsung, PAL, /* from sourceforge v3tv */ 16*169,16*464,0xA0,0x90,0x30,0x8e,623}, - { "MT2032 universal", Microtune,PAL|NTSC, + { "MT2032/MT2050", Microtune,PAL|NTSC, 0,0,0,0,0,0,0}, { "Temic PAL_BG (4106 FH5)", TEMIC, PAL, 16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623}, @@ -283,23 +287,55 @@ } #endif -// Initalization as described in "MT203x Programming Procedures", Rev 1.2, Feb.2001 -static int mt2032_init(struct i2c_client *c) +static int mt2050_init(struct i2c_client *c) +{ + unsigned char buf[1]; + int ret; + + buf[0]=6; + buf[1]=0x10; + ret=i2c_master_send(c,buf,2); // power + + buf[0]=0x0f; + buf[1]=0x0f; + ret=i2c_master_send(c,buf,2); // m1lo + + buf[0]=0x0d; + ret=i2c_master_send(c,buf,1); + i2c_master_recv(c,buf,1); + + dprintk("mt2050 sro is %x\n",buf[0]); + return 0; +} + +// autodetect MT2032 and MT2050 +static int microtune_init(struct i2c_client *c) { unsigned char buf[21]; - int ret,xogc,xok=0; + int ret; struct tuner *t = i2c_get_clientdata(c); buf[0]=0; ret=i2c_master_send(c,buf,1); i2c_master_recv(c,buf,21); - printk("MT2032: Companycode=%02x%02x Part=%02x Revision=%02x\n", - buf[0x11],buf[0x12],buf[0x13],buf[0x14]); - - if(debug) { + // Look for MT2032 id: + // part= 0x04(MT2032), 0x06(MT2030), 0x07(MT2040) + if((buf[0x11] == 0x4d) && (buf[0x12] == 0x54) && (buf[0x13] == 0x04)) { + printk("tuner: MT2032 detected.\n"); + t->mt_type=2032; + } + else if(buf[0]==0x42) { + printk("tuner: MT2050 detected.\n"); + t->mt_type=2050; + } + else { + printk("tuner: no MT2032 nor MT2050 detected.\n"); + t->mt_type=0; + } + if(debug || t->mt_type==0) { int i; - printk("MT2032 hexdump:\n"); + printk("tuner: MT20xx hexdump:\n"); for(i=0;i<21;i++) { printk(" %02x",buf[i]); if(((i+1)%8)==0) printk(" "); @@ -307,13 +343,24 @@ } printk("\n "); } - // Look for MT2032 id: - // part= 0x04(MT2032), 0x06(MT2030), 0x07(MT2040) - if((buf[0x11] != 0x4d) || (buf[0x12] != 0x54) || (buf[0x13] != 0x04)) { - printk("not a MT2032.\n"); - return 0; - } + if(t->mt_type==0) { + printk("tuner: your tuner is not supported.\n"); + } + else if(t->mt_type==2032) + mt2032_init(c); + else if(t->mt_type==2050) + mt2050_init(c); + return 0; +} + +// Initalization as described in "MT203x Programming Procedures", Rev 1.2, Feb.2001 +static int mt2032_init(struct i2c_client *c) +{ + unsigned char buf[21]; + int ret,xogc,xok=0; + struct tuner *t = i2c_get_clientdata(c); + buf[0]=0; // Initialize Registers per spec. buf[1]=2; // Index to register 2 @@ -586,6 +633,80 @@ printk("mt2032_set_if_freq2 failed with %d\n",ret); } +static void mt2050_set_if_freq(struct i2c_client *c,unsigned int freq, unsigned int if2) +{ + 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]; + + dprintk("mt2050_set_if_freq freq=%d\n",freq); + + 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; + + dprintk("lo1 lo2 = %d %d\n", lo1, lo2); + dprintk("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) { + int i; + printk("bufs is: "); + for(i=0;i<6;i++) + printk("%x ",buf[i]); + printk("\n"); + } + + ret=i2c_master_send(c,buf,6); + if (ret!=6) + printk("mt2050_set_if_freq failed with %d\n",ret); +} + + +static void mt2050_set_tv_freq(struct i2c_client *c, + unsigned int freq, unsigned int norm) +{ + unsigned int if2; + + if (norm==VIDEO_MODE_NTSC) { + if2=45750*1000; + } else { + // Pal + if2=38900*1000; + } + mt2050_set_if_freq(c,freq*62500,if2); +} static void mt2032_set_tv_freq(struct i2c_client *c, unsigned int freq, unsigned int norm) @@ -603,9 +724,19 @@ to=39900*1000; if2=38900*1000; } - mt2032_set_if_freq(c, freq*62500 /* freq*1000*1000/16 */, - 1090*1000*1000, if2, from, to); + 1090*1000*1000, if2, from, to); +} + +static void microtune_set_tv_freq(struct i2c_client *c, + unsigned int freq, unsigned int norm) +{ + struct tuner *t = i2c_get_clientdata(c); + + if(t->mt_type==2032) + mt2032_set_tv_freq(c,freq,norm); + else if(t->mt_type==2050) + mt2050_set_tv_freq(c,freq,norm); } @@ -624,7 +755,7 @@ return; } if (t->type == TUNER_MT2032) { - mt2032_set_tv_freq(c,freq,t->mode); + microtune_set_tv_freq(c,freq,t->mode); return; } @@ -746,9 +877,12 @@ struct tuner *t = i2c_get_clientdata(c); int if2 = t->radio_if2; - // per Manual for FM tuning: first if center freq. 1085 MHz - mt2032_set_if_freq(c, freq*62500 /* freq*1000*1000/16 */, + if(t->mt_type==2032) + // per Manual for FM tuning: first if center freq. 1085 MHz + mt2032_set_if_freq(c, freq*62500 /* freq*1000*1000/16 */, 1085*1000*1000,if2,if2,if2); + else if(t->mt_type==2050) + mt2050_set_if_freq(c,freq*62500,if2); } static void set_radio_freq(struct i2c_client *c, unsigned int freq) @@ -833,7 +967,7 @@ } i2c_attach_client(client); if (t->type == TUNER_MT2032) - mt2032_init(client); + microtune_init(client); MOD_INC_USE_COUNT; return 0; @@ -895,7 +1029,7 @@ t->type,tuners[t->type].name); strlcpy(client->name, tuners[t->type].name, sizeof(client->name)); if (t->type == TUNER_MT2032) - mt2032_init(client); + microtune_init(client); break; case AUDC_SET_RADIO: if (!t->radio) {