--- mt312.c_ORIG	2004-06-16 07:18:57.000000000 +0200
+++ mt312.c	2004-08-01 17:47:40.368928527 +0200
@@ -3,6 +3,9 @@
 
     Copyright (C) 2003 Andreas Oberritter <obi@linuxtv.org>
 
+    Auto symbol rate, measure frequency offset
+        Roberto Ragusa, mail at robertoragusa dot it
+
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
     the Free Software Foundation; either version 2 of the License, or
@@ -213,7 +216,7 @@
 	if (freq < 1550000)
 		buf[3] |= 0x10;
 
-	dprintk(KERN_INFO "synth dword = %02x%02x%02x%02x\n", buf[0],
+	dprintk(KERN_INFO "sl1935 synth dword = %02x%02x%02x%02x\n", buf[0],
 	       buf[1], buf[2], buf[3]);
 
 	return mt312_pll_write(i2c, I2C_ADDR_SL1935, buf, sizeof(buf));
@@ -233,7 +236,7 @@
 	if (freq < 1550000)
 		buf[3] |= 0x02;
 
-	dprintk(KERN_INFO "synth dword = %02x%02x%02x%02x\n", buf[0],
+	dprintk(KERN_INFO "tsa5059 synth dword = %02x%02x%02x%02x\n", buf[0],
 	       buf[1], buf[2], buf[3]);
 
 	return mt312_pll_write(i2c, I2C_ADDR_TSA5059, buf, sizeof(buf));
@@ -482,6 +485,19 @@
 	return 0;
 }
 
+static int mt312_read_frequency_offset(struct dvb_i2c_bus *i2c, u16 * frequency_offset)
+{
+	int ret;
+	u8 buf[2];
+
+	if ((ret = mt312_read(i2c, LNB_FREQ_H, &buf, sizeof(buf))) < 0)
+		return ret;
+
+	*frequency_offset = (buf[0] << 8) | buf[1];
+
+	return 0;
+}
+
 static int mt312_set_frontend(struct dvb_i2c_bus *i2c,
 			      const struct dvb_frontend_parameters *p,
 			      const long id)
@@ -506,8 +522,9 @@
 	    || (p->inversion > INVERSION_AUTO))
 		return -EINVAL;
 
-	if ((p->u.qpsk.symbol_rate < mt312_info.symbol_rate_min)
-	    || (p->u.qpsk.symbol_rate > mt312_info.symbol_rate_max))
+	if (!((p->u.qpsk.symbol_rate <= 0x0fff)  // auto symbol rate
+	      || ((p->u.qpsk.symbol_rate >= mt312_info.symbol_rate_min)
+	          && (p->u.qpsk.symbol_rate <= mt312_info.symbol_rate_max))))
 		return -EINVAL;
 
 	if ((p->u.qpsk.fec_inner < FEC_NONE)
@@ -524,7 +541,7 @@
 	// It should be better for the mt312 as well, but tunning will be slower. ACCJr 09/29/03
 		if ((ret = mt312_readreg(i2c, CONFIG, &config_val) < 0))
 			return ret;
-		if (p->u.qpsk.symbol_rate >= 30000000) //Note that 30MS/s should use 90MHz
+		if (p->u.qpsk.symbol_rate >= 30000000) //Note that 30MS/s should use 90MHz //if autosearch, 60
 		{
 			if ((config_val & 0x0c) == 0x08) //We are running 60MHz
 				if ((ret = mt312_init(i2c, id, (u8) 90)) < 0)
@@ -545,15 +562,27 @@
 		return -EINVAL;
 	}
 
-	if ((ret = set_tv_freq(i2c, p->frequency, p->u.qpsk.symbol_rate)) < 0)
-		return ret;
+        if (p->u.qpsk.symbol_rate >= mt312_info.symbol_rate_min){ //Specified symbol rate
+		if ((ret = set_tv_freq(i2c, p->frequency, p->u.qpsk.symbol_rate)) < 0)
+			return ret;
 
-	/* sr = (u16)(sr * 256.0 / 1000000.0) */
-	sr = mt312_div(p->u.qpsk.symbol_rate * 4, 15625);
+		/* sr = (u16)(sr * 256.0 / 1000000.0) */
+		sr = mt312_div(p->u.qpsk.symbol_rate * 4, 15625);
 
-	/* SYM_RATE */
-	buf[0] = (sr >> 8) & 0x3f;
-	buf[1] = (sr >> 0) & 0xff;
+		/* SYM_RATE */
+		buf[0] = (sr >> 8) & 0x3f;
+		buf[1] = (sr >> 0) & 0xff;
+	}
+	else{ //Auto symbol rate
+		if ((ret = set_tv_freq(i2c, p->frequency, 20000000)) < 0) //20000000 as placeholder
+			return ret;
+
+		/* SYM_RATE SEARCH */
+                /* use the specified frequency ranges */
+		buf[0] = 0x80 | ((p->u.qpsk.symbol_rate >> 8) & 0x0f);
+		buf[1] = p->u.qpsk.symbol_rate & 0xff;
+		dprintk("%s: sr_auto_range= %02x %02x\n", __FILE__, buf[0], buf[1]);
+	}
 
 	/* VIT_MODE */
 	buf[2] = inv_tab[p->inversion] | fec_tab[p->u.qpsk.fec_inner];
@@ -561,8 +590,13 @@
 	/* QPSK_CTRL */
 	buf[3] = 0x40;		/* swap I and Q before QPSK demodulation */
 
-	if (p->u.qpsk.symbol_rate < 10000000)
-		buf[3] |= 0x04;	/* use afc mode */
+        if (p->u.qpsk.symbol_rate > 0){ //Specified symbol rate
+		if (p->u.qpsk.symbol_rate < 10000000)
+			buf[3] |= 0x04;	/* use afc mode */
+	}
+	else{ //Auto symbol rate
+		//buf[3] |= 0x04;	/* use afc mode */
+	}
 
 	/* GO */
 	buf[4] = 0x01;
@@ -598,6 +632,7 @@
 	u16 sym_rat_op;
 	u16 monitor;
 	u8 buf[2];
+	u8 config_val, pll;
 
 	if ((ret = mt312_readreg(i2c, SYM_RATE_H, &sym_rate_h)) < 0)
 		return ret;
@@ -611,8 +646,9 @@
 
 		monitor = (buf[0] << 8) | buf[1];
 
-		dprintk(KERN_DEBUG "sr(auto) = %u\n",
-		       mt312_div(monitor * 15625, 4));
+		*sr = mt312_div(monitor * 1000, 1024) * 1000;
+		dprintk(KERN_DEBUG "sr(auto) = %d\n",
+		       *sr);
 	} else {
 		if ((ret = mt312_writereg(i2c, MON_CTRL, 0x05)) < 0)
 			return ret;
@@ -629,9 +665,21 @@
 
 		dprintk(KERN_DEBUG "sym_rat_op=%d dec_ratio=%d\n",
 		       sym_rat_op, dec_ratio);
-		dprintk(KERN_DEBUG "*sr(manual) = %lu\n",
-		       (((MT312_PLL_CLK * 8192) / (sym_rat_op + 8192)) *
-			2) - dec_ratio);
+
+                // check the pll frequency
+		if ((ret = mt312_readreg(i2c, CONFIG, &config_val) < 0))
+			return ret;
+                if ((config_val & 0x0c) == 0x08) pll = 60; else pll = 90;
+		dprintk(KERN_DEBUG "pll=%d\n",
+		       pll);
+
+                // datasheet is apparently very wrong -- rora 2004/07/31
+		// it says PLL_CLK instead of SYS_CLK
+		// it says "...*2-dec_ratio" instead of "...*2^(-dec_ratio)"
+		*sr = mt312_div((pll * 1000 * 8192 / (sym_rat_op + 8192) * 1000), 1 << dec_ratio);
+
+		dprintk(KERN_DEBUG "*sr(manual) = %d\n",
+		       *sr);
 	}
 
 	return 0;
@@ -738,6 +786,9 @@
 	case FE_READ_UNCORRECTED_BLOCKS:
 		return mt312_read_ubc(i2c, arg);
 
+	case FE_READ_FREQUENCY_OFFSET:
+		return mt312_read_frequency_offset(i2c, arg);
+
 	case FE_SET_FRONTEND:
 		return mt312_set_frontend(i2c, arg, (long) fe->data);
 
@@ -785,6 +836,8 @@
 	if ((id != ID_VP310) && (id != ID_MT312))
 		return -ENODEV;
 
+	printk("%s: %s chip found\n", __FILE__, id == ID_VP310 ? "Zarlink VP310": "Zarlink MT312");
+
 	if ((ret = dvb_register_frontend(mt312_ioctl, i2c,
 				(void *)(long)id, &mt312_info)) < 0)
 		return ret;
