Re: A link DTU advice needed

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

 



moi
attached patch should fix it. I have been too busy to find proper solution for ZL10353, though I now know how it should be done.

regards
Antti Palosaari

Dag Nygren wrote:
Hi again,

is there anything I can do to help debugging the
A-link DTU USB stick "Tuning failed" problem?
The stick seems to be the old model without the (m),
using the modules:

qt1010 zl10353 dvb_usb_gl861 dvb_usb
and now tunes to 3 of the 4 MUX:es we have here
in Espoo, Finland but no deal with one of them whatever I do.

Best
Dag


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


--
              |||
             (0-0)
---------oOO--(_)--OOo---------------------------------------------
 http://palosaari.fi/
-"Kahta asiaa en ymmärrä.. C-kielen syntaksi ja naisten logiikka.."

diff -r 496bf62d9e03 linux/drivers/media/dvb/dvb-usb/au6610.c
--- a/linux/drivers/media/dvb/dvb-usb/au6610.c	Thu Nov 15 12:07:19 2007 -0200
+++ b/linux/drivers/media/dvb/dvb-usb/au6610.c	Thu Nov 15 17:02:19 2007 +0200
@@ -123,10 +123,23 @@ static int au6610_identify_state(struct 
 	return 0;
 }
 
+static int au6610_zl10353_demod_init(struct dvb_frontend *fe)
+{
+	u8 unk1[] = { 0x8e , 0x00 };
+	u8 unk2[] = { 0x90, 0x00, 0xff, 0xff, 0x00, 0xff, 0x3f, 0x3f };
+
+	zl10353_write_(fe, unk1, sizeof(unk1));
+	zl10353_write_(fe, unk2, sizeof(unk2));
+
+	return 0;
+}
+
 static struct zl10353_config au6610_zl10353_config = {
 	.demod_address = 0x0f,
 	.no_tuner = 1,
 	.parallel_ts = 1,
+	.agc2 = 1,
+	.demod_init = au6610_zl10353_demod_init
 };
 
 static int au6610_zl10353_frontend_attach(struct dvb_usb_adapter *adap)
diff -r 496bf62d9e03 linux/drivers/media/dvb/dvb-usb/gl861.c
--- a/linux/drivers/media/dvb/dvb-usb/gl861.c	Thu Nov 15 12:07:19 2007 -0200
+++ b/linux/drivers/media/dvb/dvb-usb/gl861.c	Thu Nov 15 17:02:19 2007 +0200
@@ -45,6 +45,8 @@ static int gl861_i2c_msg(struct dvb_usb_
 		return -EINVAL;
 	}
 
+	udelay(10); /* avoid usb i2c timeouts */
+
 	return usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), req, type,
 			       value, index, rbuf, rlen, 2000);
 }
@@ -100,10 +102,23 @@ static int gl861_identify_state(struct u
 	return 0;
 }
 
+static int gl861_zl10353_demod_init(struct dvb_frontend *fe)
+{
+	u8 unk1[] = { 0x8e , 0x00 };
+	u8 unk2[] = { 0x90, 0x00, 0xff, 0xff, 0x00, 0xff, 0x3f, 0x3f };
+
+	zl10353_write_(fe, unk1, sizeof(unk1));
+	zl10353_write_(fe, unk2, sizeof(unk2));
+
+	return 0;
+}
+
 static struct zl10353_config gl861_zl10353_config = {
 	.demod_address = 0x0f,
 	.no_tuner = 1,
 	.parallel_ts = 1,
+	.agc2 = 1,
+	.demod_init = gl861_zl10353_demod_init
 };
 
 static int gl861_frontend_attach(struct dvb_usb_adapter *adap)
@@ -156,6 +171,7 @@ static int gl861_probe(struct usb_interf
 }
 
 static struct usb_device_id gl861_table [] = {
+//		{ USB_DEVICE(USB_VID_MSI, 123) },
 		{ USB_DEVICE(USB_VID_MSI, USB_PID_MSI_MEGASKY580_55801) },
 		{ USB_DEVICE(USB_VID_ALINK, USB_VID_ALINK_DTU) },
 		{ }		/* Terminating entry */
diff -r 496bf62d9e03 linux/drivers/media/dvb/frontends/qt1010.c
--- a/linux/drivers/media/dvb/frontends/qt1010.c	Thu Nov 15 12:07:19 2007 -0200
+++ b/linux/drivers/media/dvb/frontends/qt1010.c	Thu Nov 15 17:02:19 2007 +0200
@@ -28,7 +28,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 */
@@ -42,7 +42,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;
@@ -56,12 +56,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)
 {
@@ -71,7 +72,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)
@@ -82,333 +83,579 @@ 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);
-		}
-		if (err) return err;
-	}
-
-	if (debug)
-		qt1010_dump_regs(priv);
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
-
-	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;
-	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 }
-	};
-
-	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 }
-	};
-	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);
+	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_RD:
-			if (i2c_data[i].val == 0x20)
-				valptr = &priv->reg20_init_val;
-			else
-				valptr = &tmpval;
-			err = qt1010_readreg(priv, i2c_data[i].reg, valptr);
+		case QT1010_READ:
+			err = qt1010_readreg(priv, data[i].reg, &tmpval);
 			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++;
+		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;
-	}
-
-	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);
+		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 */
+
+	return 0;
+}
+
+/* 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;
+	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 }
+	};
+
+	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 }
+	};
+	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;
 }
 
@@ -436,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 496bf62d9e03 linux/drivers/media/dvb/frontends/qt1010.h
--- a/linux/drivers/media/dvb/frontends/qt1010.h	Thu Nov 15 12:07:19 2007 -0200
+++ b/linux/drivers/media/dvb/frontends/qt1010.h	Thu Nov 15 17:02:19 2007 +0200
@@ -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 496bf62d9e03 linux/drivers/media/dvb/frontends/qt1010_priv.h
--- a/linux/drivers/media/dvb/frontends/qt1010_priv.h	Thu Nov 15 12:07:19 2007 -0200
+++ b/linux/drivers/media/dvb/frontends/qt1010_priv.h	Thu Nov 15 17:02:19 2007 +0200
@@ -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 496bf62d9e03 linux/drivers/media/dvb/frontends/zl10353.c
--- a/linux/drivers/media/dvb/frontends/zl10353.c	Thu Nov 15 12:07:19 2007 -0200
+++ b/linux/drivers/media/dvb/frontends/zl10353.c	Thu Nov 15 17:02:19 2007 +0200
@@ -21,6 +21,7 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/string.h>
@@ -123,106 +124,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 +300,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 +313,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));
@@ -340,7 +321,29 @@ static int zl10353_init(struct dvb_front
 		if (debug_regs)
 			zl10353_dump_regs(fe);
 #endif
-	}
+		/* calibrate */
+		udelay(200);
+		zl10353_single_write(fe, 0xea , 0x01);
+		udelay(200);
+		zl10353_single_write(fe, 0xea , 0x00);
+
+		/* AGC2 */
+		val = 0x48;
+		if (state->config.agc2)
+			val &= ~0x40; /* clear bit 6 */
+		zl10353_single_write(fe, OP_CTL_0, val);
+
+		return state->config.demod_init(fe);
+	}
+
+
+#if 0
+	/* 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));
+	}
+#endif
 
 	return 0;
 }
@@ -352,7 +355,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 496bf62d9e03 linux/drivers/media/dvb/frontends/zl10353.h
--- a/linux/drivers/media/dvb/frontends/zl10353.h	Thu Nov 15 12:07:19 2007 -0200
+++ b/linux/drivers/media/dvb/frontends/zl10353.h	Thu Nov 15 17:02:19 2007 +0200
@@ -29,14 +29,23 @@ 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;
+
+	/* Initialise the demodulator and PLL. Cannot be NULL */
+	int (*demod_init)(struct dvb_frontend* fe);
 };
 
 #if defined(CONFIG_DVB_ZL10353) || (defined(CONFIG_DVB_ZL10353_MODULE) && defined(MODULE))
@@ -51,4 +60,11 @@ static inline struct dvb_frontend* zl103
 }
 #endif // CONFIG_DVB_ZL10353
 
+static inline int zl10353_write_(struct dvb_frontend *fe, u8 *buf, int len) {
+	int r = 0;
+	if (fe->ops.write)
+		r = fe->ops.write(fe, buf, len);
+	return r;
+}
+
 #endif /* ZL10353_H */
diff -r 496bf62d9e03 linux/drivers/media/dvb/frontends/zl10353_priv.h
--- a/linux/drivers/media/dvb/frontends/zl10353_priv.h	Thu Nov 15 12:07:19 2007 -0200
+++ b/linux/drivers/media/dvb/frontends/zl10353_priv.h	Thu Nov 15 17:02:19 2007 +0200
@@ -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@xxxxxxxxxxx
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb

[Index of Archives]     [Linux Media]     [Video 4 Linux]     [Asterisk]     [Samba]     [Xorg]     [Xfree86]     [Linux USB]

  Powered by Linux