V4L/DVB (5446): Renamed ASUStek P7131 card [1043:4876]
[powerpc.git] / drivers / media / video / saa7134 / saa7134-dvb.c
index fb741fa..71c32b3 100644 (file)
@@ -41,7 +41,9 @@
 
 #include "tda10086.h"
 #include "tda826x.h"
+#include "tda827x.h"
 #include "isl6421.h"
+
 MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
 MODULE_LICENSE("GPL");
 
@@ -50,7 +52,25 @@ static unsigned int antenna_pwr = 0;
 module_param(antenna_pwr, int, 0444);
 MODULE_PARM_DESC(antenna_pwr,"enable antenna power (Pinnacle 300i)");
 
-/* ------------------------------------------------------------------ */
+static int use_frontend = 0;
+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...)   do { if (debug) \
+       printk(KERN_DEBUG "%s/dvb: " fmt, dev->name , ## arg); } while(0)
+
+/* Print a warning */
+#define wprintk(fmt, arg...) \
+       printk(KERN_WARNING "%s/dvb: " fmt, dev->name, ## arg)
+
+/* ------------------------------------------------------------------
+ * mt352 based DVB-T cards
+ */
+
 static int pinnacle_antenna_pwr(struct saa7134_dev *dev, int on)
 {
        u32 ok;
@@ -71,8 +91,7 @@ static int pinnacle_antenna_pwr(struct saa7134_dev *dev, int on)
        saa_setl(SAA7134_GPIO_GPSTATUS0 >> 2,   (1 << 28));
        udelay(10);
        ok = saa_readl(SAA7134_GPIO_GPSTATUS0) & (1 << 27);
-       printk("%s: %s %s\n", dev->name, __FUNCTION__,
-              ok ? "on" : "off");
+       dprintk("%s %s\n", __FUNCTION__, ok ? "on" : "off");
 
        if (!ok)
                saa_clearl(SAA7134_GPIO_GPSTATUS0 >> 2,   (1 << 26));
@@ -92,7 +111,7 @@ static int mt352_pinnacle_init(struct dvb_frontend* fe)
        static u8 irq_cfg []       = { INTERRUPT_EN_0, 0x00, 0x00, 0x00, 0x00 };
        struct saa7134_dev *dev= fe->dvb->priv;
 
-       printk("%s: %s called\n",dev->name,__FUNCTION__);
+       dprintk("%s called\n", __FUNCTION__);
 
        mt352_write(fe, clock_config,   sizeof(clock_config));
        udelay(200);
@@ -181,10 +200,26 @@ static struct mt352_config avermedia_777 = {
        .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);
+}
+
+/* ------------------------------------------------------------------
+ * 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) };
@@ -259,15 +294,20 @@ static int philips_tda6651_pll_set(u8 addr, struct dvb_frontend *fe, struct dvb_
 
        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) {
+               wprintk("could not write to tuner at addr: 0x%02x\n",
+                       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) };
 
@@ -283,46 +323,17 @@ static int philips_tda6651_pll_init(u8 addr, struct dvb_frontend *fe)
 
 /* ------------------------------------------------------------------ */
 
-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_tu1216_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_tu1216_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,
@@ -331,57 +342,78 @@ static struct tda1004x_config philips_tu1216_61_config = {
        .xtal_freq     = TDA10046_XTAL_4M,
        .agc_config    = TDA10046_AGC_DEFAULT,
        .if_freq       = TDA10046_FREQ_3617,
-       .request_firmware = philips_tu1216_request_firmware,
+       .tuner_address = 0x61,
+       .request_firmware = philips_tda1004x_request_firmware
 };
 
 /* ------------------------------------------------------------------ */
 
-static int philips_europa_tuner_init(struct dvb_frontend *fe)
+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;
-       msleep(1);
+       return 0;
+}
 
-       /* switch the board to dvb mode */
-       init_msg.addr = 0x43;
-       init_msg.len  = 0x02;
-       msg[0] = 0x00;
-       msg[1] = 0x40;
+static int philips_td1316_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *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, &init_msg, 1) != 1)
+       if (i2c_transfer(&dev->i2c_adap, &analog_msg, 1) != 1)
                return -EIO;
-
        return 0;
 }
 
-static int philips_td1316_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+/* ------------------------------------------------------------------ */
+
+static int philips_europa_tuner_init(struct dvb_frontend *fe)
 {
-       return philips_tda6651_pll_set(0x61, fe, params);
+       struct saa7134_dev *dev = fe->dvb->priv;
+       static u8 msg[] = { 0x00, 0x40};
+       struct i2c_msg init_msg = {.addr = 0x43,.flags = 0,.buf = msg,.len = sizeof(msg) };
+
+
+       if (philips_td1316_tuner_init(fe))
+               return -EIO;
+       msleep(1);
+       if (i2c_transfer(&dev->i2c_adap, &init_msg, 1) != 1)
+               return -EIO;
+
+       return 0;
 }
 
 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);
@@ -406,7 +438,8 @@ static struct tda1004x_config philips_europa_config = {
        .xtal_freq     = TDA10046_XTAL_4M,
        .agc_config    = TDA10046_AGC_IFO_AUTO_POS,
        .if_freq       = TDA10046_FREQ_052,
-       .request_firmware = NULL,
+       .tuner_address = 0x61,
+       .request_firmware = philips_tda1004x_request_firmware
 };
 
 /* ------------------------------------------------------------------ */
@@ -414,9 +447,11 @@ static struct tda1004x_config philips_europa_config = {
 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);
@@ -430,9 +465,11 @@ static int philips_fmd1216_tuner_init(struct dvb_frontend *fe)
 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) };
+       u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0x60 };
+       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);
@@ -450,8 +487,10 @@ static int philips_fmd1216_tuner_sleep(struct dvb_frontend *fe)
 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;
@@ -526,8 +565,11 @@ static int philips_fmd1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_
 
        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) {
+               wprintk("could not write to tuner at addr: 0x%02x\n",
+                       addr << 1);
                return -EIO;
+       }
        return 0;
 }
 
@@ -538,479 +580,365 @@ static struct tda1004x_config medion_cardbus = {
        .xtal_freq     = TDA10046_XTAL_16M,
        .agc_config    = TDA10046_AGC_IFO_AUTO_NEG,
        .if_freq       = TDA10046_FREQ_3613,
-       .request_firmware = NULL,
+       .tuner_address = 0x61,
+       .request_firmware = philips_tda1004x_request_firmware
 };
 
-/* ------------------------------------------------------------------ */
-
-struct tda827x_data {
-       u32 lomax;
-       u8  spd;
-       u8  bs;
-       u8  bp;
-       u8  cp;
-       u8  gc3;
-       u8 div1p5;
-};
-
-static struct tda827x_data tda827x_dvbt[] = {
-       { .lomax =  62000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1},
-       { .lomax =  66000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1},
-       { .lomax =  76000000, .spd = 3, .bs = 1, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0},
-       { .lomax =  84000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0},
-       { .lomax =  93000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0},
-       { .lomax =  98000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0},
-       { .lomax = 109000000, .spd = 3, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0},
-       { .lomax = 123000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1},
-       { .lomax = 133000000, .spd = 2, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1},
-       { .lomax = 151000000, .spd = 2, .bs = 1, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0},
-       { .lomax = 154000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0},
-       { .lomax = 181000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 0, .div1p5 = 0},
-       { .lomax = 185000000, .spd = 2, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0},
-       { .lomax = 217000000, .spd = 2, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0},
-       { .lomax = 244000000, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1},
-       { .lomax = 265000000, .spd = 1, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1},
-       { .lomax = 302000000, .spd = 1, .bs = 1, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0},
-       { .lomax = 324000000, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0},
-       { .lomax = 370000000, .spd = 1, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0},
-       { .lomax = 454000000, .spd = 1, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0},
-       { .lomax = 493000000, .spd = 0, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1},
-       { .lomax = 530000000, .spd = 0, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1},
-       { .lomax = 554000000, .spd = 0, .bs = 1, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0},
-       { .lomax = 604000000, .spd = 0, .bs = 1, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0},
-       { .lomax = 696000000, .spd = 0, .bs = 2, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0},
-       { .lomax = 740000000, .spd = 0, .bs = 2, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0},
-       { .lomax = 820000000, .spd = 0, .bs = 3, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0},
-       { .lomax = 865000000, .spd = 0, .bs = 3, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0},
-       { .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;
-}
+/* ------------------------------------------------------------------
+ * tda 1004x based cards with philips silicon tuner
+ */
 
-static int philips_tda827x_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static void philips_tda827x_lna_gain(struct dvb_frontend *fe, int high)
 {
        struct saa7134_dev *dev = fe->dvb->priv;
-       u8 tuner_buf[14];
-
-       struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tuner_buf,
-                                       .len = sizeof(tuner_buf) };
-       int i, tuner_freq, if_freq;
-       u32 N;
-       switch (params->u.ofdm.bandwidth) {
-       case BANDWIDTH_6_MHZ:
-               if_freq = 4000000;
+       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 BANDWIDTH_7_MHZ:
-               if_freq = 4500000;
+       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) {
+                       wprintk("could not access tda8290 at addr: 0x%02x\n",
+                               addr << 1);
+                       return;
+               }
+               msg.buf = GP00_LEV;
+               if (config == 2)
+                       GP00_LEV[1] = high ? 1 : 0;
+               i2c_transfer(&dev->i2c_adap, &msg, 1);
                break;
-       default:                   /* 8 MHz or Auto */
-               if_freq = 5000000;
+       case 3: /* switch with GPIO of saa713x */
+               saa7134_set_gpio(dev, 22, high);
                break;
        }
-       tuner_freq = params->frequency + if_freq;
-
-       i = 0;
-       while (tda827x_dvbt[i].lomax < tuner_freq) {
-               if(tda827x_dvbt[i + 1].lomax == 0)
-                       break;
-               i++;
-       }
-
-       N = ((tuner_freq + 125000) / 250000) << (tda827x_dvbt[i].spd + 2);
-       tuner_buf[0] = 0;
-       tuner_buf[1] = (N>>8) | 0x40;
-       tuner_buf[2] = N & 0xff;
-       tuner_buf[3] = 0;
-       tuner_buf[4] = 0x52;
-       tuner_buf[5] = (tda827x_dvbt[i].spd << 6) + (tda827x_dvbt[i].div1p5 << 5) +
-                                  (tda827x_dvbt[i].bs << 3) + tda827x_dvbt[i].bp;
-       tuner_buf[6] = (tda827x_dvbt[i].gc3 << 4) + 0x8f;
-       tuner_buf[7] = 0xbf;
-       tuner_buf[8] = 0x2a;
-       tuner_buf[9] = 0x05;
-       tuner_buf[10] = 0xff;
-       tuner_buf[11] = 0x00;
-       tuner_buf[12] = 0x00;
-       tuner_buf[13] = 0x40;
-
-       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)
-               return -EIO;
-
-       msleep(500);
-       /* correct CP value */
-       tuner_buf[0] = 0x30;
-       tuner_buf[1] = 0x50 + tda827x_dvbt[i].cp;
-       tuner_msg.len = 2;
-       if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 1);
-       i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
-
-       return 0;
 }
 
-static int philips_tda827x_tuner_sleep(struct dvb_frontend *fe)
+static int tda8290_i2c_gate_ctrl( struct dvb_frontend* fe, int enable)
 {
-       struct saa7134_dev *dev = fe->dvb->priv;
-       static u8 tda827x_sleep[] = { 0x30, 0xd0};
-       struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tda827x_sleep,
-                                   .len = sizeof(tda827x_sleep) };
-       if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 1);
-       i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
+       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(state->i2c, &tda8290_msg, 1) != 1) {
+               struct saa7134_dev *dev = fe->dvb->priv;
+               wprintk("could not access tda8290 I2C gate\n");
+               return -EIO;
+       }
+       msleep(20);
        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,
-       .if_freq       = TDA10046_FREQ_045,
-       .request_firmware = NULL,
-};
-
 /* ------------------------------------------------------------------ */
 
-struct tda827xa_data {
-       u32 lomax;
-       u8  svco;
-       u8  spd;
-       u8  scr;
-       u8  sbs;
-       u8  gc3;
-};
-
-static struct tda827xa_data tda827xa_dvbt[] = {
-       { .lomax =  56875000, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 1},
-       { .lomax =  67250000, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1},
-       { .lomax =  81250000, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1},
-       { .lomax =  97500000, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1},
-       { .lomax = 113750000, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1},
-       { .lomax = 134500000, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
-       { .lomax = 154000000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
-       { .lomax = 162500000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
-       { .lomax = 183000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
-       { .lomax = 195000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1},
-       { .lomax = 227500000, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1},
-       { .lomax = 269000000, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1},
-       { .lomax = 290000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1},
-       { .lomax = 325000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1},
-       { .lomax = 390000000, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1},
-       { .lomax = 455000000, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1},
-       { .lomax = 520000000, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},
-       { .lomax = 538000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1},
-       { .lomax = 550000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},
-       { .lomax = 620000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
-       { .lomax = 650000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
-       { .lomax = 700000000, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
-       { .lomax = 780000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
-       { .lomax = 820000000, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
-       { .lomax = 870000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
-       { .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_tda827x_tuner_init(struct dvb_frontend *fe)
 {
        struct saa7134_dev *dev = fe->dvb->priv;
-       u8 tuner_buf[14];
-       unsigned char reg2[2];
-
-       struct i2c_msg msg = {.addr = addr,.flags = 0,.buf = tuner_buf};
-       int i, tuner_freq, if_freq;
-       u32 N;
+       struct tda1004x_state *state = fe->demodulator_priv;
 
-       switch (params->u.ofdm.bandwidth) {
-       case BANDWIDTH_6_MHZ:
-               if_freq = 4000000;
-               break;
-       case BANDWIDTH_7_MHZ:
-               if_freq = 4500000;
+       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;
-       default:                   /* 8 MHz or Auto */
-               if_freq = 5000000;
+       case 2: dprintk("setting GPIO21 to 1 (Radio antenna?)\n");
+               saa7134_set_gpio(dev, 21, 1);
                break;
        }
-       tuner_freq = params->frequency + if_freq;
-
-       i = 0;
-       while (tda827xa_dvbt[i].lomax < tuner_freq) {
-               if(tda827xa_dvbt[i + 1].lomax == 0)
-                       break;
-               i++;
-       }
-
-       N = ((tuner_freq + 31250) / 62500) << tda827xa_dvbt[i].spd;
-       tuner_buf[0] = 0;            // subaddress
-       tuner_buf[1] = N >> 8;
-       tuner_buf[2] = N & 0xff;
-       tuner_buf[3] = 0;
-       tuner_buf[4] = 0x16;
-       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[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;
-       if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 1);
-       if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1)
-               return -EIO;
-
-       msg.buf= reg2;
-       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;
-       if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 1);
-       i2c_transfer(&dev->i2c_adap, &msg, 1);
-
-       msleep(2);
-       /* correct CP value */
-       reg2[0] = 0x30;
-       reg2[1] = 0x10 + tda827xa_dvbt[i].scr;
-       msg.len = 2;
-       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);
-       if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 1);
-       i2c_transfer(&dev->i2c_adap, &msg, 1);
-
        return 0;
-
 }
 
-static int philips_tda827xa_tuner_sleep(u8 addr, struct dvb_frontend *fe)
+static int philips_tda827x_tuner_sleep(struct dvb_frontend *fe)
 {
        struct saa7134_dev *dev = fe->dvb->priv;
-       static u8 tda827xa_sleep[] = { 0x30, 0x90};
-       struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tda827xa_sleep,
-                                   .len = sizeof(tda827xa_sleep) };
-       if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 1);
-       i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
+       struct tda1004x_state *state = fe->demodulator_priv;
+
+       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 struct tda827x_config tda827x_cfg = {
+       .lna_gain = philips_tda827x_lna_gain,
+       .init = philips_tda827x_tuner_init,
+       .sleep = philips_tda827x_tuner_sleep
+};
 
-static int philips_tiger_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static void configure_tda827x_fe(struct saa7134_dev *dev, struct tda1004x_config *tda_conf)
 {
-       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(0x61, 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;
+       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;
+               if (dvb_attach(tda827x_attach, dev->dvb.frontend, tda_conf->tuner_address,
+                                               &dev->i2c_adap,&tda827x_cfg) == NULL) {
+                       wprintk("no tda827x tuner found at addr: %02x\n",
+                               tda_conf->tuner_address);
+               }
+       }
 }
 
-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 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 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)};
+static struct tda1004x_config philips_tiger_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,
+       .i2c_gate      = 0x4b,
+       .tuner_address = 0x61,
+       .tuner_config  = 0,
+       .antenna_switch= 1,
+       .request_firmware = philips_tda1004x_request_firmware
+};
 
-       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,
+       .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  = 0,
+       .request_firmware = philips_tda1004x_request_firmware
+};
 
-static struct tda1004x_config philips_tiger_config = {
+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,
-       .request_firmware = NULL,
+       .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 int lifeview_trio_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
-{
-       int ret;
+static struct tda1004x_config pinnacle_pctv_310i_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,
+       .i2c_gate      = 0x4b,
+       .tuner_address = 0x61,
+       .tuner_config  = 1,
+       .request_firmware = philips_tda1004x_request_firmware
+};
 
-       ret = philips_tda827xa_pll_set(0x60, fe, params);
-       return ret;
-}
+static struct tda1004x_config hauppauge_hvr_1110_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,
+       .i2c_gate      = 0x4b,
+       .tuner_address = 0x61,
+       .request_firmware = philips_tda1004x_request_firmware
+};
 
-static int lifeview_trio_tuner_sleep(struct dvb_frontend *fe)
-{
-       philips_tda827xa_tuner_sleep(0x60, fe);
-       return 0;
-}
+static struct tda1004x_config asus_p7131_dual_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,
+       .i2c_gate      = 0x4b,
+       .tuner_address = 0x61,
+       .tuner_config  = 0,
+       .antenna_switch= 2,
+       .request_firmware = philips_tda1004x_request_firmware
+};
 
 static struct tda1004x_config lifeview_trio_config = {
        .demod_address = 0x09,
        .invert        = 1,
        .invert_oclk   = 0,
        .xtal_freq     = TDA10046_XTAL_16M,
-       .agc_config    = TDA10046_AGC_TDA827X_GPL,
+       .agc_config    = TDA10046_AGC_TDA827X,
+       .gpio_config   = TDA10046_GP00_I,
        .if_freq       = TDA10046_FREQ_045,
-       .request_firmware = NULL,
+       .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;
-
-       ret = philips_tda827xa_pll_set(0x61, fe, params);
-       return ret;
-}
-
-static int ads_duo_tuner_init(struct dvb_frontend *fe)
-{
-       struct saa7134_dev *dev = fe->dvb->priv;
-       /* route TDA8275a AGC input to the channel decoder */
-       saa_writeb(SAA7134_GPIO_GPSTATUS2, 0x60);
-       return 0;
-}
-
-static int ads_duo_tuner_sleep(struct dvb_frontend *fe)
-{
-       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);
-       return 0;
-}
-
-static struct tda1004x_config ads_tech_duo_config = {
+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_GPL,
+       .agc_config    = TDA10046_AGC_TDA827X,
+       .gpio_config   = TDA10046_GP11_I,
        .if_freq       = TDA10046_FREQ_045,
-       .request_firmware = NULL,
+       .tuner_address = 0x60,
+       .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 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
+};
 
-static struct tda1004x_config tevion_dvbt220rf_config = {
+static struct tda1004x_config asus_p7131_4871_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,
-       .request_firmware = NULL,
+       .i2c_gate      = 0x4b,
+       .tuner_address = 0x61,
+       .tuner_config  = 2,
+       .antenna_switch= 2,
+       .request_firmware = philips_tda1004x_request_firmware
 };
 
-/* ------------------------------------------------------------------ */
+static struct tda1004x_config asus_p7131_hybrid_lna_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,
+       .i2c_gate      = 0x4b,
+       .tuner_address = 0x61,
+       .tuner_config  = 2,
+       .antenna_switch= 2,
+       .request_firmware = philips_tda1004x_request_firmware
+};
+/* ------------------------------------------------------------------
+ * special case: this card uses saa713x GPIO22 for the mode switch
+ */
 
-static int md8800_dvbt_analog_mode(struct dvb_frontend *fe)
+static int ads_duo_tuner_init(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);
+       philips_tda827x_tuner_init(fe);
+       /* route TDA8275a AGC input to the channel decoder */
+       saa7134_set_gpio(dev, 22, 1);
        return 0;
 }
 
-static int md8800_dvbt_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int ads_duo_tuner_sleep(struct dvb_frontend *fe)
 {
-       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;
+       /* route TDA8275a AGC input to the analog IF chip*/
+       saa7134_set_gpio(dev, 22, 0);
+       philips_tda827x_tuner_sleep(fe);
+       return 0;
 }
 
-static struct tda1004x_config md8800_dvbt_config = {
+static struct tda827x_config ads_duo_cfg = {
+       .lna_gain = philips_tda827x_lna_gain,
+       .init = ads_duo_tuner_init,
+       .sleep = ads_duo_tuner_sleep
+};
+
+static struct tda1004x_config ads_tech_duo_config = {
        .demod_address = 0x08,
        .invert        = 1,
        .invert_oclk   = 0,
        .xtal_freq     = TDA10046_XTAL_16M,
        .agc_config    = TDA10046_AGC_TDA827X,
+       .gpio_config   = TDA10046_GP00_I,
        .if_freq       = TDA10046_FREQ_045,
-       .request_firmware = NULL,
+       .tuner_address = 0x61,
+       .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,
@@ -1030,10 +958,13 @@ static struct nxt200x_config kworldatsc110 = {
        .set_pll_input    = nxt200x_set_pll_input,
 };
 
-/* ------------------------------------------------------------------ */
+/* ==================================================================
+ * Core code
+ */
 
 static int dvb_init(struct saa7134_dev *dev)
 {
+       int ret;
        /* init struct videobuf_dvb */
        dev->ts.nr_bufs    = 32;
        dev->ts.nr_packets = 32*4;
@@ -1047,7 +978,7 @@ static int dvb_init(struct saa7134_dev *dev)
 
        switch (dev->board) {
        case SAA7134_BOARD_PINNACLE_300I_DVBT_PAL:
-               printk("%s: pinnacle 300i dvb setup\n",dev->name);
+               dprintk("pinnacle 300i dvb setup\n");
                dev->dvb.frontend = dvb_attach(mt352_attach, &pinnacle_300i,
                                               &dev->i2c_adap);
                if (dev->dvb.frontend) {
@@ -1056,7 +987,7 @@ static int dvb_init(struct saa7134_dev *dev)
                break;
        case SAA7134_BOARD_AVERMEDIA_777:
        case SAA7134_BOARD_AVERMEDIA_A16AR:
-               printk("%s: avertv 777 dvb setup\n",dev->name);
+               dprintk("avertv 777 dvb setup\n");
                dev->dvb.frontend = dvb_attach(mt352_attach, &avermedia_777,
                                               &dev->i2c_adap);
                if (dev->dvb.frontend) {
@@ -1078,31 +1009,16 @@ static int dvb_init(struct saa7134_dev *dev)
                                               &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;
                }
                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);
                break;
        case SAA7134_BOARD_PHILIPS_EUROPA:
+       case SAA7134_BOARD_VIDEOMATE_DVBT_300:
                dev->dvb.frontend = dvb_attach(tda10046_attach,
                                               &philips_europa_config,
                                               &dev->i2c_adap);
@@ -1114,101 +1030,66 @@ static int dvb_init(struct saa7134_dev *dev)
                        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,
-                                              &dev->i2c_adap);
-               if (dev->dvb.frontend) {
-                       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_200:
                dev->dvb.frontend = dvb_attach(tda10046_attach,
                                               &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;
                }
                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.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);
+               break;
+       case SAA7134_BOARD_PINNACLE_PCTV_310i:
+               configure_tda827x_fe(dev, &pinnacle_pctv_310i_config);
+               break;
+       case SAA7134_BOARD_HAUPPAUGE_HVR1110:
+               configure_tda827x_fe(dev, &hauppauge_hvr_1110_config);
                break;
        case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
-               dev->dvb.frontend = dvb_attach(tda10046_attach,
-                                              &philips_tiger_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 = philips_tiger_tuner_sleep;
-                       dev->dvb.frontend->ops.tuner_ops.set_params = philips_tiger_tuner_set_params;
-               }
+               configure_tda827x_fe(dev, &asus_p7131_dual_config);
                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);
                break;
        case SAA7134_BOARD_FLYDVB_TRIO:
-               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;
+               if(! use_frontend) {    //terrestrial
+                       configure_tda827x_fe(dev, &lifeview_trio_config);
+               } else {              //satellite
+                       dev->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs, &dev->i2c_adap);
+                       if (dev->dvb.frontend) {
+                               if (dvb_attach(tda826x_attach, dev->dvb.frontend, 0x63,
+                                                                       &dev->i2c_adap, 0) == NULL) {
+                                       wprintk("%s: Lifeview Trio, No tda826x found!\n", __FUNCTION__);
+                               }
+                               if (dvb_attach(isl6421_attach, dev->dvb.frontend, &dev->i2c_adap,
+                                                                               0x08, 0, 0) == NULL) {
+                                       wprintk("%s: Lifeview Trio, No ISL6421 found!\n", __FUNCTION__);
+                               }
+                       }
                }
                break;
        case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331:
+       case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS:
                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;
+                       if (dvb_attach(tda827x_attach,dev->dvb.frontend,
+                                  ads_tech_duo_config.tuner_address,
+                                  &dev->i2c_adap,&ads_duo_cfg) == NULL) {
+                               wprintk("no tda827x tuner found at addr: %02x\n",
+                                       ads_tech_duo_config.tuner_address);
+                       }
                }
                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,
-                                              &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;
-               }
+               configure_tda827x_fe(dev, &tevion_dvbt220rf_config);
                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);
                break;
        case SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180:
                dev->dvb.frontend = dvb_attach(nxt200x_attach, &avertvhda180,
@@ -1232,26 +1113,72 @@ static int dvb_init(struct saa7134_dev *dev)
                if (dev->dvb.frontend) {
                        if (dvb_attach(tda826x_attach, dev->dvb.frontend, 0x60,
                                       &dev->i2c_adap, 0) == NULL) {
-                               printk("%s: No tda826x found!\n", __FUNCTION__);
+                               wprintk("%s: No tda826x found!\n", __FUNCTION__);
                        }
                        if (dvb_attach(isl6421_attach, dev->dvb.frontend,
                                       &dev->i2c_adap, 0x08, 0, 0) == NULL) {
-                               printk("%s: No ISL6421 found!\n", __FUNCTION__);
+                               wprintk("%s: No ISL6421 found!\n", __FUNCTION__);
                        }
                }
                break;
+       case SAA7134_BOARD_ASUS_EUROPA2_HYBRID:
+               dev->dvb.frontend = tda10046_attach(&medion_cardbus,
+                                                   &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_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;
+               }
+               break;
+       case SAA7134_BOARD_VIDEOMATE_DVBT_200A:
+               dev->dvb.frontend = dvb_attach(tda10046_attach,
+                               &philips_europa_config,
+                               &dev->i2c_adap);
+               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;
+               }
+               break;
+       case SAA7134_BOARD_CINERGY_HT_PCMCIA:
+               configure_tda827x_fe(dev, &cinergy_ht_config);
+               break;
+       case SAA7134_BOARD_CINERGY_HT_PCI:
+               configure_tda827x_fe(dev, &cinergy_ht_pci_config);
+               break;
+       case SAA7134_BOARD_PHILIPS_TIGER_S:
+               configure_tda827x_fe(dev, &philips_tiger_s_config);
+               break;
+       case SAA7134_BOARD_ASUS_P7131_4871:
+               configure_tda827x_fe(dev, &asus_p7131_4871_config);
+               break;
+       case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA:
+               configure_tda827x_fe(dev, &asus_p7131_hybrid_lna_config);
+               break;
        default:
-               printk("%s: Huh? unknown DVB card?\n",dev->name);
+               wprintk("Huh? unknown DVB card?\n");
                break;
        }
 
        if (NULL == dev->dvb.frontend) {
-               printk("%s: frontend initialization failed\n",dev->name);
+               printk(KERN_ERR "%s/dvb: frontend initialization failed\n", dev->name);
                return -1;
        }
 
        /* register everything else */
-       return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev, &dev->pci->dev);
+       ret = videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev, &dev->pci->dev);
+
+       /* this sequence is necessary to make the tda1004x load its firmware
+        * and to enter analog mode of hybrid boards
+        */
+       if (!ret) {
+               if (dev->dvb.frontend->ops.init)
+                       dev->dvb.frontend->ops.init(dev->dvb.frontend);
+               if (dev->dvb.frontend->ops.sleep)
+                       dev->dvb.frontend->ops.sleep(dev->dvb.frontend);
+       }
+       return ret;
 }
 
 static int dvb_fini(struct saa7134_dev *dev)