V4L/DVB (5314): Added support for tda827x tuners with preamlifiers

This patch contains
- new tuning code for the tda827xa silicon tuner.
- controls the preamplifier of some boards with this tuner.
- support for the Philips Tiger S hybrid DVB-T reference design.
- reworked the saa7134-dvb modulue to get rid of most of the
  small board specific functions.

Signed-off-by: Hartmut Hackmann <hartmut.hackmann@t-online.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134
index a12246a..f18533f 100644
--- a/Documentation/video4linux/CARDLIST.saa7134
+++ b/Documentation/video4linux/CARDLIST.saa7134
@@ -107,3 +107,4 @@
 106 -> Encore ENLTV                             [1131:2342,1131:2341,3016:2344]
 107 -> Encore ENLTV-FM                          [1131:230f]
 108 -> Terratec Cinergy HT PCI                  [153b:1175]
+109 -> Philips Tiger - S Reference design
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index 4399d13..782832e 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -2543,10 +2543,10 @@
 		.name           = "Philips Tiger reference design",
 		.audio_clock    = 0x00187de7,
 		.tuner_type     = TUNER_PHILIPS_TDA8290,
-		.tuner_config   = 0,
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
+		.tuner_config   = 0,
 		.mpeg           = SAA7134_MPEG_DVB,
 		.gpiomask       = 0x0200000,
 		.inputs = {{
@@ -2625,7 +2625,7 @@
 		}},
 		.radio = {
 			.name   = name_radio,
-			.amux   = LINE1,
+			.amux   = TV,
 			.gpio   = 0x0200000,
 		},
 	},
@@ -3044,6 +3044,7 @@
 		.radio_type     = UNSET,
 		.tuner_addr     = ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
+		.tuner_config   = 1,
 		.mpeg           = SAA7134_MPEG_DVB,
 		.gpiomask       = 0x000200000,
 		.inputs         = {{
@@ -3290,6 +3291,36 @@
 			.amux   = LINE1,
 		}},
 	},
+	[SAA7134_BOARD_PHILIPS_TIGER_S] = {
+		.name           = "Philips Tiger - S Reference design",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tuner_config   = 2,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.gpiomask       = 0x0200000,
+		.inputs = {{
+			.name   = name_tv,
+			.vmux   = 1,
+			.amux   = TV,
+			.tv     = 1,
+		},{
+			.name   = name_comp1,
+			.vmux   = 3,
+			.amux   = LINE1,
+		},{
+			.name   = name_svideo,
+			.vmux   = 8,
+			.amux   = LINE1,
+		}},
+		.radio = {
+			.name   = name_radio,
+			.amux   = TV,
+			.gpio   = 0x0200000,
+		},
+	},
 };
 
 const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
@@ -4104,8 +4135,8 @@
 		break;
 	case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331:
 	case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS:
-		saa_writeb(SAA7134_GPIO_GPMODE3, 0x08);
-		saa_writeb(SAA7134_GPIO_GPSTATUS3, 0x00);
+		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x08000000, 0x08000000);
+		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x08000000, 0x00000000);
 		break;
 	case SAA7134_BOARD_AVERMEDIA_CARDBUS:
 		/* power-up tuner chip */
@@ -4168,6 +4199,8 @@
 				tun_setup.mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV;
 				tun_setup.type = dev->tuner_type;
 				tun_setup.addr = ADDR_UNSET;
+				tun_setup.config = 0;
+				tun_setup.gpio_func = NULL;
 
 				saa7134_i2c_call_clients (dev, TUNER_SET_TYPE_ADDR, &tun_setup);
 		}
@@ -4235,6 +4268,8 @@
 		tun_setup.mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV;
 		tun_setup.type = dev->tuner_type;
 		tun_setup.addr = ADDR_UNSET;
+		tun_setup.config = 0;
+		tun_setup.gpio_func = NULL;
 
 		saa7134_i2c_call_clients (dev, TUNER_SET_TYPE_ADDR,&tun_setup);
 		}
@@ -4254,11 +4289,36 @@
 		tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV;
 		tun_setup.type = dev->tuner_type;
 		tun_setup.addr = dev->tuner_addr;
+		tun_setup.config = 0;
+		tun_setup.gpio_func = NULL;
 
 		saa7134_i2c_call_clients (dev, TUNER_SET_TYPE_ADDR,&tun_setup);
 		}
 		break;
 	case SAA7134_BOARD_PHILIPS_TIGER:
+	case SAA7134_BOARD_PHILIPS_TIGER_S:
+		{
+		u8 data[] = { 0x3c, 0x33, 0x60};
+		struct tuner_setup tun_setup;
+		struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
+		if(dev->autodetected && (dev->eedata[0x49] == 0x50)) {
+			dev->board = SAA7134_BOARD_PHILIPS_TIGER_S;
+			printk(KERN_INFO "%s: Reconfigured board as %s\n",
+				dev->name, saa7134_boards[dev->board].name);
+		}
+		if(dev->board == SAA7134_BOARD_PHILIPS_TIGER_S) {
+			tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV;
+			tun_setup.type = TUNER_PHILIPS_TDA8290;
+			tun_setup.addr = 0x4b;
+			tun_setup.config = 2;
+			tun_setup.gpio_func = (tuner_gpio_func_t) saa7134_set_gpio;
+
+			saa7134_i2c_call_clients (dev, TUNER_SET_TYPE_ADDR,&tun_setup);
+			data[2] = 0x68;
+		}
+		i2c_transfer(&dev->i2c_adap, &msg, 1);
+		}
+		break;
 	case SAA7134_BOARD_PINNACLE_PCTV_310i:
 	case SAA7134_BOARD_TEVION_DVBT_220RF:
 	case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
@@ -4268,7 +4328,7 @@
 		 * and configure firmware eeprom address
 		 */
 		{
-		u8 data[] = { 0x3c, 0x33, 0x68};
+		u8 data[] = { 0x3c, 0x33, 0x60};
 		struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
 		i2c_transfer(&dev->i2c_adap, &msg, 1);
 		}
@@ -4282,18 +4342,18 @@
 		break;
 	case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331:
 	case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS:
-		/* make the tda10046 find its eeprom */
+		/* initialize analog mode  */
 		{
-		u8 data[] = { 0x3c, 0x33, 0x62};
+		u8 data[] = { 0x3c, 0x33, 0x6a};
 		struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
 		i2c_transfer(&dev->i2c_adap, &msg, 1);
 		}
 		break;
 	case SAA7134_BOARD_CINERGY_HT_PCMCIA:
 	case SAA7134_BOARD_CINERGY_HT_PCI:
-		/* make the tda10046 find its eeprom */
+		/* initialize analog mode */
 		{
-		u8 data[] = { 0x3c, 0x33, 0x60};
+		u8 data[] = { 0x3c, 0x33, 0x68};
 		struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
 		i2c_transfer(&dev->i2c_adap, &msg, 1);
 		}
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c
index 2e0518b..8ed03d6 100644
--- a/drivers/media/video/saa7134/saa7134-core.c
+++ b/drivers/media/video/saa7134/saa7134-core.c
@@ -1205,6 +1205,7 @@
 
 /* ----------------------------------------------------------- */
 
+EXPORT_SYMBOL(saa7134_set_gpio);
 EXPORT_SYMBOL(saa7134_i2c_call_clients);
 EXPORT_SYMBOL(saa7134_devlist);
 EXPORT_SYMBOL(saa7134_boards);
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
index 6d148a7..61a68c6 100644
--- a/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/drivers/media/video/saa7134/saa7134-dvb.c
@@ -54,7 +54,17 @@
 module_param(use_frontend, int, 0644);
 MODULE_PARM_DESC(use_frontend,"for cards with multiple frontends (0: terrestrial, 1: satellite)");
 
-/* ------------------------------------------------------------------ */
+static int debug = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off module debugging (default:off).");
+
+#define dprintk(fmt, arg...)	if (debug) \
+	printk(KERN_DEBUG "%s/dvb: " fmt, dev->name , ## arg)
+
+/* ------------------------------------------------------------------
+ * mt352 based DVB-T cards
+ */
+
 static int pinnacle_antenna_pwr(struct saa7134_dev *dev, int on)
 {
 	u32 ok;
@@ -185,10 +195,35 @@
 	.demod_init    = mt352_aver777_init,
 };
 
-/* ------------------------------------------------------------------ */
-static int philips_tda6651_pll_set(u8 addr, struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+/* ==================================================================
+ * tda1004x based DVB-T cards, helper functions
+ */
+
+static int philips_tda1004x_request_firmware(struct dvb_frontend *fe,
+					   const struct firmware **fw, char *name)
 {
 	struct saa7134_dev *dev = fe->dvb->priv;
+	return request_firmware(fw, name, &dev->pci->dev);
+}
+
+static void philips_tda1004x_set_board_name(struct dvb_frontend *fe, char *name)
+{
+	size_t len;
+
+	len = sizeof(fe->ops.info.name);
+	strncpy(fe->ops.info.name, name, len);
+	fe->ops.info.name[len - 1] = 0;
+}
+
+/* ------------------------------------------------------------------
+ * these tuners are tu1216, td1316(a)
+ */
+
+static int philips_tda6651_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+	struct saa7134_dev *dev = fe->dvb->priv;
+	struct tda1004x_state *state = fe->demodulator_priv;
+	u8 addr = state->config->tuner_address;
 	u8 tuner_buf[4];
 	struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tuner_buf,.len =
 			sizeof(tuner_buf) };
@@ -263,15 +298,19 @@
 
 	if (fe->ops.i2c_gate_ctrl)
 		fe->ops.i2c_gate_ctrl(fe, 1);
-	if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
+	if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1) {
+		printk("%s/dvb: could not write to tuner at addr: 0x%02x\n",dev->name, addr << 1);
 		return -EIO;
+	}
 	msleep(1);
 	return 0;
 }
 
-static int philips_tda6651_pll_init(u8 addr, struct dvb_frontend *fe)
+static int philips_tu1216_init(struct dvb_frontend *fe)
 {
 	struct saa7134_dev *dev = fe->dvb->priv;
+	struct tda1004x_state *state = fe->demodulator_priv;
+	u8 addr = state->config->tuner_address;
 	static u8 tu1216_init[] = { 0x0b, 0xf5, 0x85, 0xab };
 	struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tu1216_init,.len = sizeof(tu1216_init) };
 
@@ -287,46 +326,17 @@
 
 /* ------------------------------------------------------------------ */
 
-static int philips_tu1216_tuner_60_init(struct dvb_frontend *fe)
-{
-	return philips_tda6651_pll_init(0x60, fe);
-}
-
-static int philips_tu1216_tuner_60_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
-{
-	return philips_tda6651_pll_set(0x60, fe, params);
-}
-
-static int philips_tda1004x_request_firmware(struct dvb_frontend *fe,
-					   const struct firmware **fw, char *name)
-{
-	struct saa7134_dev *dev = fe->dvb->priv;
-	return request_firmware(fw, name, &dev->pci->dev);
-}
-
 static struct tda1004x_config philips_tu1216_60_config = {
-
 	.demod_address = 0x8,
 	.invert        = 1,
 	.invert_oclk   = 0,
 	.xtal_freq     = TDA10046_XTAL_4M,
 	.agc_config    = TDA10046_AGC_DEFAULT,
 	.if_freq       = TDA10046_FREQ_3617,
-	.request_firmware = philips_tda1004x_request_firmware,
+	.tuner_address = 0x60,
+	.request_firmware = philips_tda1004x_request_firmware
 };
 
-/* ------------------------------------------------------------------ */
-
-static int philips_tu1216_tuner_61_init(struct dvb_frontend *fe)
-{
-	return philips_tda6651_pll_init(0x61, fe);
-}
-
-static int philips_tu1216_tuner_61_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
-{
-	return philips_tda6651_pll_set(0x61, fe, params);
-}
-
 static struct tda1004x_config philips_tu1216_61_config = {
 
 	.demod_address = 0x8,
@@ -335,7 +345,8 @@
 	.xtal_freq     = TDA10046_XTAL_4M,
 	.agc_config    = TDA10046_AGC_DEFAULT,
 	.if_freq       = TDA10046_FREQ_3617,
-	.request_firmware = philips_tda1004x_request_firmware,
+	.tuner_address = 0x61,
+	.request_firmware = philips_tda1004x_request_firmware
 };
 
 /* ------------------------------------------------------------------ */
@@ -343,24 +354,42 @@
 static int philips_td1316_tuner_init(struct dvb_frontend *fe)
 {
 	struct saa7134_dev *dev = fe->dvb->priv;
+	struct tda1004x_state *state = fe->demodulator_priv;
+	u8 addr = state->config->tuner_address;
 	static u8 msg[] = { 0x0b, 0xf5, 0x86, 0xab };
-	struct i2c_msg init_msg = {.addr = 0x61,.flags = 0,.buf = msg,.len = sizeof(msg) };
+	struct i2c_msg init_msg = {.addr = addr,.flags = 0,.buf = msg,.len = sizeof(msg) };
 
 	/* setup PLL configuration */
 	if (fe->ops.i2c_gate_ctrl)
 		fe->ops.i2c_gate_ctrl(fe, 1);
 	if (i2c_transfer(&dev->i2c_adap, &init_msg, 1) != 1)
 		return -EIO;
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0);
 	return 0;
 }
 
 static int philips_td1316_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
 {
-	return philips_tda6651_pll_set(0x61, fe, params);
+	return philips_tda6651_pll_set(fe, params);
 }
 
+static int philips_td1316_tuner_sleep(struct dvb_frontend *fe)
+{
+	struct saa7134_dev *dev = fe->dvb->priv;
+	struct tda1004x_state *state = fe->demodulator_priv;
+	u8 addr = state->config->tuner_address;
+	static u8 msg[] = { 0x0b, 0xdc, 0x86, 0xa4 };
+	struct i2c_msg analog_msg = {.addr = addr,.flags = 0,.buf = msg,.len = sizeof(msg) };
+
+	/* switch the tuner to analog mode */
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (i2c_transfer(&dev->i2c_adap, &analog_msg, 1) != 1)
+		return -EIO;
+	return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
 static int philips_europa_tuner_init(struct dvb_frontend *fe)
 {
 	struct saa7134_dev *dev = fe->dvb->priv;
@@ -380,18 +409,14 @@
 static int philips_europa_tuner_sleep(struct dvb_frontend *fe)
 {
 	struct saa7134_dev *dev = fe->dvb->priv;
-	/* this message actually turns the tuner back to analog mode */
-	static u8 msg[] = { 0x0b, 0xdc, 0x86, 0xa4 };
-	struct i2c_msg analog_msg = {.addr = 0x61,.flags = 0,.buf = msg,.len = sizeof(msg) };
 
-	i2c_transfer(&dev->i2c_adap, &analog_msg, 1);
-	msleep(1);
+	static u8 msg[] = { 0x00, 0x14 };
+	struct i2c_msg analog_msg = {.addr = 0x43,.flags = 0,.buf = msg,.len = sizeof(msg) };
+
+	if (philips_td1316_tuner_sleep(fe))
+		return -EIO;
 
 	/* switch the board to analog mode */
-	analog_msg.addr = 0x43;
-	analog_msg.len  = 0x02;
-	msg[0] = 0x00;
-	msg[1] = 0x14;
 	if (fe->ops.i2c_gate_ctrl)
 		fe->ops.i2c_gate_ctrl(fe, 1);
 	i2c_transfer(&dev->i2c_adap, &analog_msg, 1);
@@ -416,7 +441,8 @@
 	.xtal_freq     = TDA10046_XTAL_4M,
 	.agc_config    = TDA10046_AGC_IFO_AUTO_POS,
 	.if_freq       = TDA10046_FREQ_052,
-	.request_firmware = philips_tda1004x_request_firmware,
+	.tuner_address = 0x61,
+	.request_firmware = philips_tda1004x_request_firmware
 };
 
 /* ------------------------------------------------------------------ */
@@ -424,9 +450,11 @@
 static int philips_fmd1216_tuner_init(struct dvb_frontend *fe)
 {
 	struct saa7134_dev *dev = fe->dvb->priv;
+	struct tda1004x_state *state = fe->demodulator_priv;
+	u8 addr = state->config->tuner_address;
 	/* this message is to set up ATC and ALC */
 	static u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0xa0 };
-	struct i2c_msg tuner_msg = {.addr = 0x61,.flags = 0,.buf = fmd1216_init,.len = sizeof(fmd1216_init) };
+	struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = fmd1216_init,.len = sizeof(fmd1216_init) };
 
 	if (fe->ops.i2c_gate_ctrl)
 		fe->ops.i2c_gate_ctrl(fe, 1);
@@ -440,9 +468,11 @@
 static int philips_fmd1216_tuner_sleep(struct dvb_frontend *fe)
 {
 	struct saa7134_dev *dev = fe->dvb->priv;
+	struct tda1004x_state *state = fe->demodulator_priv;
+	u8 addr = state->config->tuner_address;
 	/* this message actually turns the tuner back to analog mode */
 	static u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0x60 };
-	struct i2c_msg tuner_msg = {.addr = 0x61,.flags = 0,.buf = fmd1216_init,.len = sizeof(fmd1216_init) };
+	struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = fmd1216_init,.len = sizeof(fmd1216_init) };
 
 	if (fe->ops.i2c_gate_ctrl)
 		fe->ops.i2c_gate_ctrl(fe, 1);
@@ -460,8 +490,10 @@
 static int philips_fmd1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
 {
 	struct saa7134_dev *dev = fe->dvb->priv;
+	struct tda1004x_state *state = fe->demodulator_priv;
+	u8 addr = state->config->tuner_address;
 	u8 tuner_buf[4];
-	struct i2c_msg tuner_msg = {.addr = 0x61,.flags = 0,.buf = tuner_buf,.len =
+	struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tuner_buf,.len =
 			sizeof(tuner_buf) };
 	int tuner_frequency = 0;
 	int divider = 0;
@@ -536,8 +568,10 @@
 
 	if (fe->ops.i2c_gate_ctrl)
 		fe->ops.i2c_gate_ctrl(fe, 1);
-	if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
+	if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1) {
+		printk("%s/dvb: could not write to tuner at addr: 0x%02x\n",dev->name, addr << 1);
 		return -EIO;
+	}
 	return 0;
 }
 
@@ -548,9 +582,76 @@
 	.xtal_freq     = TDA10046_XTAL_16M,
 	.agc_config    = TDA10046_AGC_IFO_AUTO_NEG,
 	.if_freq       = TDA10046_FREQ_3613,
-	.request_firmware = philips_tda1004x_request_firmware,
+	.tuner_address = 0x61,
+	.request_firmware = philips_tda1004x_request_firmware
 };
 
+/* ------------------------------------------------------------------
+ * tda 1004x based cards with philips silicon tuner
+ */
+
+static void philips_tda827x_lna_gain(struct dvb_frontend *fe, int high)
+{
+	struct saa7134_dev *dev = fe->dvb->priv;
+	struct tda1004x_state *state = fe->demodulator_priv;
+	u8 addr = state->config->i2c_gate;
+	u8 config = state->config->tuner_config;
+	u8 GP00_CF[] = {0x20, 0x01};
+	u8 GP00_LEV[] = {0x22, 0x00};
+
+	struct i2c_msg msg = {.addr = addr,.flags = 0,.buf = GP00_CF, .len = 2};
+	if (config) {
+		if (high) {
+			dprintk("setting LNA to high gain\n");
+		} else {
+			dprintk("setting LNA to low gain\n");
+		}
+	}
+	switch (config) {
+	case 0: /* no LNA */
+		break;
+	case 1: /* switch is GPIO 0 of tda8290 */
+	case 2:
+		/* turn Vsync off */
+		saa7134_set_gpio(dev, 22, 0);
+		GP00_LEV[1] = high ? 0 : 1;
+		if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) {
+			printk("%s/dvb: could not access tda8290 at addr: 0x%02x\n",dev->name, addr << 1);
+			return;
+		}
+		msg.buf = GP00_LEV;
+		if (config == 2)
+			GP00_LEV[1] = high ? 1 : 0;
+		i2c_transfer(&dev->i2c_adap, &msg, 1);
+		break;
+	case 3: /* switch with GPIO of saa713x */
+		saa7134_set_gpio(dev, 22, high);
+		break;
+	}
+}
+
+static int tda8290_i2c_gate_ctrl( struct dvb_frontend* fe, int enable)
+{
+	struct saa7134_dev *dev = fe->dvb->priv;
+	struct tda1004x_state *state = fe->demodulator_priv;
+
+	u8 addr = state->config->i2c_gate;
+	static u8 tda8290_close[] = { 0x21, 0xc0};
+	static u8 tda8290_open[]  = { 0x21, 0x80};
+	struct i2c_msg tda8290_msg = {.addr = addr,.flags = 0, .len = 2};
+	if (enable) {
+		tda8290_msg.buf = tda8290_close;
+	} else {
+		tda8290_msg.buf = tda8290_open;
+	}
+	if (i2c_transfer(&dev->i2c_adap, &tda8290_msg, 1) != 1) {
+		printk("%s/dvb: could not access tda8290 I2C gate\n",dev->name);
+		return -EIO;
+	}
+	msleep(20);
+	return 0;
+}
+
 /* ------------------------------------------------------------------ */
 
 struct tda827x_data {
@@ -595,17 +696,14 @@
 	{ .lomax =         0, .spd = 0, .bs = 0, .bp = 0, .cp = 0, .gc3 = 0, .div1p5 = 0}
 };
 
-static int philips_tda827x_tuner_init(struct dvb_frontend *fe)
-{
-	return 0;
-}
-
-static int philips_tda827x_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_tda827xo_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
 {
 	struct saa7134_dev *dev = fe->dvb->priv;
+	struct tda1004x_state *state = fe->demodulator_priv;
+	u8 addr = state->config->tuner_address;
 	u8 tuner_buf[14];
 
-	struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tuner_buf,
+	struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tuner_buf,
 					.len = sizeof(tuner_buf) };
 	int i, tuner_freq, if_freq;
 	u32 N;
@@ -649,9 +747,10 @@
 	tuner_msg.len = 14;
 	if (fe->ops.i2c_gate_ctrl)
 		fe->ops.i2c_gate_ctrl(fe, 1);
-	if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
+	if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1) {
+		printk("%s/dvb: could not write to tuner at addr: 0x%02x\n",dev->name, addr << 1);
 		return -EIO;
-
+	}
 	msleep(500);
 	/* correct CP value */
 	tuner_buf[0] = 0x30;
@@ -664,11 +763,13 @@
 	return 0;
 }
 
-static int philips_tda827x_tuner_sleep(struct dvb_frontend *fe)
+static int philips_tda827xo_tuner_sleep(struct dvb_frontend *fe)
 {
 	struct saa7134_dev *dev = fe->dvb->priv;
+	struct tda1004x_state *state = fe->demodulator_priv;
+	u8 addr = state->config->tuner_address;
 	static u8 tda827x_sleep[] = { 0x30, 0xd0};
-	struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tda827x_sleep,
+	struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tda827x_sleep,
 				    .len = sizeof(tda827x_sleep) };
 	if (fe->ops.i2c_gate_ctrl)
 		fe->ops.i2c_gate_ctrl(fe, 1);
@@ -676,17 +777,6 @@
 	return 0;
 }
 
-static struct tda1004x_config tda827x_lifeview_config = {
-	.demod_address = 0x08,
-	.invert        = 1,
-	.invert_oclk   = 0,
-	.xtal_freq     = TDA10046_XTAL_16M,
-	.agc_config    = TDA10046_AGC_TDA827X,
-	.gpio_config   = TDA10046_GP11_I,
-	.if_freq       = TDA10046_FREQ_045,
-	.request_firmware = philips_tda1004x_request_firmware,
-};
-
 /* ------------------------------------------------------------------ */
 
 struct tda827xa_data {
@@ -727,17 +817,20 @@
 	{ .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0},
 	{ .lomax =         0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0}};
 
-
-static int philips_tda827xa_pll_set(u8 addr, struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_tda827xa_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
 {
 	struct saa7134_dev *dev = fe->dvb->priv;
-	u8 tuner_buf[14];
-	unsigned char reg2[2];
+	struct tda1004x_state *state = fe->demodulator_priv;
+	u8 addr = state->config->tuner_address;
+	u8 tuner_buf[10];
 
 	struct i2c_msg msg = {.addr = addr,.flags = 0,.buf = tuner_buf};
 	int i, tuner_freq, if_freq;
 	u32 N;
 
+	philips_tda827x_lna_gain( fe, 1);
+	msleep(20);
+
 	switch (params->u.ofdm.bandwidth) {
 	case BANDWIDTH_6_MHZ:
 		if_freq = 4000000;
@@ -767,45 +860,82 @@
 	tuner_buf[5] = (tda827xa_dvbt[i].spd << 5) + (tda827xa_dvbt[i].svco << 3) +
 			tda827xa_dvbt[i].sbs;
 	tuner_buf[6] = 0x4b + (tda827xa_dvbt[i].gc3 << 4);
-	tuner_buf[7] = 0x0c;
+	tuner_buf[7] = 0x1c;
 	tuner_buf[8] = 0x06;
 	tuner_buf[9] = 0x24;
-	tuner_buf[10] = 0xff;
-	tuner_buf[11] = 0x60;
-	tuner_buf[12] = 0x00;
-	tuner_buf[13] = 0x39;  // lpsel
-	msg.len = 14;
+	tuner_buf[10] = 0x00;
+	msg.len = 11;
 	if (fe->ops.i2c_gate_ctrl)
 		fe->ops.i2c_gate_ctrl(fe, 1);
-	if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1)
+	if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) {
+		printk("%s/dvb: could not write to tuner at addr: 0x%02x\n",dev->name, addr << 1);
 		return -EIO;
+	}
+	tuner_buf[0] = 0x90;
+	tuner_buf[1] = 0xff;
+	tuner_buf[2] = 0x60;
+	tuner_buf[3] = 0x00;
+	tuner_buf[4] = 0x59;  // lpsel, for 6MHz + 2
+	msg.len = 5;
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	i2c_transfer(&dev->i2c_adap, &msg, 1);
 
-	msg.buf= reg2;
+	tuner_buf[0] = 0xa0;
+	tuner_buf[1] = 0x40;
 	msg.len = 2;
-	reg2[0] = 0x60;
-	reg2[1] = 0x3c;
 	if (fe->ops.i2c_gate_ctrl)
 		fe->ops.i2c_gate_ctrl(fe, 1);
 	i2c_transfer(&dev->i2c_adap, &msg, 1);
 
-	reg2[0] = 0xa0;
-	reg2[1] = 0x40;
+	msleep(11);
+	msg.flags = I2C_M_RD;
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	i2c_transfer(&dev->i2c_adap, &msg, 1);
+	msg.flags = 0;
+
+	tuner_buf[1] >>= 4;
+	dprintk("tda8275a AGC2 gain is: %d\n", tuner_buf[1]);
+	if ((tuner_buf[1]) < 2) {
+		philips_tda827x_lna_gain(fe, 0);
+		tuner_buf[0] = 0x60;
+		tuner_buf[1] = 0x0c;
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 1);
+		i2c_transfer(&dev->i2c_adap, &msg, 1);
+	}
+
+	tuner_buf[0] = 0xc0;
+	tuner_buf[1] = 0x99;    // lpsel, for 6MHz + 2
 	if (fe->ops.i2c_gate_ctrl)
 		fe->ops.i2c_gate_ctrl(fe, 1);
 	i2c_transfer(&dev->i2c_adap, &msg, 1);
 
-	msleep(2);
+	tuner_buf[0] = 0x60;
+	tuner_buf[1] = 0x3c;
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	i2c_transfer(&dev->i2c_adap, &msg, 1);
+
 	/* correct CP value */
-	reg2[0] = 0x30;
-	reg2[1] = 0x10 + tda827xa_dvbt[i].scr;
-	msg.len = 2;
+	tuner_buf[0] = 0x30;
+	tuner_buf[1] = 0x10 + tda827xa_dvbt[i].scr;
 	if (fe->ops.i2c_gate_ctrl)
 		fe->ops.i2c_gate_ctrl(fe, 1);
 	i2c_transfer(&dev->i2c_adap, &msg, 1);
 
-	msleep(550);
-	reg2[0] = 0x50;
-	reg2[1] = 0x4f + (tda827xa_dvbt[i].gc3 << 4);
+	msleep(163);
+	tuner_buf[0] = 0xc0;
+	tuner_buf[1] = 0x39;  // lpsel, for 6MHz + 2
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	i2c_transfer(&dev->i2c_adap, &msg, 1);
+
+	msleep(3);
+	/* freeze AGC1 */
+	tuner_buf[0] = 0x50;
+	tuner_buf[1] = 0x4f + (tda827xa_dvbt[i].gc3 << 4);
 	if (fe->ops.i2c_gate_ctrl)
 		fe->ops.i2c_gate_ctrl(fe, 1);
 	i2c_transfer(&dev->i2c_adap, &msg, 1);
@@ -814,9 +944,11 @@
 
 }
 
-static int philips_tda827xa_tuner_sleep(u8 addr, struct dvb_frontend *fe)
+static int philips_tda827xa_tuner_sleep(struct dvb_frontend *fe)
 {
 	struct saa7134_dev *dev = fe->dvb->priv;
+	struct tda1004x_state *state = fe->demodulator_priv;
+	u8 addr = state->config->tuner_address;
 	static u8 tda827xa_sleep[] = { 0x30, 0x90};
 	struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tda827xa_sleep,
 				    .len = sizeof(tda827xa_sleep) };
@@ -828,58 +960,108 @@
 	return 0;
 }
 
-/* ------------------------------------------------------------------ */
+/* ------------------------------------------------------------------
+ * upper layer: distinguish the silicon tuner versions
+ */
 
-static int tda8290_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+static int philips_tda827x_tuner_init(struct dvb_frontend *fe)
 {
 	struct saa7134_dev *dev = fe->dvb->priv;
-	static u8 tda8290_close[] = { 0x21, 0xc0};
-	static u8 tda8290_open[]  = { 0x21, 0x80};
-	struct i2c_msg tda8290_msg = {.addr = 0x4b,.flags = 0, .len = 2};
-	if (enable) {
-		tda8290_msg.buf = tda8290_close;
-	} else {
-		tda8290_msg.buf = tda8290_open;
+	struct tda1004x_state *state = fe->demodulator_priv;
+	u8 addr = state->config->tuner_address;
+	u8 data;
+	struct i2c_msg tuner_msg = {.addr = addr,.flags = I2C_M_RD,.buf = &data, .len = 1};
+	state->conf_probed = 0;
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1) {
+		printk("%s/dvb: could not read from tuner at addr: 0x%02x\n",dev->name, addr << 1);
+		return -EIO;
 	}
-	if (i2c_transfer(&dev->i2c_adap, &tda8290_msg, 1) != 1)
-		return -EIO;
-	msleep(20);
+	if ((data & 0x3c) == 0) {
+		dprintk("tda827x tuner found\n");
+		state->conf_probed = 1;
+	} else {
+		dprintk("tda827xa tuner found\n");
+		state->conf_probed = 2;
+	}
+	switch (state->config->antenna_switch) {
+	case 0: break;
+	case 1:	dprintk("setting GPIO21 to 0 (TV antenna?)\n");
+		saa7134_set_gpio(dev, 21, 0);
+		break;
+	case 2: dprintk("setting GPIO21 to 1 (Radio antenna?)\n");
+		saa7134_set_gpio(dev, 21, 1);
+		break;
+	}
 	return 0;
 }
 
+static int philips_tda827x_tuner_sleep(struct dvb_frontend *fe)
+{
+	struct saa7134_dev *dev = fe->dvb->priv;
+	struct tda1004x_state *state = fe->demodulator_priv;
+	switch (state->conf_probed) {
+	case 1: philips_tda827xo_tuner_sleep(fe);
+		break;
+	case 2: philips_tda827xa_tuner_sleep(fe);
+		break;
+	default: dprintk("Huh? unknown tda827x version!\n");
+		return -EIO;
+	}
+	switch (state->config->antenna_switch) {
+	case 0: break;
+	case 1: dprintk("setting GPIO21 to 1 (Radio antenna?)\n");
+		saa7134_set_gpio(dev, 21, 1);
+		break;
+	case 2:	dprintk("setting GPIO21 to 0 (TV antenna?)\n");
+		saa7134_set_gpio(dev, 21, 0);
+		break;
+	}
+	return 0;
+}
+
+static int philips_tda827x_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+	struct saa7134_dev *dev = fe->dvb->priv;
+	struct tda1004x_state *state = fe->demodulator_priv;
+	switch (state->conf_probed) {
+	case 1: philips_tda827xo_pll_set(fe, params);
+		break;
+	case 2: philips_tda827xa_pll_set(fe, params);
+		break;
+	default: dprintk("Huh? unknown tda827x version!\n");
+		return -EIO;
+	}
+	return 0;
+}
+
+static void configure_tda827x_fe(struct saa7134_dev *dev, struct tda1004x_config *tda_conf,
+				 char *board_name)
+{
+	dev->dvb.frontend = dvb_attach(tda10046_attach, tda_conf, &dev->i2c_adap);
+	if (dev->dvb.frontend) {
+		if (tda_conf->i2c_gate)
+			dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl;
+		dev->dvb.frontend->ops.tuner_ops.init = philips_tda827x_tuner_init;
+		dev->dvb.frontend->ops.tuner_ops.sleep = philips_tda827x_tuner_sleep;
+		dev->dvb.frontend->ops.tuner_ops.set_params = philips_tda827x_pll_set;
+	}
+	philips_tda1004x_set_board_name(dev->dvb.frontend, board_name);
+}
+
 /* ------------------------------------------------------------------ */
-
-static int philips_tiger_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
-{
-	int ret;
-
-	ret = philips_tda827xa_pll_set(0x61, fe, params);
-	if (ret != 0)
-		return ret;
-	return 0;
-}
-
-static int philips_tiger_tuner_init(struct dvb_frontend *fe)
-{
-	struct saa7134_dev *dev = fe->dvb->priv;
-	static u8 data[] = { 0x3c, 0x33, 0x6a};
-	struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
-
-	if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1)
-		return -EIO;
-	return 0;
-}
-
-static int philips_tiger_tuner_sleep(struct dvb_frontend *fe)
-{
-	struct saa7134_dev *dev = fe->dvb->priv;
-	static u8 data[] = { 0x3c, 0x33, 0x68};
-	struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
-
-	i2c_transfer(&dev->i2c_adap, &msg, 1);
-	philips_tda827xa_tuner_sleep( 0x61, fe);
-	return 0;
-}
+static struct tda1004x_config tda827x_lifeview_config = {
+	.demod_address = 0x08,
+	.invert        = 1,
+	.invert_oclk   = 0,
+	.xtal_freq     = TDA10046_XTAL_16M,
+	.agc_config    = TDA10046_AGC_TDA827X,
+	.gpio_config   = TDA10046_GP11_I,
+	.if_freq       = TDA10046_FREQ_045,
+	.tuner_address = 0x60,
+	.request_firmware = philips_tda1004x_request_firmware
+};
 
 static struct tda1004x_config philips_tiger_config = {
 	.demod_address = 0x08,
@@ -889,31 +1071,12 @@
 	.agc_config    = TDA10046_AGC_TDA827X,
 	.gpio_config   = TDA10046_GP11_I,
 	.if_freq       = TDA10046_FREQ_045,
-	.request_firmware = philips_tda1004x_request_firmware,
+	.i2c_gate      = 0x4b,
+	.tuner_address = 0x61,
+	.tuner_config  = 0,
+	.antenna_switch= 1,
+	.request_firmware = philips_tda1004x_request_firmware
 };
-/* ------------------------------------------------------------------ */
-
-static int cinergy_ht_tuner_init(struct dvb_frontend *fe)
-{
-	struct saa7134_dev *dev = fe->dvb->priv;
-	static u8 data[] = { 0x3c, 0x33, 0x62};
-	struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
-
-	if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1)
-		return -EIO;
-	return 0;
-}
-
-static int cinergy_ht_tuner_sleep(struct dvb_frontend *fe)
-{
-	struct saa7134_dev *dev = fe->dvb->priv;
-	static u8 data[] = { 0x3c, 0x33, 0x60};
-	struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
-
-	i2c_transfer(&dev->i2c_adap, &msg, 1);
-	philips_tda827xa_tuner_sleep( 0x61, fe);
-	return 0;
-}
 
 static struct tda1004x_config cinergy_ht_config = {
 	.demod_address = 0x08,
@@ -923,10 +1086,40 @@
 	.agc_config    = TDA10046_AGC_TDA827X,
 	.gpio_config   = TDA10046_GP01_I,
 	.if_freq       = TDA10046_FREQ_045,
-	.request_firmware = philips_tda1004x_request_firmware,
+	.i2c_gate      = 0x4b,
+	.tuner_address = 0x61,
+	.tuner_config  = 0,
+	.request_firmware = philips_tda1004x_request_firmware
 };
 
-/* ------------------------------------------------------------------ */
+static struct tda1004x_config cinergy_ht_pci_config = {
+	.demod_address = 0x08,
+	.invert        = 1,
+	.invert_oclk   = 0,
+	.xtal_freq     = TDA10046_XTAL_16M,
+	.agc_config    = TDA10046_AGC_TDA827X,
+	.gpio_config   = TDA10046_GP01_I,
+	.if_freq       = TDA10046_FREQ_045,
+	.i2c_gate      = 0x4b,
+	.tuner_address = 0x60,
+	.tuner_config  = 0,
+	.request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config philips_tiger_s_config = {
+	.demod_address = 0x08,
+	.invert        = 1,
+	.invert_oclk   = 0,
+	.xtal_freq     = TDA10046_XTAL_16M,
+	.agc_config    = TDA10046_AGC_TDA827X,
+	.gpio_config   = TDA10046_GP01_I,
+	.if_freq       = TDA10046_FREQ_045,
+	.i2c_gate      = 0x4b,
+	.tuner_address = 0x61,
+	.tuner_config  = 2,
+	.antenna_switch= 1,
+	.request_firmware = philips_tda1004x_request_firmware
+};
 
 static struct tda1004x_config pinnacle_pctv_310i_config = {
 	.demod_address = 0x08,
@@ -936,11 +1129,12 @@
 	.agc_config    = TDA10046_AGC_TDA827X,
 	.gpio_config   = TDA10046_GP11_I,
 	.if_freq       = TDA10046_FREQ_045,
-	.request_firmware = philips_tda1004x_request_firmware,
+	.i2c_gate      = 0x4b,
+	.tuner_address = 0x61,
+	.tuner_config  = 1,
+	.request_firmware = philips_tda1004x_request_firmware
 };
 
-/* ------------------------------------------------------------------ */
-
 static struct tda1004x_config hauppauge_hvr_1110_config = {
 	.demod_address = 0x08,
 	.invert        = 1,
@@ -949,11 +1143,11 @@
 	.agc_config    = TDA10046_AGC_TDA827X,
 	.gpio_config   = TDA10046_GP11_I,
 	.if_freq       = TDA10046_FREQ_045,
-	.request_firmware = philips_tda1004x_request_firmware,
+	.i2c_gate      = 0x4b,
+	.tuner_address = 0x61,
+	.request_firmware = philips_tda1004x_request_firmware
 };
 
-/* ------------------------------------------------------------------ */
-
 static struct tda1004x_config asus_p7131_dual_config = {
 	.demod_address = 0x08,
 	.invert        = 1,
@@ -962,51 +1156,13 @@
 	.agc_config    = TDA10046_AGC_TDA827X,
 	.gpio_config   = TDA10046_GP11_I,
 	.if_freq       = TDA10046_FREQ_045,
-	.request_firmware = philips_tda1004x_request_firmware,
+	.i2c_gate      = 0x4b,
+	.tuner_address = 0x61,
+	.tuner_config  = 0,
+	.antenna_switch= 2,
+	.request_firmware = philips_tda1004x_request_firmware
 };
 
-static int asus_p7131_dual_tuner_init(struct dvb_frontend *fe)
-{
-	struct saa7134_dev *dev = fe->dvb->priv;
-	static u8 data[] = { 0x3c, 0x33, 0x6a};
-	struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
-
-	if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1)
-		return -EIO;
-	/* make sure the DVB-T antenna input is set */
-	saa_setl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0200000);
-	return 0;
-}
-
-static int asus_p7131_dual_tuner_sleep(struct dvb_frontend *fe)
-{
-	struct saa7134_dev *dev = fe->dvb->priv;
-	static u8 data[] = { 0x3c, 0x33, 0x68};
-	struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
-
-	i2c_transfer(&dev->i2c_adap, &msg, 1);
-	philips_tda827xa_tuner_sleep( 0x61, fe);
-	/* reset antenna inputs for analog usage */
-	saa_clearl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0200000);
-	return 0;
-}
-
-/* ------------------------------------------------------------------ */
-
-static int lifeview_trio_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
-{
-	int ret;
-
-	ret = philips_tda827xa_pll_set(0x60, fe, params);
-	return ret;
-}
-
-static int lifeview_trio_tuner_sleep(struct dvb_frontend *fe)
-{
-	philips_tda827xa_tuner_sleep(0x60, fe);
-	return 0;
-}
-
 static struct tda1004x_config lifeview_trio_config = {
 	.demod_address = 0x09,
 	.invert        = 1,
@@ -1015,24 +1171,46 @@
 	.agc_config    = TDA10046_AGC_TDA827X,
 	.gpio_config   = TDA10046_GP00_I,
 	.if_freq       = TDA10046_FREQ_045,
-	.request_firmware = philips_tda1004x_request_firmware,
+	.tuner_address = 0x60,
+	.request_firmware = philips_tda1004x_request_firmware
 };
 
-/* ------------------------------------------------------------------ */
+static struct tda1004x_config tevion_dvbt220rf_config = {
+	.demod_address = 0x08,
+	.invert        = 1,
+	.invert_oclk   = 0,
+	.xtal_freq     = TDA10046_XTAL_16M,
+	.agc_config    = TDA10046_AGC_TDA827X,
+	.gpio_config   = TDA10046_GP11_I,
+	.if_freq       = TDA10046_FREQ_045,
+	.tuner_address = 0x60,
+	.request_firmware = philips_tda1004x_request_firmware
+};
 
-static int ads_duo_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
-{
-	int ret;
+static struct tda1004x_config md8800_dvbt_config = {
+	.demod_address = 0x08,
+	.invert        = 1,
+	.invert_oclk   = 0,
+	.xtal_freq     = TDA10046_XTAL_16M,
+	.agc_config    = TDA10046_AGC_TDA827X,
+	.gpio_config   = TDA10046_GP01_I,
+	.if_freq       = TDA10046_FREQ_045,
+	.i2c_gate      = 0x4b,
+	.tuner_address = 0x60,
+	.tuner_config  = 0,
+	.request_firmware = philips_tda1004x_request_firmware
+};
 
-	ret = philips_tda827xa_pll_set(0x61, fe, params);
-	return ret;
-}
+/* ------------------------------------------------------------------
+ * special case: this card uses saa713x GPIO22 for the mode switch
+ */
 
 static int ads_duo_tuner_init(struct dvb_frontend *fe)
 {
 	struct saa7134_dev *dev = fe->dvb->priv;
+	philips_tda827x_tuner_init(fe);
 	/* route TDA8275a AGC input to the channel decoder */
-	saa_writeb(SAA7134_GPIO_GPSTATUS2, 0x60);
+	saa_setl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0400000);
 	return 0;
 }
 
@@ -1040,8 +1218,8 @@
 {
 	struct saa7134_dev *dev = fe->dvb->priv;
 	/* route TDA8275a AGC input to the analog IF chip*/
-	saa_writeb(SAA7134_GPIO_GPSTATUS2, 0x20);
-	philips_tda827xa_tuner_sleep( 0x61, fe);
+	saa_clearl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0400000);
+	philips_tda827x_tuner_sleep(fe);
 	return 0;
 }
 
@@ -1053,87 +1231,22 @@
 	.agc_config    = TDA10046_AGC_TDA827X,
 	.gpio_config   = TDA10046_GP00_I,
 	.if_freq       = TDA10046_FREQ_045,
-	.request_firmware = philips_tda1004x_request_firmware,
+	.tuner_address = 0x61,
+	.request_firmware = philips_tda1004x_request_firmware
 };
 
-/* ------------------------------------------------------------------ */
-
-static int tevion_dvb220rf_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
-{
-	int ret;
-	ret = philips_tda827xa_pll_set(0x60, fe, params);
-	return ret;
-}
-
-static int tevion_dvb220rf_tuner_sleep(struct dvb_frontend *fe)
-{
-	philips_tda827xa_tuner_sleep( 0x61, fe);
-	return 0;
-}
-
-static struct tda1004x_config tevion_dvbt220rf_config = {
-	.demod_address = 0x08,
-	.invert        = 1,
-	.invert_oclk   = 0,
-	.xtal_freq     = TDA10046_XTAL_16M,
-	.agc_config    = TDA10046_AGC_TDA827X,
-	.gpio_config   = TDA10046_GP11_I,
-	.if_freq       = TDA10046_FREQ_045,
-	.request_firmware = philips_tda1004x_request_firmware,
-};
-
-/* ------------------------------------------------------------------ */
-
-static int md8800_dvbt_analog_mode(struct dvb_frontend *fe)
-{
-	struct saa7134_dev *dev = fe->dvb->priv;
-	static u8 data[] = { 0x3c, 0x33, 0x68};
-	struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
-
-	i2c_transfer(&dev->i2c_adap, &msg, 1);
-	philips_tda827xa_tuner_sleep( 0x61, fe);
-	return 0;
-}
-
-static int md8800_dvbt_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
-{
-	int ret;
-	struct saa7134_dev *dev = fe->dvb->priv;
-	static u8 tda8290_close[] = { 0x21, 0xc0};
-	static u8 tda8290_open[]  = { 0x21, 0x80};
-	struct i2c_msg tda8290_msg = {.addr = 0x4b,.flags = 0, .len = 2};
-	/* close tda8290 i2c bridge */
-	tda8290_msg.buf = tda8290_close;
-	ret = i2c_transfer(&dev->i2c_adap, &tda8290_msg, 1);
-	if (ret != 1)
-		return -EIO;
-	msleep(20);
-	ret = philips_tda827xa_pll_set(0x60, fe, params);
-	if (ret != 0)
-		return ret;
-	/* open tda8290 i2c bridge */
-	tda8290_msg.buf = tda8290_open;
-	i2c_transfer(&dev->i2c_adap, &tda8290_msg, 1);
-	return ret;
-}
-
-static struct tda1004x_config md8800_dvbt_config = {
-	.demod_address = 0x08,
-	.invert        = 1,
-	.invert_oclk   = 0,
-	.xtal_freq     = TDA10046_XTAL_16M,
-	.agc_config    = TDA10046_AGC_TDA827X,
-	.gpio_config   = TDA10046_GP11_I,
-	.if_freq       = TDA10046_FREQ_045,
-	.request_firmware = philips_tda1004x_request_firmware,
-};
+/* ==================================================================
+ * tda10086 based DVB-S cards, helper functions
+ */
 
 static struct tda10086_config flydvbs = {
 	.demod_address = 0x0e,
 	.invert = 0,
 };
 
-/* ------------------------------------------------------------------ */
+/* ==================================================================
+ * nxt200x based ATSC cards, helper functions
+ */
 
 static struct nxt200x_config avertvhda180 = {
 	.demod_address    = 0x0a,
@@ -1153,10 +1266,13 @@
 	.set_pll_input    = nxt200x_set_pll_input,
 };
 
-/* ------------------------------------------------------------------ */
+/* ==================================================================
+ * Core code
+ */
 
 static int dvb_init(struct saa7134_dev *dev)
 {
+	char *board_name;
 	/* init struct videobuf_dvb */
 	dev->ts.nr_bufs    = 32;
 	dev->ts.nr_packets = 32*4;
@@ -1194,6 +1310,7 @@
 			dev->dvb.frontend->ops.tuner_ops.init = philips_fmd1216_tuner_init;
 			dev->dvb.frontend->ops.tuner_ops.sleep = philips_fmd1216_tuner_sleep;
 			dev->dvb.frontend->ops.tuner_ops.set_params = philips_fmd1216_tuner_set_params;
+			philips_tda1004x_set_board_name(dev->dvb.frontend, "DVB-T Medion MD7134");
 		}
 		break;
 	case SAA7134_BOARD_PHILIPS_TOUGH:
@@ -1201,42 +1318,16 @@
 					       &philips_tu1216_60_config,
 					       &dev->i2c_adap);
 		if (dev->dvb.frontend) {
-			dev->dvb.frontend->ops.tuner_ops.init = philips_tu1216_tuner_60_init;
-			dev->dvb.frontend->ops.tuner_ops.set_params = philips_tu1216_tuner_60_set_params;
+			dev->dvb.frontend->ops.tuner_ops.init = philips_tu1216_init;
+			dev->dvb.frontend->ops.tuner_ops.set_params = philips_tda6651_pll_set;
+			philips_tda1004x_set_board_name(dev->dvb.frontend, "DVB-T Philips TOUGH");
 		}
 		break;
 	case SAA7134_BOARD_FLYDVBTDUO:
-		dev->dvb.frontend = dvb_attach(tda10046_attach,
-					       &tda827x_lifeview_config,
-					       &dev->i2c_adap);
-		if (dev->dvb.frontend) {
-			dev->dvb.frontend->ops.tuner_ops.init = philips_tda827x_tuner_init;
-			dev->dvb.frontend->ops.tuner_ops.sleep = philips_tda827x_tuner_sleep;
-			dev->dvb.frontend->ops.tuner_ops.set_params = philips_tda827x_tuner_set_params;
-		}
-		break;
 	case SAA7134_BOARD_FLYDVBT_DUO_CARDBUS:
-		dev->dvb.frontend = dvb_attach(tda10046_attach,
-					       &tda827x_lifeview_config,
-					       &dev->i2c_adap);
-		if (dev->dvb.frontend) {
-			dev->dvb.frontend->ops.tuner_ops.init = philips_tda827x_tuner_init;
-			dev->dvb.frontend->ops.tuner_ops.sleep = philips_tda827x_tuner_sleep;
-			dev->dvb.frontend->ops.tuner_ops.set_params = philips_tda827x_tuner_set_params;
-		}
+		configure_tda827x_fe(dev, &tda827x_lifeview_config, "DVB-T Lifeview FlyDVB Duo");
 		break;
 	case SAA7134_BOARD_PHILIPS_EUROPA:
-		dev->dvb.frontend = dvb_attach(tda10046_attach,
-					       &philips_europa_config,
-					       &dev->i2c_adap);
-		if (dev->dvb.frontend) {
-			dev->original_demod_sleep = dev->dvb.frontend->ops.sleep;
-			dev->dvb.frontend->ops.sleep = philips_europa_demod_sleep;
-			dev->dvb.frontend->ops.tuner_ops.init = philips_europa_tuner_init;
-			dev->dvb.frontend->ops.tuner_ops.sleep = philips_europa_tuner_sleep;
-			dev->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params;
-		}
-		break;
 	case SAA7134_BOARD_VIDEOMATE_DVBT_300:
 		dev->dvb.frontend = dvb_attach(tda10046_attach,
 					       &philips_europa_config,
@@ -1247,6 +1338,11 @@
 			dev->dvb.frontend->ops.tuner_ops.init = philips_europa_tuner_init;
 			dev->dvb.frontend->ops.tuner_ops.sleep = philips_europa_tuner_sleep;
 			dev->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params;
+			if (dev->board == SAA7134_BOARD_VIDEOMATE_DVBT_300)
+				board_name = "DVB-T Compro VideoMate 300";
+			else
+				board_name = "DVB-T Philips Europa";
+			philips_tda1004x_set_board_name(dev->dvb.frontend, board_name);
 		}
 		break;
 	case SAA7134_BOARD_VIDEOMATE_DVBT_200:
@@ -1254,74 +1350,29 @@
 					       &philips_tu1216_61_config,
 					       &dev->i2c_adap);
 		if (dev->dvb.frontend) {
-			dev->dvb.frontend->ops.tuner_ops.init = philips_tu1216_tuner_61_init;
-			dev->dvb.frontend->ops.tuner_ops.set_params = philips_tu1216_tuner_61_set_params;
+			dev->dvb.frontend->ops.tuner_ops.init = philips_tu1216_init;
+			dev->dvb.frontend->ops.tuner_ops.set_params = philips_tda6651_pll_set;
+			philips_tda1004x_set_board_name(dev->dvb.frontend, "DVB-T Compro VideoMate 200");
 		}
 		break;
 	case SAA7134_BOARD_PHILIPS_TIGER:
-		dev->dvb.frontend = dvb_attach(tda10046_attach,
-					       &philips_tiger_config,
-					       &dev->i2c_adap);
-		if (dev->dvb.frontend) {
-			dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl;
-			dev->dvb.frontend->ops.tuner_ops.init = philips_tiger_tuner_init;
-			dev->dvb.frontend->ops.tuner_ops.sleep = philips_tiger_tuner_sleep;
-			dev->dvb.frontend->ops.tuner_ops.set_params = philips_tiger_tuner_set_params;
-		}
+		configure_tda827x_fe(dev, &philips_tiger_config, "DVB-T Philips Tiger");
 		break;
 	case SAA7134_BOARD_PINNACLE_PCTV_310i:
-		dev->dvb.frontend = dvb_attach(tda10046_attach,
-					       &pinnacle_pctv_310i_config,
-					       &dev->i2c_adap);
-		if (dev->dvb.frontend) {
-			dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl;
-			dev->dvb.frontend->ops.tuner_ops.init = philips_tiger_tuner_init;
-			dev->dvb.frontend->ops.tuner_ops.sleep = philips_tiger_tuner_sleep;
-			dev->dvb.frontend->ops.tuner_ops.set_params = philips_tiger_tuner_set_params;
-		}
+		configure_tda827x_fe(dev, &pinnacle_pctv_310i_config, "DVB-T Pinnacle PCTV 310i");
 		break;
 	case SAA7134_BOARD_HAUPPAUGE_HVR1110:
-		dev->dvb.frontend = dvb_attach(tda10046_attach,
-					       &hauppauge_hvr_1110_config,
-					       &dev->i2c_adap);
-		if (dev->dvb.frontend) {
-			dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl;
-			dev->dvb.frontend->ops.tuner_ops.init = philips_tiger_tuner_init;
-			dev->dvb.frontend->ops.tuner_ops.sleep = philips_tiger_tuner_sleep;
-			dev->dvb.frontend->ops.tuner_ops.set_params = philips_tiger_tuner_set_params;
-		}
+		configure_tda827x_fe(dev, &hauppauge_hvr_1110_config, "DVB-T Hauppauge HVR 1110");
 		break;
 	case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
-		dev->dvb.frontend = dvb_attach(tda10046_attach,
-					       &asus_p7131_dual_config,
-					       &dev->i2c_adap);
-		if (dev->dvb.frontend) {
-			dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl;
-			dev->dvb.frontend->ops.tuner_ops.init = asus_p7131_dual_tuner_init;
-			dev->dvb.frontend->ops.tuner_ops.sleep = asus_p7131_dual_tuner_sleep;
-			dev->dvb.frontend->ops.tuner_ops.set_params = philips_tiger_tuner_set_params;
-		}
+		configure_tda827x_fe(dev, &asus_p7131_dual_config, "DVB-T Asus P7137 Dual");
 		break;
 	case SAA7134_BOARD_FLYDVBT_LR301:
-		dev->dvb.frontend = dvb_attach(tda10046_attach,
-					       &tda827x_lifeview_config,
-					       &dev->i2c_adap);
-		if (dev->dvb.frontend) {
-			dev->dvb.frontend->ops.tuner_ops.init = philips_tda827x_tuner_init;
-			dev->dvb.frontend->ops.tuner_ops.sleep = philips_tda827x_tuner_sleep;
-			dev->dvb.frontend->ops.tuner_ops.set_params = philips_tda827x_tuner_set_params;
-		}
+		configure_tda827x_fe(dev, &tda827x_lifeview_config, "DVB-T Lifeview FlyDVBT LR301");
 		break;
 	case SAA7134_BOARD_FLYDVB_TRIO:
 		if(! use_frontend) {	//terrestrial
-			dev->dvb.frontend = dvb_attach(tda10046_attach,
-						       &lifeview_trio_config,
-						       &dev->i2c_adap);
-			if (dev->dvb.frontend) {
-				dev->dvb.frontend->ops.tuner_ops.sleep = lifeview_trio_tuner_sleep;
-				dev->dvb.frontend->ops.tuner_ops.set_params =
-								lifeview_trio_tuner_set_params;
-			}
+			configure_tda827x_fe(dev, &lifeview_trio_config, NULL);
 		} else {  	      //satellite
 			dev->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs, &dev->i2c_adap);
 			if (dev->dvb.frontend) {
@@ -1337,24 +1388,6 @@
 		}
 		break;
 	case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331:
-		dev->dvb.frontend = dvb_attach(tda10046_attach,
-					       &ads_tech_duo_config,
-					       &dev->i2c_adap);
-		if (dev->dvb.frontend) {
-			dev->dvb.frontend->ops.tuner_ops.init = ads_duo_tuner_init;
-			dev->dvb.frontend->ops.tuner_ops.sleep = ads_duo_tuner_sleep;
-			dev->dvb.frontend->ops.tuner_ops.set_params = ads_duo_tuner_set_params;
-		}
-		break;
-	case SAA7134_BOARD_TEVION_DVBT_220RF:
-		dev->dvb.frontend = dvb_attach(tda10046_attach,
-					       &tevion_dvbt220rf_config,
-					       &dev->i2c_adap);
-		if (dev->dvb.frontend) {
-			dev->dvb.frontend->ops.tuner_ops.sleep = tevion_dvb220rf_tuner_sleep;
-			dev->dvb.frontend->ops.tuner_ops.set_params = tevion_dvb220rf_tuner_set_params;
-		}
-		break;
 	case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS:
 		dev->dvb.frontend = dvb_attach(tda10046_attach,
 					       &ads_tech_duo_config,
@@ -1362,17 +1395,19 @@
 		if (dev->dvb.frontend) {
 			dev->dvb.frontend->ops.tuner_ops.init = ads_duo_tuner_init;
 			dev->dvb.frontend->ops.tuner_ops.sleep = ads_duo_tuner_sleep;
-			dev->dvb.frontend->ops.tuner_ops.set_params = ads_duo_tuner_set_params;
+			dev->dvb.frontend->ops.tuner_ops.set_params = philips_tda827x_pll_set;
+			if (dev->board == SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331)
+				board_name = "DVB-T ADS DUO Cardbus PTV331";
+			else
+				board_name = "DVB-T Lifeview FlyDVT Cardbus";
+			philips_tda1004x_set_board_name(dev->dvb.frontend, board_name);
 		}
 		break;
+	case SAA7134_BOARD_TEVION_DVBT_220RF:
+		configure_tda827x_fe(dev, &tevion_dvbt220rf_config, "DVB-T Tevion 220RF");
+		break;
 	case SAA7134_BOARD_MEDION_MD8800_QUADRO:
-		dev->dvb.frontend = tda10046_attach(&md8800_dvbt_config,
-						    &dev->i2c_adap);
-		if (dev->dvb.frontend) {
-			dev->dvb.frontend->ops.tuner_ops.init = philips_tiger_tuner_init;
-			dev->dvb.frontend->ops.tuner_ops.sleep = md8800_dvbt_analog_mode;
-			dev->dvb.frontend->ops.tuner_ops.set_params = md8800_dvbt_pll_set;
-		}
+		configure_tda827x_fe(dev, &md8800_dvbt_config, "DVB-T Medion MD8800");
 		break;
 	case SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180:
 		dev->dvb.frontend = dvb_attach(nxt200x_attach, &avertvhda180,
@@ -1413,6 +1448,7 @@
 			dev->dvb.frontend->ops.tuner_ops.init = philips_fmd1216_tuner_init;
 			dev->dvb.frontend->ops.tuner_ops.sleep = philips_fmd1216_tuner_sleep;
 			dev->dvb.frontend->ops.tuner_ops.set_params = philips_fmd1216_tuner_set_params;
+			philips_tda1004x_set_board_name(dev->dvb.frontend, "DVBT Asus Europa 2 Hybrid");
 		}
 		break;
 	case SAA7134_BOARD_VIDEOMATE_DVBT_200A:
@@ -1422,31 +1458,17 @@
 		if (dev->dvb.frontend) {
 			dev->dvb.frontend->ops.tuner_ops.init = philips_td1316_tuner_init;
 			dev->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params;
+			philips_tda1004x_set_board_name(dev->dvb.frontend, "DVBT Compro Videomate 200a");
 		}
 		break;
 	case SAA7134_BOARD_CINERGY_HT_PCMCIA:
-		dev->dvb.frontend = dvb_attach(tda10046_attach,
-					       &cinergy_ht_config,
-					       &dev->i2c_adap);
-		if (dev->dvb.frontend) {
-			dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl;
-			dev->dvb.frontend->ops.tuner_ops.init = cinergy_ht_tuner_init;
-			dev->dvb.frontend->ops.tuner_ops.sleep = cinergy_ht_tuner_sleep;
-			dev->dvb.frontend->ops.tuner_ops.set_params = philips_tiger_tuner_set_params;
-
-		}
+		configure_tda827x_fe(dev, &cinergy_ht_config, "DVB-T Terratec Cinergy HT Cardbus");
 		break;
 	case SAA7134_BOARD_CINERGY_HT_PCI:
-		dev->dvb.frontend = dvb_attach(tda10046_attach,
-					       &cinergy_ht_config,
-					       &dev->i2c_adap);
-		if (dev->dvb.frontend) {
-			dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl;
-			dev->dvb.frontend->ops.tuner_ops.init = cinergy_ht_tuner_init;
-			dev->dvb.frontend->ops.tuner_ops.sleep = cinergy_ht_tuner_sleep;
-			dev->dvb.frontend->ops.tuner_ops.set_params = md8800_dvbt_pll_set;
-
-		}
+		configure_tda827x_fe(dev, &cinergy_ht_pci_config, "DVB-T Terratec Cinergy HT PCI");
+		break;
+	case SAA7134_BOARD_PHILIPS_TIGER_S:
+		configure_tda827x_fe(dev, &philips_tiger_s_config, "DVB-T Philips Tiger S");
 		break;
 	default:
 		printk("%s: Huh? unknown DVB card?\n",dev->name);
diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c
index f2cb630..e1cb273 100644
--- a/drivers/media/video/saa7134/saa7134-video.c
+++ b/drivers/media/video/saa7134/saa7134-video.c
@@ -603,7 +603,14 @@
 	saa_writeb(SAA7134_RAW_DATA_GAIN,         0x40);
 	saa_writeb(SAA7134_RAW_DATA_OFFSET,       0x80);
 
-	saa7134_i2c_call_clients(dev,VIDIOC_S_STD,&norm->id);
+	/* only tell the tuner if this is a tv input */
+	if (card_in(dev,dev->ctl_input).tv) {
+		if ((card(dev).tuner_type == TUNER_PHILIPS_TDA8290)
+				&& ((card(dev).tuner_config == 1)
+				||  (card(dev).tuner_config == 2)))
+			saa7134_set_gpio(dev, 22, 5);
+		saa7134_i2c_call_clients(dev,VIDIOC_S_STD,&norm->id);
+	}
 }
 
 static void video_mux(struct saa7134_dev *dev, int input)
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index 303c080..b46265a 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -231,6 +231,7 @@
 #define SAA7134_BOARD_ENCORE_ENLTV         106
 #define SAA7134_BOARD_ENCORE_ENLTV_FM      107
 #define SAA7134_BOARD_CINERGY_HT_PCI       108
+#define SAA7134_BOARD_PHILIPS_TIGER_S      109
 
 #define SAA7134_MAXBOARDS 8
 #define SAA7134_INPUT_MAX 8
diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c
index 027c8a0..e6c3e61 100644
--- a/drivers/media/video/tda8290.c
+++ b/drivers/media/video/tda8290.c
@@ -192,14 +192,52 @@
 	{ .lomax =     0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0}   /* End */
 };
 
+static void tda827xa_lna_gain(struct i2c_client *c, int high)
+{
+	struct tuner *t = i2c_get_clientdata(c);
+	unsigned char buf[] = {0x22, 0x01};
+	int arg;
+	struct i2c_msg msg = {.addr = c->addr, .flags = 0, .buf = buf, .len = sizeof(buf)};
+	if (t->config) {
+		if (high)
+			tuner_dbg("setting LNA to high gain\n");
+		else
+			tuner_dbg("setting LNA to low gain\n");
+	}
+	switch (t->config) {
+	case 0: /* no LNA */
+		break;
+	case 1: /* switch is GPIO 0 of tda8290 */
+	case 2:
+		/* turn Vsync on */
+		if (t->std & V4L2_STD_MN)
+			arg = 5;
+		else
+			arg = 4;
+		if (t->gpio_func)
+			t->gpio_func(c->adapter->algo_data, 22, 5);
+		buf[1] = high ? 0 : 1;
+		if (t->config == 2)
+			buf[1] = high ? 1 : 0;
+		i2c_transfer(c->adapter, &msg, 1);
+		break;
+	case 3: /* switch with GPIO of saa713x */
+		if (t->gpio_func)
+			t->gpio_func(c->adapter->algo_data, 22, high);
+		break;
+	}
+}
+
 static void tda827xa_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
 {
-	unsigned char tuner_reg[14];
-	unsigned char reg2[2];
+	unsigned char tuner_reg[11];
 	u32 N;
 	int i;
 	struct tuner *t = i2c_get_clientdata(c);
-	struct i2c_msg msg = {.addr = t->tda827x_addr, .flags = 0};
+	struct i2c_msg msg = {.addr = t->tda827x_addr, .flags = 0, .buf = tuner_reg};
+
+	tda827xa_lna_gain( c, 1);
+	msleep(10);
 
 	if (t->mode == V4L2_TUNER_RADIO)
 		freq = freq / 1000;
@@ -222,48 +260,58 @@
 	tuner_reg[5] = (tda827xa_analog[i].spd << 5) + (tda827xa_analog[i].svco << 3) +
 			tda827xa_analog[i].sbs;
 	tuner_reg[6] = 0x8b + (tda827xa_analog[i].gc3 << 4);
-	tuner_reg[7] = 0x0c;
+	tuner_reg[7] = 0x1c;
 	tuner_reg[8] = 4;
 	tuner_reg[9] = 0x20;
-	tuner_reg[10] = 0xff;
-	tuner_reg[11] = 0xe0;
-	tuner_reg[12] = 0;
-	tuner_reg[13] = 0x39 + (t->tda827x_lpsel << 1);
-
-	msg.buf = tuner_reg;
-	msg.len = 14;
+	tuner_reg[10] = 0x00;
+	msg.len = 11;
 	i2c_transfer(c->adapter, &msg, 1);
 
-	msg.buf= reg2;
+	tuner_reg[0] = 0x90;
+	tuner_reg[1] = 0xff;
+	tuner_reg[2] = 0xe0;
+	tuner_reg[3] = 0;
+	tuner_reg[4] = 0x99 + (t->tda827x_lpsel << 1);
+	msg.len = 5;
+	i2c_transfer(c->adapter, &msg, 1);
+
+	tuner_reg[0] = 0xa0;
+	tuner_reg[1] = 0xc0;
 	msg.len = 2;
-	reg2[0] = 0x60;
-	reg2[1] = 0x3c;
 	i2c_transfer(c->adapter, &msg, 1);
 
-	reg2[0] = 0xa0;
-	reg2[1] = 0xc0;
+	tuner_reg[0] = 0x30;
+	tuner_reg[1] = 0x10 + tda827xa_analog[i].scr;
 	i2c_transfer(c->adapter, &msg, 1);
 
-	msleep(2);
-	reg2[0] = 0x30;
-	reg2[1] = 0x10 + tda827xa_analog[i].scr;
+	msg.flags = I2C_M_RD;
+	i2c_transfer(c->adapter, &msg, 1);
+	msg.flags = 0;
+	tuner_reg[1] >>= 4;
+	tuner_dbg("AGC2 gain is: %d\n", tuner_reg[1]);
+	if (tuner_reg[1] < 1)
+		tda827xa_lna_gain( c, 0);
+
+	msleep(100);
+	tuner_reg[0] = 0x60;
+	tuner_reg[1] = 0x3c;
 	i2c_transfer(c->adapter, &msg, 1);
 
-	msleep(550);
-	reg2[0] = 0x50;
-	reg2[1] = 0x8f + (tda827xa_analog[i].gc3 << 4);
+	msleep(163);
+	tuner_reg[0] = 0x50;
+	tuner_reg[1] = 0x8f + (tda827xa_analog[i].gc3 << 4);
 	i2c_transfer(c->adapter, &msg, 1);
 
-	reg2[0] = 0x80;
-	reg2[1] = 0x28;
+	tuner_reg[0] = 0x80;
+	tuner_reg[1] = 0x28;
 	i2c_transfer(c->adapter, &msg, 1);
 
-	reg2[0] = 0xb0;
-	reg2[1] = 0x01;
+	tuner_reg[0] = 0xb0;
+	tuner_reg[1] = 0x01;
 	i2c_transfer(c->adapter, &msg, 1);
 
-	reg2[0] = 0xc0;
-	reg2[1] = 0x19 + (t->tda827x_lpsel << 1);
+	tuner_reg[0] = 0xc0;
+	tuner_reg[1] = 0x19 + (t->tda827x_lpsel << 1);
 	i2c_transfer(c->adapter, &msg, 1);
 }
 
@@ -319,7 +367,9 @@
 	unsigned char addr_pll_stat = 0x1b;
 	unsigned char adc_sat, agc_stat,
 		      pll_stat;
+	int i;
 
+	tuner_dbg("tda827xa config is 0x%02x\n", t->config);
 	i2c_master_send(c, easy_mode, 2);
 	i2c_master_send(c, agc_out_on, 2);
 	i2c_master_send(c, soft_reset, 2);
@@ -340,17 +390,22 @@
 		tda827xa_tune(c, ifc, freq);
 	else
 		tda827x_tune(c, ifc, freq);
+	for (i = 0; i < 3; i++) {
+		i2c_master_send(c, &addr_pll_stat, 1);
+		i2c_master_recv(c, &pll_stat, 1);
+		if (pll_stat & 0x80) {
+			i2c_master_send(c, &addr_adc_sat, 1);
+			i2c_master_recv(c, &adc_sat, 1);
+			i2c_master_send(c, &addr_agc_stat, 1);
+			i2c_master_recv(c, &agc_stat, 1);
+			tuner_dbg("tda8290 is locked, AGC: %d\n", agc_stat);
+			break;
+		} else {
+			tuner_dbg("tda8290 not locked, no signal?\n");
+			msleep(100);
+		}
+	}
 	/* adjust headroom resp. gain */
-	i2c_master_send(c, &addr_adc_sat, 1);
-	i2c_master_recv(c, &adc_sat, 1);
-	i2c_master_send(c, &addr_agc_stat, 1);
-	i2c_master_recv(c, &agc_stat, 1);
-	i2c_master_send(c, &addr_pll_stat, 1);
-	i2c_master_recv(c, &pll_stat, 1);
-	if (pll_stat & 0x80)
-		tuner_dbg("tda8290 is locked, AGC: %d\n", agc_stat);
-	else
-		tuner_dbg("tda8290 not locked, no signal?\n");
 	if ((agc_stat > 115) || (!(pll_stat & 0x80) && (adc_sat < 20))) {
 		tuner_dbg("adjust gain, step 1. Agc: %d, ADC stat: %d, lock: %d\n",
 			   agc_stat, adc_sat, pll_stat & 0x80);
@@ -487,11 +542,16 @@
 
 static void tda8290_init_if(struct i2c_client *c)
 {
+	struct tuner *t = i2c_get_clientdata(c);
 	unsigned char set_VS[] = { 0x30, 0x6F };
+	unsigned char set_GP00_CF[] = { 0x20, 0x01 };
 	unsigned char set_GP01_CF[] = { 0x20, 0x0B };
 
+	if ((t->config == 1) || (t->config == 2))
+		i2c_master_send(c, set_GP00_CF, 2);
+	else
+		i2c_master_send(c, set_GP01_CF, 2);
 	i2c_master_send(c, set_VS, 2);
-	i2c_master_send(c, set_GP01_CF, 2);
 }
 
 static void tda8290_init_tuner(struct i2c_client *c)