Patch(bttv-0.7.109/linux-2.4.23): Support MT2050 for newer pinnacle cards EMPTYV-51014521-2.2A

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]



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) {

[Index of Archives]     [Linux DVB]     [Video Disk Recorder]     [Asterisk]     [Photo]     [DCCP]     [Netdev]     [Xorg]     [Util Linux NG]     [Xfree86]     [Free Photo Albums]     [Fedora Users]     [Fedora Women]     [ALSA Users]     [ALSA Devel]     [Linux USB]

Powered by Linux