heissan!
Can you try attached patch and report?
This patch is a little bit unready due to changes needed to zl10353 demodulator driver. I have no knowledge what are registers 0x8e and 0x90-0x96 (please help) but I have strong feeling that those are associated to the AGC2 functionality. I think I will put those under the agc2-config-switch and send this patch again later. Any ideas are welcome :) Patch is done against current gl861 devel tree at http://linuxtv.org/hg/~aapot/gl861/ .

Thanks for Markus and Aapo for helping!

Regards Antti

Signed-off-by: Antti Palosaari <[EMAIL PROTECTED]>

Markus Rechberger wrote:
On 6/13/07, Erich N. Pekarek <[EMAIL PROTECTED]> wrote:
Hello,

having read various tutorials, having tried various repositories including
v4l-dvb-experimental from mcentral.de, v4l-dvb-test and the regular v4l-dvb,
having installed rc4 of 2.4.22 kernel, while trying to follow the rules of
clean install and reboot, I have to admit, that tuning to 794Mhz for the
Austrian MUX-A seems to be impossible with linux (feisty). The same device
works without problems with a medium to strong signal on XP.

Current status: i seem to tune, but no SNR-Level seems sufficient for a
lock.

here is my lsusb: Bus 001 Device 004: ID 0db0:5581 Micro Star International
dmesg is identical to most other postings - ZL10353, QT1010 and GL861 are
being detected on "... 55801 USB 2.0...", no firmware upload takes place.
Setting an additional   zl10353_single_write(fe, 0x5A, 0x0C);
as described on
http://linuxtv.org/pipermail/linux-dvb/2007-January/015518.html
shows no effort.
---
#dvbtune -f 794
Using DVB card "Zarlink ZL10353 DVB-T"tuning DVB-T (in United Kingdom) to
794000 Hz
polling....
Getting frontend event
FE_STATUS:
polling....
polling....

---
kaffeine shows some signal, two of 99%, SNR reaches 12% once (on the wrong
frequency?) and won´t lock on to it.

---
channels.conf copied:
ORF1:794000000:I999B8C999D999M16T8G4Y0:T:27500:1010:1011,1012;1013:1015:0:10101:
8232:100:0
---
mplayer:
...

Playing dvb://ORF1.
dvb_tune Freq: 794000
Not able to lock to the signal on the given frequency, timeout: 30
dvb_tune, TUNING FAILED
ERROR, COULDN'T SET CHANNEL  0: Failed to open dvb://ORF1.


Exiting... (End of file)
---
I cannot identify the problem without help. Would someone please assist me
in tracking down and solving the error?

Someone who owns that device maybe can help you to get further with it.

I´ve already returned a WinTV HVR-900 to my dealer, because of the missing
micronas support in the newest revision and get starting depressed :-(

The Micronas drx3975d will be supported soon I already received some
specs and sample sourcecode.

cheers,
Markus
So long and thanks for all the ... help

Kind regards
Erich

P.s: dmesg output will follow after another kernel has been compiled. Which
other log files would you like to see?

--
Der GMX SmartSurfer hilft bis zu 70% Ihrer Onlinekosten zu sparen!
Ideal für Modem und ISDN: http://www.gmx.net/de/go/smartsurfer

_______________________________________________
linux-dvb mailing list
linux-dvb@linuxtv.org
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb





--
              |||
             (0-0)
---------oOO--(_)--OOo--------------------------------------------
tel. +358 40 535 7322 | MSN Messenger [EMAIL PROTECTED] | www.palosaari.fi
-Kahta asiaa en ymmärrä.. C-kielen syntaksi ja naisten logiikka.."

diff -r 214a42e5076f linux/drivers/media/dvb/dvb-usb/au6610.c
--- a/linux/drivers/media/dvb/dvb-usb/au6610.c	Tue May 08 23:36:40 2007 +0300
+++ b/linux/drivers/media/dvb/dvb-usb/au6610.c	Wed Jun 13 23:33:28 2007 +0300
@@ -127,6 +127,8 @@ static struct zl10353_config au6610_zl10
 	.demod_address = 0x0f,
 	.no_tuner = 1,
 	.parallel_ts = 1,
+	.agc2 = 1,
+	.unknown_init = 1
 };
 
 static int au6610_zl10353_frontend_attach(struct dvb_usb_adapter *adap)
diff -r 214a42e5076f linux/drivers/media/dvb/dvb-usb/gl861.c
--- a/linux/drivers/media/dvb/dvb-usb/gl861.c	Tue May 08 23:36:40 2007 +0300
+++ b/linux/drivers/media/dvb/dvb-usb/gl861.c	Wed Jun 13 23:33:28 2007 +0300
@@ -104,6 +104,8 @@ static struct zl10353_config gl861_zl103
 	.demod_address = 0x0f,
 	.no_tuner = 1,
 	.parallel_ts = 1,
+	.agc2 = 1,
+	.unknown_init = 1
 };
 
 static int gl861_frontend_attach(struct dvb_usb_adapter *adap)
diff -r 214a42e5076f linux/drivers/media/dvb/frontends/qt1010.c
--- a/linux/drivers/media/dvb/frontends/qt1010.c	Tue May 08 23:36:40 2007 +0300
+++ b/linux/drivers/media/dvb/frontends/qt1010.c	Wed Jun 13 23:41:11 2007 +0300
@@ -27,7 +27,7 @@ MODULE_PARM_DESC(debug, "Turn on/off deb
 
 #define dprintk(args...) \
 	do { \
-		if (debug) printk(KERN_DEBUG "QT1010: " args); \
+		if (debug) printk(KERN_DEBUG "qt1010: " args); \
 	} while (0)
 
 /* read single register */
@@ -41,7 +41,7 @@ static int qt1010_readreg(struct qt1010_
 	};
 
 	if (i2c_transfer(priv->i2c, msg, 2) != 2) {
-		printk(KERN_WARNING "qt1010 I2C read failed\n");
+		printk(KERN_WARNING "qt1010: i2c read failed (reg:%02x)\n", reg);
 		return -EREMOTEIO;
 	}
 	return 0;
@@ -55,12 +55,13 @@ static int qt1010_writereg(struct qt1010
 			       .flags = 0, .buf = buf, .len = 2 };
 
 	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
-		printk(KERN_WARNING "qt1010 I2C write failed\n");
+		printk(KERN_WARNING "qt1010: i2c write failed (reg:%02x val:%02x)\n", reg, val);
 		return -EREMOTEIO;
 	}
 	return 0;
 }
 
+#if 0
 /* dump all registers */
 static void qt1010_dump_regs(struct qt1010_priv *priv)
 {
@@ -70,7 +71,7 @@ static void qt1010_dump_regs(struct qt10
 	for (reg = 0; ; reg++) {
 		if (reg % 16 == 0) {
 			if (reg)
-				printk("%s\n", buf);
+				dprintk("%s\n", buf);
 			sprintf(buf, "%02x: ", reg);
 		}
 		if (qt1010_readreg(priv, reg, &val) == 0)
@@ -81,176 +82,74 @@ static void qt1010_dump_regs(struct qt10
 		if (reg == 0x2f)
 			break;
 	}
-	printk("%s\n", buf);
-}
-
-static int qt1010_set_params(struct dvb_frontend *fe,
-			     struct dvb_frontend_parameters *params)
-{
-	struct qt1010_priv *priv;
+	dprintk("%s\n", buf);
+}
+#endif
+
+/* read register in the loop until mask match or timeout occurs */
+static int qt1010_readreg_looping(struct qt1010_priv *priv, u8 reg, u8 mask, u8 *val)
+{
+	int err = 0;
+	u8 tmpval;
+	unsigned long timeout;
+
+	timeout = jiffies + msecs_to_jiffies(30);
+
+	while (time_before(jiffies, timeout) && !err) {
+		err = qt1010_readreg(priv, reg, &tmpval);
+		if (tmpval & mask) break;
+	}
+ 	*val = tmpval;
+	return err;
+}
+
+/* write ten times value 0x80 to register 0x01 */
+static int qt1010_loop10(struct qt1010_priv *priv)
+{
 	int err;
-	u32 freq, div, mod1, mod2;
-	u8 i, tmpval, reg05;
-	qt1010_i2c_oper_t rd[48] = {
-		{ QT1010_WR, 0x01, 0x80 },
-		{ QT1010_WR, 0x02, 0x3f },
-		{ QT1010_WR, 0x05, 0xff }, /* 02 c write */
-		{ QT1010_WR, 0x06, 0x44 },
-		{ QT1010_WR, 0x07, 0xff }, /* 04 c write */
-		{ QT1010_WR, 0x08, 0x08 },
-		{ QT1010_WR, 0x09, 0xff }, /* 06 c write */
-		{ QT1010_WR, 0x0a, 0xff }, /* 07 c write */
-		{ QT1010_WR, 0x0b, 0xff }, /* 08 c write */
-		{ QT1010_WR, 0x0c, 0xe1 },
-		{ QT1010_WR, 0x1a, 0xff }, /* 10 c write */
-		{ QT1010_WR, 0x1b, 0x00 },
-		{ QT1010_WR, 0x1c, 0x89 },
-		{ QT1010_WR, 0x11, 0xff }, /* 13 c write */
-		{ QT1010_WR, 0x12, 0xff }, /* 14 c write */
-		{ QT1010_WR, 0x22, 0xff }, /* 15 c write */
-		{ QT1010_WR, 0x1e, 0x00 },
-		{ QT1010_WR, 0x1e, 0xd0 },
-		{ QT1010_RD, 0x22, 0xff }, /* 16 c read */
-		{ QT1010_WR, 0x1e, 0x00 },
-		{ QT1010_RD, 0x05, 0xff }, /* 20 c read */
-		{ QT1010_RD, 0x22, 0xff }, /* 21 c read */
-		{ QT1010_WR, 0x23, 0xd0 },
-		{ QT1010_WR, 0x1e, 0x00 },
-		{ QT1010_WR, 0x1e, 0xe0 },
-		{ QT1010_RD, 0x23, 0xff }, /* 25 c read */
-		{ QT1010_RD, 0x23, 0xff }, /* 26 c read */
-		{ QT1010_WR, 0x1e, 0x00 },
-		{ QT1010_WR, 0x24, 0xd0 },
-		{ QT1010_WR, 0x1e, 0x00 },
-		{ QT1010_WR, 0x1e, 0xf0 },
-		{ QT1010_RD, 0x24, 0xff }, /* 31 c read */
-		{ QT1010_WR, 0x1e, 0x00 },
-		{ QT1010_WR, 0x14, 0x7f },
-		{ QT1010_WR, 0x15, 0x7f },
-		{ QT1010_WR, 0x05, 0xff }, /* 35 c write */
-		{ QT1010_WR, 0x06, 0x00 },
-		{ QT1010_WR, 0x15, 0x1f },
-		{ QT1010_WR, 0x16, 0xff },
-		{ QT1010_WR, 0x18, 0xff },
-		{ QT1010_WR, 0x1f, 0xff }, /* 40 c write */
-		{ QT1010_WR, 0x20, 0xff }, /* 41 c write */
-		{ QT1010_WR, 0x21, 0x53 },
-		{ QT1010_WR, 0x25, 0xff }, /* 43 c write */
-		{ QT1010_WR, 0x26, 0x15 },
-		{ QT1010_WR, 0x00, 0xff }, /* 45 c write */
-		{ QT1010_WR, 0x02, 0x00 },
-		{ QT1010_WR, 0x01, 0x00 }
-	};
-
-#define FREQ1 32000000 /* 32 MHz */
-#define FREQ2  4000000 /* 4 MHz Quartz oscillator in the stick? */
-
-	priv = fe->tuner_priv;
-	freq = params->frequency;
-	div = (freq + QT1010_OFFSET) / QT1010_STEP;
-	freq = (div * QT1010_STEP) - QT1010_OFFSET;
-	mod1 = (freq + QT1010_OFFSET) % FREQ1;
-	mod2 = (freq + QT1010_OFFSET) % FREQ2;
-	priv->bandwidth =
-		(fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
-	priv->frequency = freq;
+	u8 i;
+	for (i = 0; i < 10; i++) {
+		if ((err = qt1010_writereg(priv, 0x01, 0x80)))
+			return err;
+	}
+	return 0;
+}
+
+/* do i2c reads / writes according to given data */
+static int qt1010_handle_i2c_oper_table(struct dvb_frontend *fe,
+                                        qt1010_i2c_oper_t *data, int len)
+{
+	struct qt1010_priv *priv = fe->tuner_priv;
+	int err, i;
+	u8 tmpval;
 
 	if (fe->ops.i2c_gate_ctrl)
 		fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
 
-	/* reg 05 base value */
-	if      (freq < 290000000) reg05 = 0x14; /* 290 MHz */
-	else if (freq < 610000000) reg05 = 0x34; /* 610 MHz */
-	else if (freq < 802000000) reg05 = 0x54; /* 802 MHz */
-	else                       reg05 = 0x74;
-
-	/* 0x5 */
-	rd[2].val = reg05;
-
-	/* 07 - set frequency: 32 MHz scale */
-	rd[4].val = (freq + QT1010_OFFSET) / FREQ1;
-
-	/* 09 - changes every 8/24 MHz */
-	if (mod1 < 8000000) rd[6].val = 0x1d;
-	else                rd[6].val = 0x1c;
-
-	/* 0a - set frequency: 4 MHz scale (max 28 MHz) */
-	if      (mod1 < 1*FREQ2) rd[7].val = 0x09; /*  +0 MHz */
-	else if (mod1 < 2*FREQ2) rd[7].val = 0x08; /*  +4 MHz */
-	else if (mod1 < 3*FREQ2) rd[7].val = 0x0f; /*  +8 MHz */
-	else if (mod1 < 4*FREQ2) rd[7].val = 0x0e; /* +12 MHz */
-	else if (mod1 < 5*FREQ2) rd[7].val = 0x0d; /* +16 MHz */
-	else if (mod1 < 6*FREQ2) rd[7].val = 0x0c; /* +20 MHz */
-	else if (mod1 < 7*FREQ2) rd[7].val = 0x0b; /* +24 MHz */
-	else                     rd[7].val = 0x0a; /* +28 MHz */
-
-	/* 0b - changes every 2/2 MHz */
-	if (mod2 < 2000000) rd[8].val = 0x45;
-	else                rd[8].val = 0x44;
-
-	/* 1a - set frequency: 125 kHz scale (max 3875 kHz)*/
-	tmpval = 0x78; /* byte, overflows intentionally */
-	rd[10].val = tmpval-((mod2/QT1010_STEP)*0x08);
-
-	/* 11 */
-	rd[13].val = 0xfd; /* TODO: correct value calculation */
-
-	/* 12 */
-	rd[14].val = 0x91; /* TODO: correct value calculation */
-
-	/* 22 */
-	if      (freq < 450000000) rd[15].val = 0xd0; /* 450 MHz */
-	else if (freq < 482000000) rd[15].val = 0xd1; /* 482 MHz */
-	else if (freq < 514000000) rd[15].val = 0xd4; /* 514 MHz */
-	else if (freq < 546000000) rd[15].val = 0xd7; /* 546 MHz */
-	else if (freq < 610000000) rd[15].val = 0xda; /* 610 MHz */
-	else                       rd[15].val = 0xd0;
-
-	/* 05 */
-	rd[35].val = (reg05 & 0xf0);
-
-	/* 1f */
-	if      (mod1 <  8000000) tmpval = 0x00;
-	else if (mod1 < 12000000) tmpval = 0x01;
-	else if (mod1 < 16000000) tmpval = 0x02;
-	else if (mod1 < 24000000) tmpval = 0x03;
-	else if (mod1 < 28000000) tmpval = 0x04;
-	else                      tmpval = 0x05;
-	rd[40].val = (priv->reg1f_init_val + 0x0e + tmpval);
-
-	/* 20 */
-	if      (mod1 <  8000000) tmpval = 0x00;
-	else if (mod1 < 12000000) tmpval = 0x01;
-	else if (mod1 < 20000000) tmpval = 0x02;
-	else if (mod1 < 24000000) tmpval = 0x03;
-	else if (mod1 < 28000000) tmpval = 0x04;
-	else                      tmpval = 0x05;
-	rd[41].val = (priv->reg20_init_val + 0x0d + tmpval);
-
-	/* 25 */
-	rd[43].val = priv->reg25_init_val;
-
-	/* 00 */
-	rd[45].val = 0x92; /* TODO: correct value calculation */
-
-	dprintk("freq:%u 05:%02x 07:%02x 09:%02x 0a:%02x 0b:%02x " \
-		"1a:%02x 11:%02x 12:%02x 22:%02x 05:%02x 1f:%02x " \
-		"20:%02x 25:%02x 00:%02x", \
-		freq, rd[2].val, rd[4].val, rd[6].val, rd[7].val, rd[8].val, \
-		rd[10].val, rd[13].val, rd[14].val, rd[15].val, rd[35].val, \
-		rd[40].val, rd[41].val, rd[43].val, rd[45].val);
-
-	for (i = 0; i < ARRAY_SIZE(rd); i++) {
-		if (rd[i].oper == QT1010_WR) {
-			err = qt1010_writereg(priv, rd[i].reg, rd[i].val);
-		} else { /* read is required to proper locking */
-			err = qt1010_readreg(priv, rd[i].reg, &tmpval);
+	for (i = 0; i < len; i++) {
+		switch (data[i].oper) {
+		case QT1010_WRITE:
+			err = qt1010_writereg(priv, data[i].reg, data[i].val);
+			break;
+		case QT1010_READ:
+			err = qt1010_readreg(priv, data[i].reg, &tmpval);
+			break;
+		case QT1010_READLOOP:
+			err = qt1010_readreg_looping(priv, data[i].reg, data[i].val, &tmpval);
+			break;
+		case QT1010_READ22:
+			err = qt1010_readreg(priv, data[i].reg, &tmpval);
+			if(tmpval < 0xff)
+				err = qt1010_writereg(priv, 0x22, tmpval + 1);
+			break;
+		case QT1010_LOOP10:
+			err = qt1010_loop10(priv);
+			break;
 		}
 		if (err) return err;
-	}
-
-	if (debug)
-		qt1010_dump_regs(priv);
+		if (data[i].retval != NULL)
+			*data[i].retval = tmpval;
+	}
 
 	if (fe->ops.i2c_gate_ctrl)
 		fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
@@ -258,156 +157,505 @@ static int qt1010_set_params(struct dvb_
 	return 0;
 }
 
-static int qt1010_init_meas1(struct qt1010_priv *priv,
-			     u8 oper, u8 reg, u8 reg_init_val, u8 *retval)
-{
-	u8 i, val1, val2;
+/* calculates register values needed for tuning to channel */
+static int qt1010_calc_regs(struct dvb_frontend *fe, u8 oper,
+                            chanset_regs_t *chanset)
+{
+	struct qt1010_priv *priv = fe->tuner_priv;
+	u32 f_rf, f_if, f_if1, f_if2, f_lo1, f_lo2, f_lo3;
+	u32 div1, num1a, num1b, div2, num2a, num2b, div3, num3x, div3b;
+	u8 do_band_switch = 0;
+	static u8 previous_oper;
+	f_rf = priv->frequency;
+
+	/* override default IF if needed (~30-60 MHz) */
+	if (priv->cfg->if_freq)
+		f_if = priv->cfg->if_freq;
+	else
+		f_if = 36125000; /* defaults to 36.125 MHz */
+
+	if( oper == QT1010_OPER_BAND) {
+		oper = previous_oper;
+		do_band_switch = 1;
+	} else
+		previous_oper = oper;
+
+	f_if1 = 1232000000;
+	f_lo1 = f_rf + f_if1;
+	div1 = 500000 + f_lo1 / 4;
+	div1 /= 1000000;
+	div1 *= 1000000;
+	num1a = (div1 / 1000000) / 8;
+	num1b = (div1 / 1000000) % 8;	
+	f_if1 = div1 * 4 - f_rf;
+
+	f_lo2 = 920000000;
+	f_if2 = f_if1 - f_lo2;
+	div2 = f_lo2 / 4;
+	div2 /= 1000000;
+	div2 *= 1000000;
+	num2a = (div2 / 1000000) / 8;
+	num2b = (div2 / 1000000) % 8;	
+
+	f_lo3 = f_if2 - f_if;
+	div3 = f_lo3 / 4;
+	div3b = div3 / 1000000;
+	num3x = (500000 + ((div3 - div3b * 1000000) * 256)) / 1000000;
+
+	dprintk("%s: div1:%d num1a:%d num1b:%d div2:%d num2a:%d num2b:%d div3:%d\n",
+	         __FUNCTION__, div1, num1a, num1b, div2, num2a, num2b, div3);
+
+	if (num3x > 255) chanset->reg1a = num3x % 256;
+	else             chanset->reg1a = num3x;
+
+	chanset->reg1c = 137 + (num3x / 256) * 2;
+	chanset->reg0b = div3b;
+
+	if (oper == QT1010_OPER_EA) {
+		switch(num1b) {
+		case 0:
+			chanset->reg1f = 0x09;
+			chanset->reg20 = 0x0a;
+			break;
+		case 1:
+			chanset->reg1f = 0x0a;
+			chanset->reg20 = 0x0a;
+			break;
+		case 2:
+			chanset->reg1f = 0x0a;
+			chanset->reg20 = 0x0b;
+			break;
+		case 3:
+			chanset->reg1f = 0x0b;
+			chanset->reg20 = 0x0c;
+			break;
+		case 4:
+			chanset->reg1f = 0x0c;
+			chanset->reg20 = 0x0c;
+			break;
+		case 5:
+			chanset->reg1f = 0x0d;
+			chanset->reg20 = 0x0d;
+			break;
+		case 6:
+			chanset->reg1f = 0x0d;
+			chanset->reg20 = 0x0d;
+			break;
+		case 7:
+			chanset->reg1f = 0x0f;
+			chanset->reg20 = 0x0e;
+			break;
+		default:
+			chanset->reg1f = 0x00;
+			chanset->reg20 = 0x00;
+			break;
+		}
+	} else if (oper == QT1010_OPER_FF) {
+		switch(num1b) {
+		case 0:
+			chanset->reg1f = 0x16;
+			chanset->reg20 = 0x15;
+			break;
+		case 1:
+			chanset->reg1f = 0x11;
+			chanset->reg20 = 0x0f;
+			break;
+		case 2:
+			chanset->reg1f = 0x11;
+			chanset->reg20 = 0x10;
+			break;
+		case 3:
+			chanset->reg1f = 0x12;
+			chanset->reg20 = 0x11;
+			break;
+		case 4:
+			chanset->reg1f = 0x13;
+			chanset->reg20 = 0x12;
+			break;
+		case 5:
+			chanset->reg1f = 0x14;
+			chanset->reg20 = 0x13;
+			break;
+		case 6:
+			chanset->reg1f = 0x15;
+			chanset->reg20 = 0x13;
+			break;
+		case 7:
+			chanset->reg1f = 0x16;
+			chanset->reg20 = 0x14;
+			break;
+		default:
+			chanset->reg1f = 0x00;
+			chanset->reg20 = 0x00;
+			break;
+		}
+	} else {
+		switch(num1b) {
+		case 0:
+			chanset->reg1f = 0x10;
+			chanset->reg20 = 0x0f;
+			break;
+		case 1:
+			chanset->reg1f = 0x11;
+			chanset->reg20 = 0x0f;
+			break;
+		case 2:
+			chanset->reg1f = 0x11;
+			chanset->reg20 = 0x10;
+			break;
+		case 3:
+			chanset->reg1f = 0x12;
+			chanset->reg20 = 0x11;
+			break;
+		case 4:
+			chanset->reg1f = 0x13;
+			chanset->reg20 = 0x12;
+			break;
+		case 5:
+			chanset->reg1f = 0x0d;
+			chanset->reg20 = 0x0d;
+			break;
+		case 6:
+			chanset->reg1f = 0x0d;
+			chanset->reg20 = 0x0d;
+			break;
+		case 7:
+			chanset->reg1f = 0x0f;
+			chanset->reg20 = 0x0e;
+			break;
+		default:
+			chanset->reg1f = 0x00;
+			chanset->reg20 = 0x00;
+			break;
+		}
+	}
+	chanset->reg1f += priv->init.reg1f;
+	chanset->reg20 += priv->init.reg20;
+
+	div1 /= 1000000;
+	if (oper == QT1010_OPER_EA) {
+		if(num1b > 0) div1 += (8 - num1b);
+		else          div1 += 8;
+	} else if(oper == QT1010_OPER_FF) {
+		if(num1b > 0) div1 -= num1b;
+		else          div1 -= 8;
+	} else {
+		if(num1b > 4) div1 += (8 - num1b);
+		else          div1 -= num1b;
+	}
+	div1 *= 1000000;
+
+	f_if1 = div1 * 4 - (f_rf / 1000000) * 1000000;
+	f_lo1 = f_rf + f_if1;
+	f_lo2 = f_if1 - f_if2;
+	div2 = f_lo2 / 4;
+	num1a = (div1 / 1000000) / 8;
+	num1b = (div1 / 1000000) % 8;
+	num2a = (div2 / 1000000) / 8;
+	num2b = (div2 / 1000000) % 8;
+
+	chanset->reg07 = num1a;
+	chanset->reg08 = num1b + 8;
+	chanset->reg09 = num2a;
+	chanset->reg0a = num2b + 8;
+
+	dprintk("%s: div1:%d num1a:%d num1b:%d div2:%d num2a:%d num2b:%d div3:%d\n",
+	         __FUNCTION__, div1, num1a, num1b, div2, num2a, num2b, div3);
+
+	/* band setting */
+	if      (f_lo1 < 1600000000) chanset->reg05 = 0x14;
+	else if (f_lo1 < 1856000000) chanset->reg05 = 0x34;
+	else if (f_lo1 < 2080000000) chanset->reg05 = 0x54;
+	else                         chanset->reg05 = 0x74;
+
+	switch((f_lo1 / 1000000)) {
+	case 1568: chanset->reg22 = priv->init.reg22_1; break;
+	case 1600: chanset->reg22 = priv->init.reg22_2; break;
+	case 1632: chanset->reg22 = priv->init.reg22_3; break;
+	case 1664: chanset->reg22 = priv->init.reg22_4; break;
+	case 1696: chanset->reg22 = priv->init.reg22_5; break;
+	case 1728: chanset->reg22 = priv->init.reg22_6; break;
+	case 1760: chanset->reg22 = priv->init.reg22_7; break;
+	case 1792: chanset->reg22 = priv->init.reg22_8; break;
+	case 1824: chanset->reg22 = priv->init.reg22_9; break;
+	default:   chanset->reg22 = 0xd0; break;
+	}
+
+	if (chanset->reg05 == 0x34) {
+		if (chanset->reg22 < 0xf0)
+			chanset->reg22 = 0xd0;
+		else if (chanset->reg22 > 0xfa)
+			chanset->reg22 = 0xda;
+		else
+			chanset->reg22 -= 0x20;
+	} else
+		chanset->reg22 = 0xd0;
+
+	if (do_band_switch)
+		if (chanset->oper_reg05 < 0x74) /* 0x14 or 0x34 or 0x54 */
+			chanset->reg05 = chanset->oper_reg05 + 0x20; /* 0x14 => 0x34 => 0x54 => 0x74 */
+
+	chanset->reg11 = 0xfd;
+#if 0
+	/* MSI Megasky 580 gl861 does this */
+	if(chanset->reg05 < 0x54)
+		chanset->reg11 = 0xfd;
+	else
+		chanset->reg11 = 0xf9;
+#endif
+#if 1
+	dprintk("%s: %d 05:%02x 07:%02x 08:%02x 09:%02x 0a:%02x " \
+	        "0b:%02x 1a:%02x 1c:%02x 22:%02x 1f:%02x 20:%02x 11:%02x\n", \
+	        __FUNCTION__, f_rf, chanset->reg05, chanset->reg07, chanset->reg08, \
+	        chanset->reg09, chanset->reg0a, chanset->reg0b, chanset->reg1a, \
+	        chanset->reg1c, chanset->reg22, chanset->reg1f, chanset->reg20, \
+	        chanset->reg11);
+#endif
+	return 0;
+}
+
+static int qt1010_chanset(struct dvb_frontend *fe,
+                          struct dvb_frontend_parameters *params,
+                          chanset_regs_t *chanset, u8 oper)
+{
+	struct qt1010_priv *priv = fe->tuner_priv;
+	int err = qt1010_calc_regs(fe, oper, chanset);
+	qt1010_i2c_oper_t data[] = {
+		{ QT1010_WRITE,    0x01, 0x80, NULL },
+		{ QT1010_WRITE,    0x02, 0x3f, NULL },
+		{ QT1010_WRITE,    0x05, chanset->reg05, NULL },
+		{ QT1010_WRITE,    0x06, 0x44, NULL },
+		{ QT1010_WRITE,    0x07, chanset->reg07, NULL },
+		{ QT1010_WRITE,    0x08, chanset->reg08, NULL },
+		{ QT1010_WRITE,    0x09, chanset->reg09, NULL },
+		{ QT1010_WRITE,    0x0a, chanset->reg0a, NULL },
+		{ QT1010_WRITE,    0x0b, chanset->reg0b, NULL },
+		{ QT1010_WRITE,    0x0c, 0xe1, NULL },
+		{ QT1010_WRITE,    0x1a, chanset->reg1a, NULL },
+		{ QT1010_WRITE,    0x1b, 0x00, NULL },
+		{ QT1010_WRITE,    0x1c, chanset->reg1c, NULL },
+		{ QT1010_WRITE,    0x11, chanset->reg11, NULL },
+		{ QT1010_LOOP10,   NA  , NA  , NULL },
+		{ QT1010_WRITE,    0x12, 0x95, NULL },
+		{ QT1010_WRITE,    0x22, chanset->reg22, NULL },
+		{ QT1010_WRITE,    0x1e, 0x00, NULL },
+		{ QT1010_WRITE,    0x1e, 0xd0, NULL },
+		{ QT1010_READ22,   0x22, NA  , NULL },
+		{ QT1010_WRITE,    0x1e, 0x00, NULL },
+		{ QT1010_READ,     0x05, NA  , &chanset->oper_reg05 },
+		{ QT1010_READ,     0x22, NA  , &chanset->oper_reg22 },
+		{ QT1010_WRITE,    0x23, 0xd0, NULL },
+		{ QT1010_WRITE,    0x1e, 0x00, NULL },
+		{ QT1010_WRITE,    0x1e, 0xe0, NULL },
+		{ QT1010_READLOOP, 0x23, 0x20, &chanset->oper_reg23 },
+		{ QT1010_WRITE,    0x1e, 0x00, NULL },
+		{ QT1010_WRITE,    0x24, 0xd0, NULL },
+		{ QT1010_WRITE,    0x1e, 0x00, NULL },
+		{ QT1010_WRITE,    0x1e, 0xf0, NULL },
+		{ QT1010_READLOOP, 0x24, 0x20, NULL },
+		{ QT1010_WRITE,    0x1e, 0x00, NULL },
+		{ QT1010_WRITE,    0x14, 0x7f, NULL },
+		{ QT1010_WRITE,    0x15, 0x7f, NULL },
+		{ QT1010_WRITE,    0x05, chanset->reg05 - 0x04, NULL },
+		{ QT1010_WRITE,    0x06, 0x00, NULL },
+		{ QT1010_WRITE,    0x15, 0x1f, NULL },
+		{ QT1010_WRITE,    0x16, 0xff, NULL },
+		{ QT1010_WRITE,    0x18, 0xff, NULL },
+		{ QT1010_WRITE,    0x1f, chanset->reg1f, NULL },
+		{ QT1010_WRITE,    0x20, chanset->reg20, NULL },
+		{ QT1010_WRITE,    0x21, priv->init.reg21, NULL },
+		{ QT1010_WRITE,    0x25, priv->init.reg25, NULL },
+		{ QT1010_WRITE,    0x26, priv->init.reg26, NULL },
+		{ QT1010_WRITE,    0x00, 0x81, NULL },
+		{ QT1010_WRITE,    0x02, 0x00, NULL },
+		{ QT1010_WRITE,    0x01, 0x00, NULL }
+	};
+
+	if (err) return err;
+
+#if 0
+	dprintk("%s:   %d 05:%02x 07:%02x 08:%02x 09:%02x 0a:%02x 0b:%02x " \
+	        "1a:%02x 1c:%02x 22:%02x 1f:%02x 20:%02x 11:%02x 05:%02x 25:%02x\n", \
+	        __FUNCTION__, priv->frequency, data[2].val, data[4].val, \
+	        data[5].val, data[6].val, data[7].val, data[8].val, data[10].val, \
+	        data[12].val, data[16].val, data[40].val, data[41].val, \
+	        data[13].val, data[35].val, data[43].val);
+#endif
+	return qt1010_handle_i2c_oper_table(fe, data, ARRAY_SIZE(data));
+}
+
+static int qt1010_set_params(struct dvb_frontend *fe,
+                             struct dvb_frontend_parameters *params)
+{
+	struct qt1010_priv *priv = fe->tuner_priv;
 	int err;
-
-	qt1010_i2c_oper_t i2c_data[] = {
-		{ QT1010_WR, reg, reg_init_val },
-		{ QT1010_WR, 0x1e, 0x00 },
-		{ QT1010_WR, 0x1e, oper },
-		{ QT1010_RD, reg, 0xff }
+	chanset_regs_t chanset;
+	priv->frequency = (params->frequency / QT1010_STEP) * QT1010_STEP;
+	priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
+
+	err = qt1010_chanset(fe, params, &chanset, QT1010_OPER_NORMAL);
+	if (chanset.oper_reg23 <= 0xea && !err)
+		err = qt1010_chanset(fe, params, &chanset, QT1010_OPER_EA);
+	if (chanset.oper_reg23 == 0xff && !err)
+		err = qt1010_chanset(fe, params, &chanset, QT1010_OPER_FF);
+	if (chanset.oper_reg22 == 0xff && !err)
+		err = qt1010_chanset(fe, params, &chanset, QT1010_OPER_BAND);
+
+	return err;
+}
+
+static int qt1010_init(struct dvb_frontend *fe)
+{
+	int err;
+	struct qt1010_priv *priv = fe->tuner_priv;
+	qt1010_i2c_oper_t data[] = {
+		{ QT1010_WRITE,    0x01, 0x80, NULL },
+		{ QT1010_WRITE,    0x0d, 0x84, NULL },
+		{ QT1010_WRITE,    0x0e, 0xb7, NULL },
+//		{ QT1010_WRITE,    0x0e, 0xb4, NULL },
+		{ QT1010_WRITE,    0x2a, 0x23, NULL },
+		{ QT1010_WRITE,    0x2c, 0xdc, NULL },
+		{ QT1010_WRITE,    0x25, 0x40, NULL },
+		{ QT1010_WRITE,    0x1e, 0x00, NULL },
+		{ QT1010_WRITE,    0x1e, 0x81, NULL },
+		{ QT1010_READLOOP, 0x25, 0x80, &priv->init.reg25 },
+		{ QT1010_WRITE,    0x1e, 0x00, NULL },
+		{ QT1010_WRITE,    0x2a, 0x23, NULL },
+		{ QT1010_WRITE,    0x2b, 0x70, NULL },
+		{ QT1010_WRITE,    0x26, 0x08, NULL },
+		{ QT1010_WRITE,    0x1e, 0x00, NULL },
+		{ QT1010_WRITE,    0x1e, 0x82, NULL },
+		{ QT1010_READLOOP, 0x26, 0x10, &priv->init.reg26 },
+		{ QT1010_WRITE,    0x1e, 0x00, NULL },
+		{ QT1010_WRITE,    0x05, 0x14, NULL },
+		{ QT1010_WRITE,    0x06, 0x44, NULL },
+		{ QT1010_WRITE,    0x07, 0x28, NULL },
+		{ QT1010_WRITE,    0x08, 0x0b, NULL },
+		{ QT1010_WRITE,    0x11, 0xf9, NULL },
+		{ QT1010_LOOP10,   NA  , NA  , NULL },
+		{ QT1010_WRITE,    0x22, 0x0d, NULL },
+		{ QT1010_WRITE,    0x1e, 0x00, NULL },
+		{ QT1010_WRITE,    0x1e, 0xd0, NULL },
+		{ QT1010_READLOOP, 0x22, 0x20, NULL },
+		{ QT1010_WRITE,    0x1e, 0x00, NULL },
+		{ QT1010_WRITE,    0x06, 0x40, NULL },
+		{ QT1010_WRITE,    0x16, 0xf0, NULL },
+		{ QT1010_WRITE,    0x02, 0x38, NULL },
+		{ QT1010_WRITE,    0x03, 0x18, NULL },
+		{ QT1010_WRITE,    0x1f, 0x20, NULL },
+		{ QT1010_WRITE,    0x20, 0xe0, NULL },
+		{ QT1010_WRITE,    0x1e, 0x00, NULL },
+		{ QT1010_WRITE,    0x1e, 0x84, NULL },
+		{ QT1010_READLOOP, 0x1f, 0x40, &priv->init.reg1f },
+		{ QT1010_READ,     0x20, NA  , &priv->init.reg20 },
+		{ QT1010_WRITE,    0x1e, 0x00, NULL },
+		{ QT1010_WRITE,    0x03, 0x19, NULL },
+		{ QT1010_WRITE,    0x02, 0x3f, NULL },
+		{ QT1010_WRITE,    0x21, 0x53, NULL },
+		{ QT1010_READ,     0x21, NA  , &priv->init.reg21 },
+		{ QT1010_WRITE,    0x11, 0xfd, NULL },
+		{ QT1010_WRITE,    0x05, 0x34, NULL },
+		{ QT1010_WRITE,    0x06, 0x44, NULL },
+		{ QT1010_WRITE,    0x07, 0x31, NULL },
+		{ QT1010_WRITE,    0x08, 0x08, NULL },
+		{ QT1010_WRITE,    0x22, 0xd0, NULL },
+		{ QT1010_WRITE,    0x1e, 0x00, NULL },
+		{ QT1010_WRITE,    0x1e, 0xd0, NULL },
+		{ QT1010_READLOOP, 0x22, 0x20, NULL },
+		{ QT1010_WRITE,    0x1e, 0x00, NULL },
+		{ QT1010_READ,     0x22, NA  , &priv->init.reg22_1 },
+		{ QT1010_WRITE,    0x07, 0x32, NULL },
+		{ QT1010_WRITE,    0x22, 0xd0, NULL },
+		{ QT1010_WRITE,    0x1e, 0x00, NULL },
+		{ QT1010_WRITE,    0x1e, 0xd0, NULL },
+		{ QT1010_READLOOP, 0x22, 0x20, NULL },
+		{ QT1010_WRITE,    0x1e, 0x00, NULL },
+		{ QT1010_READ,     0x22, NA  , &priv->init.reg22_2 },
+		{ QT1010_WRITE,    0x07, 0x33, NULL },
+		{ QT1010_WRITE,    0x22, 0xd0, NULL },
+		{ QT1010_WRITE,    0x1e, 0x00, NULL },
+		{ QT1010_WRITE,    0x1e, 0xd0, NULL },
+		{ QT1010_READLOOP, 0x22, 0x20, NULL },
+		{ QT1010_WRITE,    0x1e, 0x00, NULL },
+		{ QT1010_READ,     0x22, NA  , &priv->init.reg22_3 },
+		{ QT1010_WRITE,    0x07, 0x34, NULL },
+		{ QT1010_WRITE,    0x22, 0xd0, NULL },
+		{ QT1010_WRITE,    0x1e, 0x00, NULL },
+		{ QT1010_WRITE,    0x1e, 0xd0, NULL },
+		{ QT1010_READLOOP, 0x22, 0x20, NULL },
+		{ QT1010_WRITE,    0x1e, 0x00, NULL },
+		{ QT1010_READ,     0x22, NA  , &priv->init.reg22_4 },
+		{ QT1010_WRITE,    0x07, 0x35, NULL },
+		{ QT1010_WRITE,    0x22, 0xd0, NULL },
+		{ QT1010_WRITE,    0x1e, 0x00, NULL },
+		{ QT1010_WRITE,    0x1e, 0xd0, NULL },
+		{ QT1010_READLOOP, 0x22, 0x20, NULL },
+		{ QT1010_WRITE,    0x1e, 0x00, NULL },
+		{ QT1010_READ,     0x22, NA  , &priv->init.reg22_5 },
+		{ QT1010_WRITE,    0x07, 0x36, NULL },
+		{ QT1010_WRITE,    0x22, 0xd0, NULL },
+		{ QT1010_WRITE,    0x1e, 0x00, NULL },
+		{ QT1010_WRITE,    0x1e, 0xd0, NULL },
+		{ QT1010_READLOOP, 0x22, 0x20, NULL },
+		{ QT1010_WRITE,    0x1e, 0x00, NULL },
+		{ QT1010_READ,     0x22, NA  , &priv->init.reg22_6 },
+		{ QT1010_WRITE,    0x07, 0x37, NULL },
+		{ QT1010_WRITE,    0x22, 0xd0, NULL },
+		{ QT1010_WRITE,    0x1e, 0x00, NULL },
+		{ QT1010_WRITE,    0x1e, 0xd0, NULL },
+		{ QT1010_READLOOP, 0x22, 0x20, NULL },
+		{ QT1010_WRITE,    0x1e, 0x00, NULL },
+		{ QT1010_READ,     0x22, NA  , &priv->init.reg22_7 },
+		{ QT1010_WRITE,    0x07, 0x38, NULL },
+		{ QT1010_WRITE,    0x22, 0xd0, NULL },
+		{ QT1010_WRITE,    0x1e, 0x00, NULL },
+		{ QT1010_WRITE,    0x1e, 0xd0, NULL },
+		{ QT1010_READLOOP, 0x22, 0x20, NULL },
+		{ QT1010_WRITE,    0x1e, 0x00, NULL },
+		{ QT1010_READ,     0x22, NA  , &priv->init.reg22_8 },
+		{ QT1010_WRITE,    0x07, 0x39, NULL },
+		{ QT1010_WRITE,    0x22, 0xd0, NULL },
+		{ QT1010_WRITE,    0x1e, 0x00, NULL },
+		{ QT1010_WRITE,    0x1e, 0xd0, NULL },
+		{ QT1010_READLOOP, 0x22, 0x20, NULL },
+		{ QT1010_WRITE,    0x1e, 0x00, NULL },
+		{ QT1010_READ,     0x22, NA  , &priv->init.reg22_9 }
 	};
 
-	for (i = 0; i < ARRAY_SIZE(i2c_data); i++) {
-		if (i2c_data[i].oper == QT1010_WR) {
-			err = qt1010_writereg(priv, i2c_data[i].reg,
-					      i2c_data[i].val);
-		} else {
-			err = qt1010_readreg(priv, i2c_data[i].reg, &val2);
-		}
-		if (err) return err;
-	}
-
-	do {
-		val1 = val2;
-		err = qt1010_readreg(priv, reg, &val2);
-		if (err) return err;
-		dprintk("compare reg:%02x %02x %02x", reg, val1, val2);
-	} while (val1 != val2);
-	*retval = val1;
-
-	return qt1010_writereg(priv, 0x1e, 0x00);
-}
-
-static u8 qt1010_init_meas2(struct qt1010_priv *priv,
-			    u8 reg_init_val, u8 *retval)
-{
-	u8 i, val;
-	int err;
-	qt1010_i2c_oper_t i2c_data[] = {
-		{ QT1010_WR, 0x07, reg_init_val },
-		{ QT1010_WR, 0x22, 0xd0 },
-		{ QT1010_WR, 0x1e, 0x00 },
-		{ QT1010_WR, 0x1e, 0xd0 },
-		{ QT1010_RD, 0x22, 0xff },
-		{ QT1010_WR, 0x1e, 0x00 },
-		{ QT1010_WR, 0x22, 0xff }
+	err = qt1010_handle_i2c_oper_table(fe, data, ARRAY_SIZE(data));
+
+#if 1
+	dprintk("%s: 1f:%02x 20:%02x 21:%02x 25:%02x 26:%02x " \
+	        "22_1:%02x 22_2:%02x 22_3:%02x 22_4:%02x 22_5:%02x " \
+	        "22_6:%02x 22_7:%02x 22_8:%02x 22_9:%02x\n", \
+	        __FUNCTION__, priv->init.reg1f, priv->init.reg20, priv->init.reg21, \
+	        priv->init.reg25, priv->init.reg26, priv->init.reg22_1, \
+	        priv->init.reg22_2, priv->init.reg22_3, priv->init.reg22_4, \
+	        priv->init.reg22_5, priv->init.reg22_6, priv->init.reg22_7, \
+	        priv->init.reg22_8, priv->init.reg22_9);
+#endif
+	return err;
+}
+
+static int qt1010_sleep(struct dvb_frontend *fe)
+{
+	qt1010_i2c_oper_t data[] = {
+		{ QT1010_WRITE,    0x01, 0x80, NULL },
+		{ QT1010_WRITE,    0x02, 0x7f, NULL },
+		{ QT1010_READ,     0x05, NA  , NULL },
+		{ QT1010_WRITE,    0x05, 0x01, NULL },
+		{ QT1010_WRITE,    0x06, 0xff, NULL },
+		{ QT1010_WRITE,    0x01, 0x00, NULL }
 	};
-	for (i = 0; i < ARRAY_SIZE(i2c_data); i++) {
-		if (i2c_data[i].oper == QT1010_WR) {
-			err = qt1010_writereg(priv, i2c_data[i].reg,
-					      i2c_data[i].val);
-		} else {
-			err = qt1010_readreg(priv, i2c_data[i].reg, &val);
-		}
-		if (err) return err;
-	}
-	*retval = val;
-	return 0;
-}
-
-static int qt1010_init(struct dvb_frontend *fe)
-{
-	struct qt1010_priv *priv = fe->tuner_priv;
-	struct dvb_frontend_parameters params;
-	int err = 0;
-	u8 i, tmpval, *valptr = NULL;
-
-	qt1010_i2c_oper_t i2c_data[] = {
-		{ QT1010_WR, 0x01, 0x80 },
-		{ QT1010_WR, 0x0d, 0x84 },
-		{ QT1010_WR, 0x0e, 0xb7 },
-		{ QT1010_WR, 0x2a, 0x23 },
-		{ QT1010_WR, 0x2c, 0xdc },
-		{ QT1010_M1, 0x25, 0x40 }, /* get reg 25 init value */
-		{ QT1010_M1, 0x81, 0xff }, /* get reg 25 init value */
-		{ QT1010_WR, 0x2b, 0x70 },
-		{ QT1010_WR, 0x2a, 0x23 },
-		{ QT1010_M1, 0x26, 0x08 },
-		{ QT1010_M1, 0x82, 0xff },
-		{ QT1010_WR, 0x05, 0x14 },
-		{ QT1010_WR, 0x06, 0x44 },
-		{ QT1010_WR, 0x07, 0x28 },
-		{ QT1010_WR, 0x08, 0x0b },
-		{ QT1010_WR, 0x11, 0xfd },
-		{ QT1010_M1, 0x22, 0x0d },
-		{ QT1010_M1, 0xd0, 0xff },
-		{ QT1010_WR, 0x06, 0x40 },
-		{ QT1010_WR, 0x16, 0xf0 },
-		{ QT1010_WR, 0x02, 0x38 },
-		{ QT1010_WR, 0x03, 0x18 },
-		{ QT1010_WR, 0x20, 0xe0 },
-		{ QT1010_M1, 0x1f, 0x20 }, /* get reg 1f init value */
-		{ QT1010_M1, 0x84, 0xff }, /* get reg 1f init value */
-		{ QT1010_RD, 0x20, 0x20 }, /* get reg 20 init value */
-		{ QT1010_WR, 0x03, 0x19 },
-		{ QT1010_WR, 0x02, 0x3f },
-		{ QT1010_WR, 0x21, 0x53 },
-		{ QT1010_RD, 0x21, 0xff },
-		{ QT1010_WR, 0x11, 0xfd },
-		{ QT1010_WR, 0x05, 0x34 },
-		{ QT1010_WR, 0x06, 0x44 },
-		{ QT1010_WR, 0x08, 0x08 }
-	};
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
-
-	for (i = 0; i < ARRAY_SIZE(i2c_data); i++) {
-		switch (i2c_data[i].oper) {
-		case QT1010_WR:
-			err = qt1010_writereg(priv, i2c_data[i].reg,
-					      i2c_data[i].val);
-			break;
-		case QT1010_RD:
-			if (i2c_data[i].val == 0x20)
-				valptr = &priv->reg20_init_val;
-			else
-				valptr = &tmpval;
-			err = qt1010_readreg(priv, i2c_data[i].reg, valptr);
-			break;
-		case QT1010_M1:
-			if (i2c_data[i].val == 0x25)
-				valptr = &priv->reg25_init_val;
-			else if (i2c_data[i].val == 0x1f)
-				valptr = &priv->reg1f_init_val;
-			else
-				valptr = &tmpval;
-			err = qt1010_init_meas1(priv, i2c_data[i+1].reg,
-						i2c_data[i].reg,
-						i2c_data[i].val, valptr);
-			i++;
-			break;
-		}
-		if (err) return err;
-	}
-
-	for (i = 0x31; i < 0x3a; i++) /* 0x31 - 0x39 */
-		if ((err = qt1010_init_meas2(priv, i, &tmpval)))
-			return err;
-
-	params.frequency = 545000000; /* Sigmatek DVB-110 545000000 */
-				      /* MSI Megasky 580 GL861 533000000 */
-	return qt1010_set_params(fe, &params);
+	return qt1010_handle_i2c_oper_table(fe, data, ARRAY_SIZE(data));
 }
 
 static int qt1010_release(struct dvb_frontend *fe)
 {
-	kfree(fe->tuner_priv);
-	fe->tuner_priv = NULL;
+	if (fe != NULL) {
+		kfree(fe->tuner_priv);
+		fe->tuner_priv = NULL;
+	}
 	return 0;
 }
 
@@ -435,8 +683,7 @@ static const struct dvb_tuner_ops qt1010
 
 	.release       = qt1010_release,
 	.init          = qt1010_init,
-	/* TODO: implement sleep */
-
+	.sleep         = qt1010_sleep,
 	.set_params    = qt1010_set_params,
 	.get_frequency = qt1010_get_frequency,
 	.get_bandwidth = qt1010_get_bandwidth
diff -r 214a42e5076f linux/drivers/media/dvb/frontends/qt1010.h
--- a/linux/drivers/media/dvb/frontends/qt1010.h	Tue May 08 23:36:40 2007 +0300
+++ b/linux/drivers/media/dvb/frontends/qt1010.h	Wed Jun 13 23:33:42 2007 +0300
@@ -25,7 +25,8 @@
 #include "dvb_frontend.h"
 
 struct qt1010_config {
-	u8 i2c_address;
+	u8  i2c_address;
+	u32 if_freq; /* defaults to 36.125 MHz */
 };
 
 /**
diff -r 214a42e5076f linux/drivers/media/dvb/frontends/qt1010_priv.h
--- a/linux/drivers/media/dvb/frontends/qt1010_priv.h	Tue May 08 23:36:40 2007 +0300
+++ b/linux/drivers/media/dvb/frontends/qt1010_priv.h	Wed Jun 13 23:33:42 2007 +0300
@@ -30,20 +30,20 @@ 02  00  ?
 02  00  ?
 03  19  ?
 04  00  ?
-05  00  ? maybe band selection
+05  00  band selection
 06  00  ?
 07  2b  set frequency: 32 MHz scale, n*32 MHz
-08  0b  ?
-09  10  ? changes every 8/24 MHz; values 1d/1c
+08  0b  set frequency
+09  10  set frequency
 0a  08  set frequency: 4 MHz scale, n*4 MHz
-0b  41  ? changes every 2/2 MHz; values 45/45
+0b  41  set frequency
 0c  e1  ?
 0d  94  ?
 0e  b6  ?
 0f  2c  ?
 10  10  ?
-11  f1  ? maybe device specified adjustment
-12  11  ? maybe device specified adjustment
+11  f1  clock
+12  11  ? P3
 13  3f  ?
 14  1f  ?
 15  3f  ?
@@ -53,17 +53,17 @@ 19  80  ?
 19  80  ?
 1a  d0  set frequency: 125 kHz scale, n*125 kHz
 1b  00  ?
-1c  89  ?
+1c  89  set frequency
 1d  00  ?
 1e  00  ? looks like operation register; write cmd here, read result from 1f-26
-1f  20  ? chip initialization
-20  e0  ? chip initialization
-21  20  ?
-22  d0  ?
-23  d0  ?
-24  d0  ?
-25  40  ? chip initialization
-26  08  ?
+1f  20  chip initialization / calibration
+20  e0  chip initialization / calibration
+21  20  chip initialization / calibration
+22  d0  ? used when tuning to freq
+23  d0  ? used when tuning to freq
+24  d0  ? chip initialization / calibration
+25  40  chip initialization / calibration
+26  08  chip initialization / calibration
 27  29  ?
 28  55  ?
 29  39  ?
@@ -75,28 +75,71 @@ 2f  00  ? not used?
 2f  00  ? not used?
 */
 
-#define QT1010_STEP         125000 /*  125 kHz used by Windows drivers,
-				      hw could be more precise but we don't
-				      know how to use */
+#define QT1010_STEP         125000 /*  125 kHz */
 #define QT1010_MIN_FREQ   48000000 /*   48 MHz */
 #define QT1010_MAX_FREQ  860000000 /*  860 MHz */
 #define QT1010_OFFSET   1246000000 /* 1246 MHz */
 
-#define QT1010_WR 0
-#define QT1010_RD 1
-#define QT1010_M1 3
+
+enum qt1010_constants {
+	QT1010_READ,
+	QT1010_WRITE,
+	QT1010_READLOOP,
+	QT1010_LOOP10,
+	QT1010_READ22,
+
+	QT1010_OPER_NORMAL,
+	QT1010_OPER_EA,
+	QT1010_OPER_FF,
+	QT1010_OPER_BAND,
+
+	NA
+};
 
 typedef struct {
-	u8 oper, reg, val;
+	u8 oper, reg, val, *retval;
 } qt1010_i2c_oper_t;
+
+typedef struct {
+	u8 reg1f;
+	u8 reg20;
+	u8 reg21;
+	u8 reg25;
+	u8 reg26;
+	u8 reg22_1;
+	u8 reg22_2;
+	u8 reg22_3;
+	u8 reg22_4;
+	u8 reg22_5;
+	u8 reg22_6;
+	u8 reg22_7;
+	u8 reg22_8;
+	u8 reg22_9;
+} init_regs_t;
+
+typedef struct {
+	u8 reg05;
+	u8 reg07;
+	u8 reg08;
+	u8 reg09;
+	u8 reg0a;
+	u8 reg0b;
+	u8 reg1a;
+	u8 reg1c;
+	u8 reg22;
+	u8 reg1f;
+	u8 reg20;
+	u8 reg11;
+	u8 oper_reg05;
+	u8 oper_reg22;
+	u8 oper_reg23;
+} chanset_regs_t;
 
 struct qt1010_priv {
 	struct qt1010_config *cfg;
 	struct i2c_adapter   *i2c;
 
-	u8 reg1f_init_val;
-	u8 reg20_init_val;
-	u8 reg25_init_val;
+	init_regs_t    init;
 
 	u32 frequency;
 	u32 bandwidth;
diff -r 214a42e5076f linux/drivers/media/dvb/frontends/zl10353.c
--- a/linux/drivers/media/dvb/frontends/zl10353.c	Tue May 08 23:36:40 2007 +0300
+++ b/linux/drivers/media/dvb/frontends/zl10353.c	Wed Jun 13 23:33:42 2007 +0300
@@ -123,106 +123,84 @@ static void zl10353_dump_regs(struct dvb
 }
 #endif
 
-static void zl10353_calc_nominal_rate(struct dvb_frontend *fe,
-				      enum fe_bandwidth bandwidth,
-				      u16 *nominal_rate)
-{
-	u32 adc_clock = 22528; /* 20.480 MHz on the board(!?) */
-	u8 bw;
-	struct zl10353_state *state = fe->demodulator_priv;
-
-	if (state->config.adc_clock)
-		adc_clock = state->config.adc_clock;
-
-	switch (bandwidth) {
+static int zl10353_sleep(struct dvb_frontend *fe)
+{
+	static u8 zl10353_softdown[] = { CONFIG, 0x0C, 0x44 };
+	zl10353_write(fe, zl10353_softdown, sizeof(zl10353_softdown));
+	return 0;
+}
+
+static int zl10353_set_parameters(struct dvb_frontend *fe,
+				  struct dvb_frontend_parameters *param)
+{
+	struct zl10353_state *state = fe->demodulator_priv;
+	struct dvb_ofdm_parameters *op = &param->u.ofdm;
+	u16 nominal_rate;
+	u8 bw, bw_ctrl;
+	u8 pllbuf[6] = { 0x67 };
+	u32 adc_clock = 20480; /* default 20.480 MHz */
+
+	switch (op->bandwidth) {
 	case BANDWIDTH_6_MHZ:
 		bw = 6;
+		bw_ctrl = 0x34;
 		break;
 	case BANDWIDTH_7_MHZ:
 		bw = 7;
+		bw_ctrl = 0x35;
 		break;
 	case BANDWIDTH_8_MHZ:
 	default:
 		bw = 8;
+		bw_ctrl = 0x36;
 		break;
 	}
 
-	*nominal_rate = (64 * bw * (1<<16) / (7 * 8) * 4000 / adc_clock + 2) / 4;
-
+	if (state->config.adc_clock)
+		adc_clock = state->config.adc_clock;
+
+	nominal_rate = (64 * bw * (1<<16) / (7 * 8) * 4000 / (adc_clock + 2048) + 2) / 4;
 	dprintk("%s: bw %d, adc_clock %d => 0x%x\n",
-		__FUNCTION__, bw, adc_clock, *nominal_rate);
-}
-
-static int zl10353_sleep(struct dvb_frontend *fe)
-{
-	static u8 zl10353_softdown[] = { 0x50, 0x0C, 0x44 };
-
-	zl10353_write(fe, zl10353_softdown, sizeof(zl10353_softdown));
-	return 0;
-}
-
-static int zl10353_set_parameters(struct dvb_frontend *fe,
-				  struct dvb_frontend_parameters *param)
-{
-	struct zl10353_state *state = fe->demodulator_priv;
-	u16 nominal_rate;
-	u8 pllbuf[6] = { 0x67 };
-
-	/* These settings set "auto-everything" and start the FSM. */
-	zl10353_single_write(fe, 0x55, 0x80);
-	udelay(200);
-	zl10353_single_write(fe, 0xEA, 0x01);
-	udelay(200);
-	zl10353_single_write(fe, 0xEA, 0x00);
-
-	zl10353_single_write(fe, 0x56, 0x28);
-	zl10353_single_write(fe, 0x89, 0x20);
-	zl10353_single_write(fe, 0x5E, 0x00);
-
-	zl10353_calc_nominal_rate(fe, param->u.ofdm.bandwidth, &nominal_rate);
+		__FUNCTION__, bw, adc_clock, nominal_rate);
+
+	zl10353_single_write(fe, BW_CTL, bw_ctrl);
 	zl10353_single_write(fe, TRL_NOMINAL_RATE_1, msb(nominal_rate));
 	zl10353_single_write(fe, TRL_NOMINAL_RATE_0, lsb(nominal_rate));
 
-	zl10353_single_write(fe, 0x6C, 0xCD);
-	zl10353_single_write(fe, 0x6D, 0x7E);
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0);
-
-	// if there is no attached secondary tuner, we call set_params to program
-	// a potential tuner attached somewhere else
+	/* if there is no attached secondary tuner, we call set_params to program
+	   a potential tuner attached somewhere else */
 	if (state->config.no_tuner) {
 		if (fe->ops.tuner_ops.set_params) {
 			fe->ops.tuner_ops.set_params(fe, param);
-			if (fe->ops.i2c_gate_ctrl)
-				fe->ops.i2c_gate_ctrl(fe, 0);
 		}
-	}
-
-	// if pllbuf is defined, retrieve the settings
-	if (fe->ops.tuner_ops.calc_regs) {
-		fe->ops.tuner_ops.calc_regs(fe, param, pllbuf+1, 5);
-		pllbuf[1] <<= 1;
+		zl10353_single_write(fe, FSM_GO, 0x01);
+		udelay(250);
 	} else {
-		// fake pllbuf settings
-		pllbuf[1] = 0x61 << 1;
-		pllbuf[2] = 0;
-		pllbuf[3] = 0;
-		pllbuf[3] = 0;
-		pllbuf[4] = 0;
-	}
-
-	// there is no call to _just_ start decoding, so we send the pllbuf anyway
-	// even if there isn't a PLL attached to the secondary bus
-	zl10353_write(fe, pllbuf, sizeof(pllbuf));
-
-	zl10353_single_write(fe, 0x5F, 0x13);
-	zl10353_single_write(fe, 0x70, 0x01);
-	udelay(250);
-	zl10353_single_write(fe, 0xE4, 0x00);
-	zl10353_single_write(fe, 0xE5, 0x2A);
-	zl10353_single_write(fe, 0xE9, 0x02);
-	zl10353_single_write(fe, 0xE7, 0x40);
-	zl10353_single_write(fe, 0xE8, 0x10);
+		/* if pllbuf is defined, retrieve the settings */
+		if (fe->ops.tuner_ops.calc_regs) {
+			fe->ops.tuner_ops.calc_regs(fe, param, pllbuf+1, 5);
+			pllbuf[1] <<= 1;
+		} else {
+			/* fake pllbuf settings */
+			pllbuf[1] = 0x61 << 1;
+			pllbuf[2] = 0;
+			pllbuf[3] = 0;
+			pllbuf[3] = 0;
+			pllbuf[4] = 0;
+		}
+		/* there is no call to _just_ start decoding, so we send the pllbuf anyway
+		   even if there isn't a PLL attached to the secondary bus */
+		zl10353_write(fe, pllbuf, sizeof(pllbuf));
+
+		zl10353_single_write(fe, 0x5F, 0x13);
+		zl10353_single_write(fe, TUNER_GO, 0x01);
+		udelay(250);
+		zl10353_single_write(fe, 0xE4, 0x00);
+		zl10353_single_write(fe, 0xE5, 0x2A);
+		zl10353_single_write(fe, 0xE9, 0x02);
+		zl10353_single_write(fe, 0xE7, 0x40);
+		zl10353_single_write(fe, 0xE8, 0x10);
+	}
 
 	return 0;
 }
@@ -321,8 +299,10 @@ static int zl10353_init(struct dvb_front
 static int zl10353_init(struct dvb_frontend *fe)
 {
 	struct zl10353_state *state = fe->demodulator_priv;
-	u8 zl10353_reset_attach[6] = { 0x50, 0x03, 0x64, 0x46, 0x15, 0x0F };
+	u8 zl10353_reset_attach[7] = { CONFIG, 0x03, 0x44, 0x46, 0x15, 0x0f, 0x80 };
+	u8 zl10353_unknown[] = { 0x90, 0x00, 0xff, 0xff, 0x00, 0xff, 0x3f, 0x3f };
 	int rc = 0;
+	u8 val;
 
 #if 1
 	if (debug_regs)
@@ -332,7 +312,7 @@ static int zl10353_init(struct dvb_front
 		zl10353_reset_attach[2] &= ~0x20;
 
 	/* Do a "hard" reset if not already done */
-	if (zl10353_read_register(state, 0x50) != zl10353_reset_attach[1] ||
+	if (zl10353_read_register(state, CONFIG) != zl10353_reset_attach[1] ||
 	    zl10353_read_register(state, 0x51) != zl10353_reset_attach[2]) {
 		rc = zl10353_write(fe, zl10353_reset_attach,
 				   sizeof(zl10353_reset_attach));
@@ -342,6 +322,22 @@ static int zl10353_init(struct dvb_front
 #endif
 	}
 
+	udelay(200);
+	zl10353_single_write(fe, 0xea , 0x01);
+	udelay(200);
+	zl10353_single_write(fe, 0xea , 0x00);
+
+	/* MSI Megasky 580 gl861 & Sigmatek DVB-110 au6610 does this */
+	if (state->config.unknown_init) {
+		zl10353_single_write(fe, 0x8e , 0x00);
+		rc = zl10353_write(fe, zl10353_unknown, sizeof(zl10353_unknown));
+	}
+
+	val = 0x48;
+	if (state->config.agc2)
+		val &= ~0x40; /* clear bit 6 */
+	zl10353_single_write(fe, OP_CTL_0, val);
+
 	return 0;
 }
 
@@ -352,7 +348,7 @@ static int zl10353_i2c_gate_ctrl(struct 
 	if (enable)
 		val |= 0x10;
 
-	return zl10353_single_write(fe, 0x62, val);
+	return zl10353_single_write(fe, SCAN_CTL, val);
 }
 
 static void zl10353_release(struct dvb_frontend *fe)
diff -r 214a42e5076f linux/drivers/media/dvb/frontends/zl10353.h
--- a/linux/drivers/media/dvb/frontends/zl10353.h	Tue May 08 23:36:40 2007 +0300
+++ b/linux/drivers/media/dvb/frontends/zl10353.h	Wed Jun 13 23:33:42 2007 +0300
@@ -29,14 +29,20 @@ struct zl10353_config
 	/* demodulator's I2C address */
 	u8 demod_address;
 
-	/* frequencies in kHz */
-	int adc_clock;  // default: 22528
+	/* demodulator's input clock */
+	int adc_clock;  /* defaults to 20480 kHz */
 
 	/* set if no pll is connected to the secondary i2c bus */
 	int no_tuner;
 
 	/* set if parallel ts output is required */
 	int parallel_ts;
+
+	/* set if AGC2 is used */
+	u8 agc2;
+
+	/* extra init needed some devices */
+	u8 unknown_init;
 };
 
 #if defined(CONFIG_DVB_ZL10353) || (defined(CONFIG_DVB_ZL10353_MODULE) && defined(MODULE))
diff -r 214a42e5076f linux/drivers/media/dvb/frontends/zl10353_priv.h
--- a/linux/drivers/media/dvb/frontends/zl10353_priv.h	Tue May 08 23:36:40 2007 +0300
+++ b/linux/drivers/media/dvb/frontends/zl10353_priv.h	Wed Jun 13 23:33:42 2007 +0300
@@ -46,8 +46,14 @@ enum zl10353_reg_addr {
 	RS_ERR_CNT_0       = 0x13,
 	RS_UBC_1           = 0x14,
 	RS_UBC_0           = 0x15,
+	CONFIG             = 0x50,
+	OP_CTL_0           = 0x5a,
+	SCAN_CTL           = 0x62,
+	BW_CTL             = 0x64,
 	TRL_NOMINAL_RATE_1 = 0x65,
 	TRL_NOMINAL_RATE_0 = 0x66,
+	TUNER_GO           = 0x70,
+	FSM_GO             = 0x71,
 	CHIP_ID            = 0x7F,
 };
 

_______________________________________________
linux-dvb mailing list
linux-dvb@linuxtv.org
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb

Reply via email to