vserver 2.0 rc7
[linux-2.6.git] / drivers / media / dvb / frontends / tda1004x.c
index 1e38162..0beb370 100644 (file)
 #include "dvb_frontend.h"
 #include "tda1004x.h"
 
-#define TDA1004X_DEMOD_TDA10045 0
-#define TDA1004X_DEMOD_TDA10046 1
-
+enum tda1004x_demod {
+       TDA1004X_DEMOD_TDA10045,
+       TDA1004X_DEMOD_TDA10046,
+};
 
-struct tda1004x_state
-{
+struct tda1004x_state {
        struct i2c_adapter* i2c;
-
        struct dvb_frontend_ops ops;
-
        const struct tda1004x_config* config;
-
        struct dvb_frontend frontend;
 
        /* private demod data */
-       u8 initialised:1;
-
-       u8 demod_type;
+       u8 initialised;
+       enum tda1004x_demod demod_type;
+       u8 fw_version;
 };
 
 
@@ -144,7 +141,7 @@ static int tda1004x_write_byteI(struct tda1004x_state *state, int reg, int data)
 {
        int ret;
        u8 buf[] = { reg, data };
-       struct i2c_msg msg = { .addr=0, .flags=0, .buf=buf, .len=2 };
+       struct i2c_msg msg = { .flags = 0, .buf = buf, .len = 2 };
 
        dprintk("%s: reg=0x%x, data=0x%x\n", __FUNCTION__, reg, data);
 
@@ -165,8 +162,8 @@ static int tda1004x_read_byte(struct tda1004x_state *state, int reg)
        int ret;
        u8 b0[] = { reg };
        u8 b1[] = { 0 };
-       struct i2c_msg msg[] = {{ .addr=0, .flags=0, .buf=b0, .len=1},
-                               { .addr=0, .flags=I2C_M_RD, .buf=b1, .len = 1}};
+       struct i2c_msg msg[] = {{ .flags = 0, .buf = b0, .len = 1 },
+                               { .flags = I2C_M_RD, .buf = b1, .len = 1 }};
 
        dprintk("%s: reg=0x%x\n", __FUNCTION__, reg);
 
@@ -299,7 +296,7 @@ static int tda1004x_do_upload(struct tda1004x_state *state,
                              u8 dspCodeCounterReg, u8 dspCodeInReg)
 {
        u8 buf[65];
-       struct i2c_msg fw_msg = {.addr = 0,.flags = 0,.buf = buf,.len = 0 };
+       struct i2c_msg fw_msg = { .flags = 0, .buf = buf, .len = 0 };
        int tx_size;
        int pos = 0;
 
@@ -309,12 +306,10 @@ static int tda1004x_do_upload(struct tda1004x_state *state,
 
        buf[0] = dspCodeInReg;
        while (pos != len) {
-
                // work out how much to send this time
                tx_size = len - pos;
-               if (tx_size > 0x10) {
+               if (tx_size > 0x10)
                        tx_size = 0x10;
-               }
 
                // send the chunk
                memcpy(buf + 1, mem + pos, tx_size);
@@ -327,6 +322,7 @@ static int tda1004x_do_upload(struct tda1004x_state *state,
 
                dprintk("%s: fw_pos=0x%x\n", __FUNCTION__, pos);
        }
+
        return 0;
 }
 
@@ -340,30 +336,28 @@ static int tda1004x_check_upload_ok(struct tda1004x_state *state, u8 dspVersion)
 
        data1 = tda1004x_read_byte(state, TDA1004X_DSP_DATA1);
        data2 = tda1004x_read_byte(state, TDA1004X_DSP_DATA2);
-       if (data1 != 0x67 || data2 != dspVersion) {
+       if ((data1 != 0x67) || (data2 != dspVersion))
                return -EIO;
-       }
 
        return 0;
 }
 
-
 static int tda10045_fwupload(struct dvb_frontend* fe)
 {
        struct tda1004x_state* state = fe->demodulator_priv;
        int ret;
        const struct firmware *fw;
 
-
        /* don't re-upload unless necessary */
-       if (tda1004x_check_upload_ok(state, 0x2c) == 0) return 0;
+       if (tda1004x_check_upload_ok(state, 0x2c) == 0)
+               return 0;
 
        /* request the firmware, this will block until someone uploads it */
-       printk("tda1004x: waiting for firmware upload...\n");
+       printk("tda1004x: waiting for firmware upload (%s)...\n", TDA10045_DEFAULT_FIRMWARE);
        ret = state->config->request_firmware(fe, &fw, TDA10045_DEFAULT_FIRMWARE);
        if (ret) {
                printk("tda1004x: no firmware upload (timeout or file not found?)\n");
-               return ret;
+               return ret;
        }
 
        /* reset chip */
@@ -378,6 +372,7 @@ static int tda10045_fwupload(struct dvb_frontend* fe)
        ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10045H_FWPAGE, TDA10045H_CODE_IN);
        if (ret)
                return ret;
+       printk("tda1004x: firmware upload complete\n");
 
        /* wait for DSP to initialise */
        /* DSPREADY doesn't seem to work on the TDA10045H */
@@ -386,6 +381,25 @@ static int tda10045_fwupload(struct dvb_frontend* fe)
        return tda1004x_check_upload_ok(state, 0x2c);
 }
 
+static int tda10046_get_fw_version(struct tda1004x_state *state,
+                                  const struct firmware *fw)
+{
+       const unsigned char pattern[] = { 0x67, 0x00, 0x50, 0x62, 0x5e, 0x18, 0x67 };
+       unsigned int i;
+
+       /* area guessed from firmware v20, v21 and v25 */
+       for (i = 0x660; i < 0x700; i++) {
+               if (!memcmp(&fw->data[i], pattern, sizeof(pattern))) {
+                       state->fw_version = fw->data[i + sizeof(pattern)];
+                       printk(KERN_INFO "tda1004x: using firmware v%02x\n",
+                                       state->fw_version);
+                       return 0;
+               }
+       }
+
+       return -EINVAL;
+}
+
 static int tda10046_fwupload(struct dvb_frontend* fe)
 {
        struct tda1004x_state* state = fe->demodulator_priv;
@@ -399,19 +413,31 @@ static int tda10046_fwupload(struct dvb_frontend* fe)
        msleep(100);
 
        /* don't re-upload unless necessary */
-       if (tda1004x_check_upload_ok(state, 0x20) == 0) return 0;
+       if (tda1004x_check_upload_ok(state, state->fw_version) == 0)
+               return 0;
 
        /* request the firmware, this will block until someone uploads it */
-       printk("tda1004x: waiting for firmware upload...\n");
+       printk("tda1004x: waiting for firmware upload (%s)...\n", TDA10046_DEFAULT_FIRMWARE);
        ret = state->config->request_firmware(fe, &fw, TDA10046_DEFAULT_FIRMWARE);
        if (ret) {
                printk("tda1004x: no firmware upload (timeout or file not found?)\n");
-               return ret;
+               return ret;
+       }
+
+       if (fw->size < 24478) { /* size of firmware v20, which is the smallest of v20, v21 and v25 */
+               printk("tda1004x: firmware file seems to be too small (%d bytes)\n", fw->size);
+               return -EINVAL;
+       }
+
+       ret = tda10046_get_fw_version(state, fw);
+       if (ret < 0) {
+               printk("tda1004x: unable to find firmware version\n");
+               return ret;
        }
 
        /* set parameters */
        tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 10);
-       tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 0);
+       tda1004x_write_byteI(state, TDA10046H_CONFPLL3, state->config->n_i2c);
        tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 99);
        tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd4);
        tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x2c);
@@ -420,10 +446,11 @@ static int tda10046_fwupload(struct dvb_frontend* fe)
        ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10046H_CODE_CPT, TDA10046H_CODE_IN);
        if (ret)
                return ret;
+       printk("tda1004x: firmware upload complete\n");
 
        /* wait for DSP to initialise */
        timeout = jiffies + HZ;
-       while(!(tda1004x_read_byte(state, TDA1004X_STATUS_CD) & 0x20)) {
+       while (!(tda1004x_read_byte(state, TDA1004X_STATUS_CD) & 0x20)) {
                if (time_after(jiffies, timeout)) {
                        printk("tda1004x: DSP failed to initialised.\n");
                        return -EIO;
@@ -431,7 +458,7 @@ static int tda10046_fwupload(struct dvb_frontend* fe)
                msleep(1);
        }
 
-       return tda1004x_check_upload_ok(state, 0x20);
+       return tda1004x_check_upload_ok(state, state->fw_version);
 }
 
 static int tda1004x_encode_fec(int fec)
@@ -474,29 +501,12 @@ static int tda1004x_decode_fec(int tdafec)
        return -1;
 }
 
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
 int tda1004x_write_byte(struct dvb_frontend* fe, int reg, int data)
 {
        struct tda1004x_state* state = fe->demodulator_priv;
 
        return tda1004x_write_byteI(state, reg, data);
-               }
+}
 
 static int tda10045_init(struct dvb_frontend* fe)
 {
@@ -504,12 +514,13 @@ static int tda10045_init(struct dvb_frontend* fe)
 
        dprintk("%s\n", __FUNCTION__);
 
-       if (state->initialised) return 0;
+       if (state->initialised)
+               return 0;
 
        if (tda10045_fwupload(fe)) {
                printk("tda1004x: firmware upload failed\n");
                return -EIO;
-               }
+       }
 
        tda1004x_write_mask(state, TDA1004X_CONFADC1, 0x10, 0); // wake up the ADC
 
@@ -537,19 +548,20 @@ static int tda10045_init(struct dvb_frontend* fe)
 
        state->initialised = 1;
        return 0;
-               }
+}
 
 static int tda10046_init(struct dvb_frontend* fe)
 {
        struct tda1004x_state* state = fe->demodulator_priv;
        dprintk("%s\n", __FUNCTION__);
 
-       if (state->initialised) return 0;
+       if (state->initialised)
+               return 0;
 
        if (tda10046_fwupload(fe)) {
                printk("tda1004x: firmware upload failed\n");
-                       return -EIO;
-               }
+               return -EIO;
+       }
 
        tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 0); // wake up the chip
 
@@ -566,7 +578,7 @@ static int tda10046_init(struct dvb_frontend* fe)
        tda1004x_write_mask(state, TDA1004X_AUTO, 8, 0); // select HP stream
        tda1004x_write_mask(state, TDA1004X_CONFC1, 0x80, 0); // disable pulse killer
        tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 10); // PLL M = 10
-       tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 0); // PLL P = N = 0
+       tda1004x_write_byteI(state, TDA10046H_CONFPLL3, state->config->n_i2c); // PLL P = N = 0
        tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 99); // FREQOFFS = 99
        tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd4); // } PHY2 = -11221
        tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x2c); // }
@@ -623,9 +635,9 @@ static int tda1004x_set_fe(struct dvb_frontend* fe,
        // Hardcoded to use auto as much as possible on the TDA10045 as it
        // is very unreliable if AUTO mode is _not_ used.
        if (state->demod_type == TDA1004X_DEMOD_TDA10045) {
-       fe_params->u.ofdm.code_rate_HP = FEC_AUTO;
-       fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO;
-       fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO;
+               fe_params->u.ofdm.code_rate_HP = FEC_AUTO;
+               fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO;
+               fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO;
        }
 
        // Set standard params.. or put them to auto
@@ -642,12 +654,14 @@ static int tda1004x_set_fe(struct dvb_frontend* fe,
 
                // set HP FEC
                tmp = tda1004x_encode_fec(fe_params->u.ofdm.code_rate_HP);
-               if (tmp < 0) return tmp;
+               if (tmp < 0)
+                       return tmp;
                tda1004x_write_mask(state, TDA1004X_IN_CONF2, 7, tmp);
 
                // set LP FEC
                tmp = tda1004x_encode_fec(fe_params->u.ofdm.code_rate_LP);
-               if (tmp < 0) return tmp;
+               if (tmp < 0)
+                       return tmp;
                tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0x38, tmp << 3);
 
                // set constellation
@@ -692,7 +706,7 @@ static int tda1004x_set_fe(struct dvb_frontend* fe,
        }
 
        // set bandwidth
-       switch(state->demod_type) {
+       switch (state->demod_type) {
        case TDA1004X_DEMOD_TDA10045:
                tda10045h_set_bandwidth(state, fe_params->u.ofdm.bandwidth);
                break;
@@ -704,7 +718,8 @@ static int tda1004x_set_fe(struct dvb_frontend* fe,
 
        // set inversion
        inversion = fe_params->inversion;
-       if (state->config->invert) inversion = inversion ? INVERSION_OFF : INVERSION_ON;
+       if (state->config->invert)
+               inversion = inversion ? INVERSION_OFF : INVERSION_ON;
        switch (inversion) {
        case INVERSION_OFF:
                tda1004x_write_mask(state, TDA1004X_CONFC1, 0x20, 0);
@@ -771,19 +786,19 @@ static int tda1004x_set_fe(struct dvb_frontend* fe,
        }
 
        // start the lock
-       switch(state->demod_type) {
+       switch (state->demod_type) {
        case TDA1004X_DEMOD_TDA10045:
                tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8);
                tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 0);
-               msleep(10);
                break;
 
        case TDA1004X_DEMOD_TDA10046:
                tda1004x_write_mask(state, TDA1004X_AUTO, 0x40, 0x40);
-               msleep(10);
                break;
        }
 
+       msleep(10);
+
        return 0;
 }
 
@@ -794,13 +809,13 @@ static int tda1004x_get_fe(struct dvb_frontend* fe, struct dvb_frontend_paramete
 
        // inversion status
        fe_params->inversion = INVERSION_OFF;
-       if (tda1004x_read_byte(state, TDA1004X_CONFC1) & 0x20) {
+       if (tda1004x_read_byte(state, TDA1004X_CONFC1) & 0x20)
                fe_params->inversion = INVERSION_ON;
-       }
-       if (state->config->invert) fe_params->inversion = fe_params->inversion ? INVERSION_OFF : INVERSION_ON;
+       if (state->config->invert)
+               fe_params->inversion = fe_params->inversion ? INVERSION_OFF : INVERSION_ON;
 
        // bandwidth
-       switch(state->demod_type) {
+       switch (state->demod_type) {
        case TDA1004X_DEMOD_TDA10045:
                switch (tda1004x_read_byte(state, TDA10045H_WREF_LSB)) {
                case 0x14:
@@ -851,9 +866,8 @@ static int tda1004x_get_fe(struct dvb_frontend* fe, struct dvb_frontend_paramete
 
        // transmission mode
        fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K;
-       if (tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x10) {
+       if (tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x10)
                fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
-       }
 
        // guard interval
        switch ((tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x0c) >> 2) {
@@ -901,30 +915,33 @@ static int tda1004x_read_status(struct dvb_frontend* fe, fe_status_t * fe_status
 
        // read status
        status = tda1004x_read_byte(state, TDA1004X_STATUS_CD);
-       if (status == -1) {
+       if (status == -1)
                return -EIO;
-       }
 
        // decode
        *fe_status = 0;
-       if (status & 4) *fe_status |= FE_HAS_SIGNAL;
-       if (status & 2) *fe_status |= FE_HAS_CARRIER;
-       if (status & 8) *fe_status |= FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+       if (status & 4)
+               *fe_status |= FE_HAS_SIGNAL;
+       if (status & 2)
+               *fe_status |= FE_HAS_CARRIER;
+       if (status & 8)
+               *fe_status |= FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
 
        // if we don't already have VITERBI (i.e. not LOCKED), see if the viterbi
        // is getting anything valid
        if (!(*fe_status & FE_HAS_VITERBI)) {
                // read the CBER
                cber = tda1004x_read_byte(state, TDA1004X_CBER_LSB);
-               if (cber == -1) return -EIO;
+               if (cber == -1)
+                       return -EIO;
                status = tda1004x_read_byte(state, TDA1004X_CBER_MSB);
-               if (status == -1) return -EIO;
+               if (status == -1)
+                       return -EIO;
                cber |= (status << 8);
                tda1004x_read_byte(state, TDA1004X_CBER_RESET);
 
-               if (cber != 65535) {
+               if (cber != 65535)
                        *fe_status |= FE_HAS_VITERBI;
-               }
        }
 
        // if we DO have some valid VITERBI output, but don't already have SYNC
@@ -932,20 +949,22 @@ static int tda1004x_read_status(struct dvb_frontend* fe, fe_status_t * fe_status
        if ((*fe_status & FE_HAS_VITERBI) && (!(*fe_status & FE_HAS_SYNC))) {
                // read the VBER
                vber = tda1004x_read_byte(state, TDA1004X_VBER_LSB);
-               if (vber == -1) return -EIO;
+               if (vber == -1)
+                       return -EIO;
                status = tda1004x_read_byte(state, TDA1004X_VBER_MID);
-               if (status == -1) return -EIO;
+               if (status == -1)
+                       return -EIO;
                vber |= (status << 8);
                status = tda1004x_read_byte(state, TDA1004X_VBER_MSB);
-               if (status == -1) return -EIO;
+               if (status == -1)
+                       return -EIO;
                vber |= ((status << 16) & 0x0f);
                tda1004x_read_byte(state, TDA1004X_CVBER_LUT);
 
                // if RS has passed some valid TS packets, then we must be
                // getting some SYNC bytes
-               if (vber < 16632) {
+               if (vber < 16632)
                        *fe_status |= FE_HAS_SYNC;
-               }
        }
 
        // success
@@ -962,7 +981,7 @@ static int tda1004x_read_signal_strength(struct dvb_frontend* fe, u16 * signal)
        dprintk("%s\n", __FUNCTION__);
 
        // determine the register to use
-       switch(state->demod_type) {
+       switch (state->demod_type) {
        case TDA1004X_DEMOD_TDA10045:
                reg = TDA10045H_S_AGC;
                break;
@@ -993,9 +1012,8 @@ static int tda1004x_read_snr(struct dvb_frontend* fe, u16 * snr)
        tmp = tda1004x_read_byte(state, TDA1004X_SNR);
        if (tmp < 0)
                return -EIO;
-       if (tmp) {
+       if (tmp)
                tmp = 255 - tmp;
-       }
 
        *snr = ((tmp << 8) | tmp);
        dprintk("%s: snr=0x%x\n", __FUNCTION__, *snr);
@@ -1030,11 +1048,11 @@ static int tda1004x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
                        break;
        }
 
-       if (tmp != 0x7f) {
+       if (tmp != 0x7f)
                *ucblocks = tmp;
-       } else {
+       else
                *ucblocks = 0xffffffff;
-       }
+
        dprintk("%s: ucblocks=0x%x\n", __FUNCTION__, *ucblocks);
        return 0;
 }
@@ -1048,10 +1066,12 @@ static int tda1004x_read_ber(struct dvb_frontend* fe, u32* ber)
 
        // read it in
        tmp = tda1004x_read_byte(state, TDA1004X_CBER_LSB);
-       if (tmp < 0) return -EIO;
+       if (tmp < 0)
+               return -EIO;
        *ber = tmp << 1;
        tmp = tda1004x_read_byte(state, TDA1004X_CBER_MSB);
-       if (tmp < 0) return -EIO;
+       if (tmp < 0)
+               return -EIO;
        *ber |= (tmp << 9);
        tda1004x_read_byte(state, TDA1004X_CBER_RESET);
 
@@ -1063,98 +1083,35 @@ static int tda1004x_sleep(struct dvb_frontend* fe)
 {
        struct tda1004x_state* state = fe->demodulator_priv;
 
-       switch(state->demod_type) {
+       switch (state->demod_type) {
        case TDA1004X_DEMOD_TDA10045:
                tda1004x_write_mask(state, TDA1004X_CONFADC1, 0x10, 0x10);
-                       break;
+               break;
 
        case TDA1004X_DEMOD_TDA10046:
                tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 1);
-                       break;
-               }
+               break;
+       }
        state->initialised = 0;
 
-                       return 0;
-               }
+       return 0;
+}
 
 static int tda1004x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
-       {
-               fesettings->min_delay_ms = 800;
-               fesettings->step_size = 166667;
-               fesettings->max_drift = 166667*2;
-               return 0;
-       }
+{
+       fesettings->min_delay_ms = 800;
+       fesettings->step_size = 166667;
+       fesettings->max_drift = 166667*2;
+       return 0;
+}
 
 static void tda1004x_release(struct dvb_frontend* fe)
 {
-       struct tda1004x_state* state = (struct tda1004x_state*) fe->demodulator_priv;
+       struct tda1004x_state *state = fe->demodulator_priv;
        kfree(state);
-       }
-
-static struct dvb_frontend_ops tda10045_ops;
-
-struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config,
-                                    struct i2c_adapter* i2c)
-{
-       struct tda1004x_state* state = NULL;
-
-       /* allocate memory for the internal state */
-       state = (struct tda1004x_state*) kmalloc(sizeof(struct tda1004x_state), GFP_KERNEL);
-       if (state == NULL) goto error;
-
-       /* setup the state */
-       state->config = config;
-       state->i2c = i2c;
-       memcpy(&state->ops, &tda10045_ops, sizeof(struct dvb_frontend_ops));
-       state->initialised = 0;
-       state->demod_type = TDA1004X_DEMOD_TDA10045;
-
-       /* check if the demod is there */
-       if (tda1004x_read_byte(state, TDA1004X_CHIPID) != 0x25) goto error;
-
-       /* create dvb_frontend */
-       state->frontend.ops = &state->ops;
-       state->frontend.demodulator_priv = state;
-       return &state->frontend;
-
-error:
-       if (state) kfree(state);
-       return NULL;
-       }
-
-static struct dvb_frontend_ops tda10046_ops;
-
-struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config,
-                                    struct i2c_adapter* i2c)
-{
-       struct tda1004x_state* state = NULL;
-
-       /* allocate memory for the internal state */
-       state = (struct tda1004x_state*) kmalloc(sizeof(struct tda1004x_state), GFP_KERNEL);
-       if (state == NULL) goto error;
-
-       /* setup the state */
-       state->config = config;
-       state->i2c = i2c;
-       memcpy(&state->ops, &tda10046_ops, sizeof(struct dvb_frontend_ops));
-       state->initialised = 0;
-       state->demod_type = TDA1004X_DEMOD_TDA10046;
-
-       /* check if the demod is there */
-       if (tda1004x_read_byte(state, TDA1004X_CHIPID) != 0x46) goto error;
-
-       /* create dvb_frontend */
-       state->frontend.ops = &state->ops;
-       state->frontend.demodulator_priv = state;
-       return &state->frontend;
-
-error:
-       if (state) kfree(state);
-       return NULL;
-               }
+}
 
 static struct dvb_frontend_ops tda10045_ops = {
-
        .info = {
                .name = "Philips TDA10045H DVB-T",
                .type = FE_OFDM,
@@ -1184,8 +1141,36 @@ static struct dvb_frontend_ops tda10045_ops = {
        .read_ucblocks = tda1004x_read_ucblocks,
 };
 
-static struct dvb_frontend_ops tda10046_ops = {
+struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config,
+                                    struct i2c_adapter* i2c)
+{
+       struct tda1004x_state *state;
+
+       /* allocate memory for the internal state */
+       state = kmalloc(sizeof(struct tda1004x_state), GFP_KERNEL);
+       if (!state)
+               return NULL;
+
+       /* setup the state */
+       state->config = config;
+       state->i2c = i2c;
+       memcpy(&state->ops, &tda10045_ops, sizeof(struct dvb_frontend_ops));
+       state->initialised = 0;
+       state->demod_type = TDA1004X_DEMOD_TDA10045;
+
+       /* check if the demod is there */
+       if (tda1004x_read_byte(state, TDA1004X_CHIPID) != 0x25) {
+               kfree(state);
+               return NULL;
+       }
+
+       /* create dvb_frontend */
+       state->frontend.ops = &state->ops;
+       state->frontend.demodulator_priv = state;
+       return &state->frontend;
+}
 
+static struct dvb_frontend_ops tda10046_ops = {
        .info = {
                .name = "Philips TDA10046H DVB-T",
                .type = FE_OFDM,
@@ -1215,6 +1200,36 @@ static struct dvb_frontend_ops tda10046_ops = {
        .read_ucblocks = tda1004x_read_ucblocks,
 };
 
+struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config,
+                                    struct i2c_adapter* i2c)
+{
+       struct tda1004x_state *state;
+
+       /* allocate memory for the internal state */
+       state = kmalloc(sizeof(struct tda1004x_state), GFP_KERNEL);
+       if (!state)
+               return NULL;
+
+       /* setup the state */
+       state->config = config;
+       state->i2c = i2c;
+       memcpy(&state->ops, &tda10046_ops, sizeof(struct dvb_frontend_ops));
+       state->initialised = 0;
+       state->demod_type = TDA1004X_DEMOD_TDA10046;
+       state->fw_version = 0x20;       /* dummy default value */
+
+       /* check if the demod is there */
+       if (tda1004x_read_byte(state, TDA1004X_CHIPID) != 0x46) {
+               kfree(state);
+               return NULL;
+       }
+
+       /* create dvb_frontend */
+       state->frontend.ops = &state->ops;
+       state->frontend.demodulator_priv = state;
+       return &state->frontend;
+}
+
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");