Merge branch 'rmobile-latest' of git://git.kernel.org/pub/scm/linux/kernel/git/lethal...
[pandora-kernel.git] / drivers / media / dvb / frontends / ds3000.c
index fc61d92..90bf573 100644 (file)
@@ -229,31 +229,11 @@ static u8 ds3000_dvbs2_init_tab[] = {
        0xb8, 0x00,
 };
 
-/* DS3000 doesn't need some parameters as input and auto-detects them */
-/* save input from the application of those parameters */
-struct ds3000_tuning {
-       u32 frequency;
-       u32 symbol_rate;
-       fe_spectral_inversion_t inversion;
-       enum fe_code_rate fec;
-
-       /* input values */
-       u8 inversion_val;
-       fe_modulation_t delivery;
-       u8 rolloff;
-};
-
 struct ds3000_state {
        struct i2c_adapter *i2c;
        const struct ds3000_config *config;
-
        struct dvb_frontend frontend;
-
-       struct ds3000_tuning dcur;
-       struct ds3000_tuning dnxt;
-
        u8 skip_fw_load;
-
        /* previous uncorrected block counter for DVB-S2 */
        u16 prevUCBS2;
 };
@@ -305,7 +285,7 @@ static int ds3000_writeFW(struct ds3000_state *state, int reg,
        struct i2c_msg msg;
        u8 *buf;
 
-       buf = kmalloc(3, GFP_KERNEL);
+       buf = kmalloc(33, GFP_KERNEL);
        if (buf == NULL) {
                printk(KERN_ERR "Unable to kmalloc\n");
                ret = -ENOMEM;
@@ -317,10 +297,10 @@ static int ds3000_writeFW(struct ds3000_state *state, int reg,
        msg.addr = state->config->demod_address;
        msg.flags = 0;
        msg.buf = buf;
-       msg.len = 3;
+       msg.len = 33;
 
-       for (i = 0; i < len; i += 2) {
-               memcpy(buf + 1, data + i, 2);
+       for (i = 0; i < len; i += 32) {
+               memcpy(buf + 1, data + i, 32);
 
                dprintk("%s: write reg 0x%02x, len = %d\n", __func__, reg, len);
 
@@ -401,45 +381,6 @@ static int ds3000_tuner_readreg(struct ds3000_state *state, u8 reg)
        return b1[0];
 }
 
-static int ds3000_set_inversion(struct ds3000_state *state,
-                                       fe_spectral_inversion_t inversion)
-{
-       dprintk("%s(%d)\n", __func__, inversion);
-
-       switch (inversion) {
-       case INVERSION_OFF:
-       case INVERSION_ON:
-       case INVERSION_AUTO:
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       state->dnxt.inversion = inversion;
-
-       return 0;
-}
-
-static int ds3000_set_symbolrate(struct ds3000_state *state, u32 rate)
-{
-       int ret = 0;
-
-       dprintk("%s()\n", __func__);
-
-       dprintk("%s() symbol_rate = %d\n", __func__, state->dnxt.symbol_rate);
-
-       /*  check if symbol rate is within limits */
-       if ((state->dnxt.symbol_rate >
-                               state->frontend.ops.info.symbol_rate_max) ||
-           (state->dnxt.symbol_rate <
-                               state->frontend.ops.info.symbol_rate_min))
-               ret = -EOPNOTSUPP;
-
-       state->dnxt.symbol_rate = rate;
-
-       return ret;
-}
-
 static int ds3000_load_firmware(struct dvb_frontend *fe,
                                        const struct firmware *fw);
 
@@ -509,23 +450,31 @@ static int ds3000_load_firmware(struct dvb_frontend *fe,
        return 0;
 }
 
-static void ds3000_dump_registers(struct dvb_frontend *fe)
+static int ds3000_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
 {
        struct ds3000_state *state = fe->demodulator_priv;
-       int x, y, reg = 0, val;
-
-       for (y = 0; y < 16; y++) {
-               dprintk("%s: %02x: ", __func__, y);
-               for (x = 0; x < 16; x++) {
-                       reg = (y << 4) + x;
-                       val = ds3000_readreg(state, reg);
-                       if (x != 15)
-                               dprintk("%02x ",  val);
-                       else
-                               dprintk("%02x\n", val);
-               }
+       u8 data;
+
+       dprintk("%s(%d)\n", __func__, voltage);
+
+       data = ds3000_readreg(state, 0xa2);
+       data |= 0x03; /* bit0 V/H, bit1 off/on */
+
+       switch (voltage) {
+       case SEC_VOLTAGE_18:
+               data &= ~0x03;
+               break;
+       case SEC_VOLTAGE_13:
+               data &= ~0x03;
+               data |= 0x01;
+               break;
+       case SEC_VOLTAGE_OFF:
+               break;
        }
-       dprintk("%s: -- DS3000 DUMP DONE --\n", __func__);
+
+       ds3000_writereg(state, 0xa2, data);
+
+       return 0;
 }
 
 static int ds3000_read_status(struct dvb_frontend *fe, fe_status_t* status)
@@ -562,16 +511,6 @@ static int ds3000_read_status(struct dvb_frontend *fe, fe_status_t* status)
        return 0;
 }
 
-#define FE_IS_TUNED (FE_HAS_SIGNAL + FE_HAS_LOCK)
-static int ds3000_is_tuned(struct dvb_frontend *fe)
-{
-       fe_status_t tunerstat;
-
-       ds3000_read_status(fe, &tunerstat);
-
-       return ((tunerstat & FE_IS_TUNED) == FE_IS_TUNED);
-}
-
 /* read DS3000 BER value */
 static int ds3000_read_ber(struct dvb_frontend *fe, u32* ber)
 {
@@ -792,13 +731,6 @@ static int ds3000_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
        return 0;
 }
 
-/* Overwrite the current tuning params, we are about to tune */
-static void ds3000_clone_params(struct dvb_frontend *fe)
-{
-       struct ds3000_state *state = fe->demodulator_priv;
-       memcpy(&state->dcur, &state->dnxt, sizeof(state->dcur));
-}
-
 static int ds3000_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
 {
        struct ds3000_state *state = fe->demodulator_priv;
@@ -1016,287 +948,298 @@ static int ds3000_get_property(struct dvb_frontend *fe,
        return 0;
 }
 
-static int ds3000_tune(struct dvb_frontend *fe,
+static int ds3000_set_carrier_offset(struct dvb_frontend *fe,
+                                       s32 carrier_offset_khz)
+{
+       struct ds3000_state *state = fe->demodulator_priv;
+       s32 tmp;
+
+       tmp = carrier_offset_khz;
+       tmp *= 65536;
+       tmp = (2 * tmp + DS3000_SAMPLE_RATE) / (2 * DS3000_SAMPLE_RATE);
+
+       if (tmp < 0)
+               tmp += 65536;
+
+       ds3000_writereg(state, 0x5f, tmp >> 8);
+       ds3000_writereg(state, 0x5e, tmp & 0xff);
+
+       return 0;
+}
+
+static int ds3000_set_frontend(struct dvb_frontend *fe,
                                struct dvb_frontend_parameters *p)
 {
        struct ds3000_state *state = fe->demodulator_priv;
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 
-       int ret = 0, retune, i;
-       u8 status, mlpf, mlpf_new, mlpf_max, mlpf_min, nlpf;
+       int i;
+       fe_status_t status;
+       u8 mlpf, mlpf_new, mlpf_max, mlpf_min, nlpf, div4;
+       s32 offset_khz;
        u16 value, ndiv;
        u32 f3db;
 
        dprintk("%s() ", __func__);
 
-       /* Load the firmware if required */
-       ret = ds3000_firmware_ondemand(fe);
-       if (ret != 0) {
-               printk(KERN_ERR "%s: Unable initialise the firmware\n",
-                                                               __func__);
-               return ret;
+       if (state->config->set_ts_params)
+               state->config->set_ts_params(fe, 0);
+       /* Tune */
+       /* unknown */
+       ds3000_tuner_writereg(state, 0x07, 0x02);
+       ds3000_tuner_writereg(state, 0x10, 0x00);
+       ds3000_tuner_writereg(state, 0x60, 0x79);
+       ds3000_tuner_writereg(state, 0x08, 0x01);
+       ds3000_tuner_writereg(state, 0x00, 0x01);
+       div4 = 0;
+
+       /* calculate and set freq divider */
+       if (p->frequency < 1146000) {
+               ds3000_tuner_writereg(state, 0x10, 0x11);
+               div4 = 1;
+               ndiv = ((p->frequency * (6 + 8) * 4) +
+                               (DS3000_XTAL_FREQ / 2)) /
+                               DS3000_XTAL_FREQ - 1024;
+       } else {
+               ds3000_tuner_writereg(state, 0x10, 0x01);
+               ndiv = ((p->frequency * (6 + 8) * 2) +
+                               (DS3000_XTAL_FREQ / 2)) /
+                               DS3000_XTAL_FREQ - 1024;
        }
 
-       state->dnxt.delivery = c->modulation;
-       state->dnxt.frequency = c->frequency;
-       state->dnxt.rolloff = 2; /* fixme */
-       state->dnxt.fec = c->fec_inner;
+       ds3000_tuner_writereg(state, 0x01, (ndiv & 0x0f00) >> 8);
+       ds3000_tuner_writereg(state, 0x02, ndiv & 0x00ff);
+
+       /* set pll */
+       ds3000_tuner_writereg(state, 0x03, 0x06);
+       ds3000_tuner_writereg(state, 0x51, 0x0f);
+       ds3000_tuner_writereg(state, 0x51, 0x1f);
+       ds3000_tuner_writereg(state, 0x50, 0x10);
+       ds3000_tuner_writereg(state, 0x50, 0x00);
+       msleep(5);
+
+       /* unknown */
+       ds3000_tuner_writereg(state, 0x51, 0x17);
+       ds3000_tuner_writereg(state, 0x51, 0x1f);
+       ds3000_tuner_writereg(state, 0x50, 0x08);
+       ds3000_tuner_writereg(state, 0x50, 0x00);
+       msleep(5);
+
+       value = ds3000_tuner_readreg(state, 0x3d);
+       value &= 0x0f;
+       if ((value > 4) && (value < 15)) {
+               value -= 3;
+               if (value < 4)
+                       value = 4;
+               value = ((value << 3) | 0x01) & 0x79;
+       }
 
-       ret = ds3000_set_inversion(state, p->inversion);
-       if (ret !=  0)
-               return ret;
+       ds3000_tuner_writereg(state, 0x60, value);
+       ds3000_tuner_writereg(state, 0x51, 0x17);
+       ds3000_tuner_writereg(state, 0x51, 0x1f);
+       ds3000_tuner_writereg(state, 0x50, 0x08);
+       ds3000_tuner_writereg(state, 0x50, 0x00);
+
+       /* set low-pass filter period */
+       ds3000_tuner_writereg(state, 0x04, 0x2e);
+       ds3000_tuner_writereg(state, 0x51, 0x1b);
+       ds3000_tuner_writereg(state, 0x51, 0x1f);
+       ds3000_tuner_writereg(state, 0x50, 0x04);
+       ds3000_tuner_writereg(state, 0x50, 0x00);
+       msleep(5);
+
+       f3db = ((c->symbol_rate / 1000) << 2) / 5 + 2000;
+       if ((c->symbol_rate / 1000) < 5000)
+               f3db += 3000;
+       if (f3db < 7000)
+               f3db = 7000;
+       if (f3db > 40000)
+               f3db = 40000;
+
+       /* set low-pass filter baseband */
+       value = ds3000_tuner_readreg(state, 0x26);
+       mlpf = 0x2e * 207 / ((value << 1) + 151);
+       mlpf_max = mlpf * 135 / 100;
+       mlpf_min = mlpf * 78 / 100;
+       if (mlpf_max > 63)
+               mlpf_max = 63;
+
+       /* rounded to the closest integer */
+       nlpf = ((mlpf * f3db * 1000) + (2766 * DS3000_XTAL_FREQ / 2))
+                       / (2766 * DS3000_XTAL_FREQ);
+       if (nlpf > 23)
+               nlpf = 23;
+       if (nlpf < 1)
+               nlpf = 1;
+
+       /* rounded to the closest integer */
+       mlpf_new = ((DS3000_XTAL_FREQ * nlpf * 2766) +
+                       (1000 * f3db / 2)) / (1000 * f3db);
+
+       if (mlpf_new < mlpf_min) {
+               nlpf++;
+               mlpf_new = ((DS3000_XTAL_FREQ * nlpf * 2766) +
+                               (1000 * f3db / 2)) / (1000 * f3db);
+       }
 
-       ret = ds3000_set_symbolrate(state, c->symbol_rate);
-       if (ret !=  0)
-               return ret;
+       if (mlpf_new > mlpf_max)
+               mlpf_new = mlpf_max;
+
+       ds3000_tuner_writereg(state, 0x04, mlpf_new);
+       ds3000_tuner_writereg(state, 0x06, nlpf);
+       ds3000_tuner_writereg(state, 0x51, 0x1b);
+       ds3000_tuner_writereg(state, 0x51, 0x1f);
+       ds3000_tuner_writereg(state, 0x50, 0x04);
+       ds3000_tuner_writereg(state, 0x50, 0x00);
+       msleep(5);
+
+       /* unknown */
+       ds3000_tuner_writereg(state, 0x51, 0x1e);
+       ds3000_tuner_writereg(state, 0x51, 0x1f);
+       ds3000_tuner_writereg(state, 0x50, 0x01);
+       ds3000_tuner_writereg(state, 0x50, 0x00);
+       msleep(60);
+
+       offset_khz = (ndiv - ndiv % 2 + 1024) * DS3000_XTAL_FREQ
+               / (6 + 8) / (div4 + 1) / 2 - p->frequency;
+
+       /* ds3000 global reset */
+       ds3000_writereg(state, 0x07, 0x80);
+       ds3000_writereg(state, 0x07, 0x00);
+       /* ds3000 build-in uC reset */
+       ds3000_writereg(state, 0xb2, 0x01);
+       /* ds3000 software reset */
+       ds3000_writereg(state, 0x00, 0x01);
 
-       /* discard the 'current' tuning parameters and prepare to tune */
-       ds3000_clone_params(fe);
-
-       retune = 1;     /* try 1 times */
-       dprintk("%s:   retune = %d\n", __func__, retune);
-       dprintk("%s:   frequency   = %d\n", __func__, state->dcur.frequency);
-       dprintk("%s:   symbol_rate = %d\n", __func__, state->dcur.symbol_rate);
-       dprintk("%s:   FEC       = %d \n", __func__,
-               state->dcur.fec);
-       dprintk("%s:   Inversion   = %d\n", __func__, state->dcur.inversion);
-
-       do {
-               /* Reset status register */
-               status = 0;
-               /* Tune */
-               /* TS2020 init */
-               ds3000_tuner_writereg(state, 0x42, 0x73);
-               ds3000_tuner_writereg(state, 0x05, 0x01);
-               ds3000_tuner_writereg(state, 0x62, 0xf5);
-               /* unknown */
-               ds3000_tuner_writereg(state, 0x07, 0x02);
-               ds3000_tuner_writereg(state, 0x10, 0x00);
-               ds3000_tuner_writereg(state, 0x60, 0x79);
-               ds3000_tuner_writereg(state, 0x08, 0x01);
-               ds3000_tuner_writereg(state, 0x00, 0x01);
-               /* calculate and set freq divider */
-               if (state->dcur.frequency < 1146000) {
-                       ds3000_tuner_writereg(state, 0x10, 0x11);
-                       ndiv = ((state->dcur.frequency * (6 + 8) * 4) +
-                                       (DS3000_XTAL_FREQ / 2)) /
-                                       DS3000_XTAL_FREQ - 1024;
-               } else {
-                       ds3000_tuner_writereg(state, 0x10, 0x01);
-                       ndiv = ((state->dcur.frequency * (6 + 8) * 2) +
-                                       (DS3000_XTAL_FREQ / 2)) /
-                                       DS3000_XTAL_FREQ - 1024;
-               }
+       switch (c->delivery_system) {
+       case SYS_DVBS:
+               /* initialise the demod in DVB-S mode */
+               for (i = 0; i < sizeof(ds3000_dvbs_init_tab); i += 2)
+                       ds3000_writereg(state,
+                               ds3000_dvbs_init_tab[i],
+                               ds3000_dvbs_init_tab[i + 1]);
+               value = ds3000_readreg(state, 0xfe);
+               value &= 0xc0;
+               value |= 0x1b;
+               ds3000_writereg(state, 0xfe, value);
+               break;
+       case SYS_DVBS2:
+               /* initialise the demod in DVB-S2 mode */
+               for (i = 0; i < sizeof(ds3000_dvbs2_init_tab); i += 2)
+                       ds3000_writereg(state,
+                               ds3000_dvbs2_init_tab[i],
+                               ds3000_dvbs2_init_tab[i + 1]);
+               ds3000_writereg(state, 0xfe, 0x98);
+               break;
+       default:
+               return 1;
+       }
 
-               ds3000_tuner_writereg(state, 0x01, (ndiv & 0x0f00) >> 8);
-               ds3000_tuner_writereg(state, 0x02, ndiv & 0x00ff);
-
-               /* set pll */
-               ds3000_tuner_writereg(state, 0x03, 0x06);
-               ds3000_tuner_writereg(state, 0x51, 0x0f);
-               ds3000_tuner_writereg(state, 0x51, 0x1f);
-               ds3000_tuner_writereg(state, 0x50, 0x10);
-               ds3000_tuner_writereg(state, 0x50, 0x00);
-               msleep(5);
-
-               /* unknown */
-               ds3000_tuner_writereg(state, 0x51, 0x17);
-               ds3000_tuner_writereg(state, 0x51, 0x1f);
-               ds3000_tuner_writereg(state, 0x50, 0x08);
-               ds3000_tuner_writereg(state, 0x50, 0x00);
-               msleep(5);
-
-               value = ds3000_tuner_readreg(state, 0x3d);
-               value &= 0x0f;
-               if ((value > 4) && (value < 15)) {
-                       value -= 3;
-                       if (value < 4)
-                               value = 4;
-                       value = ((value << 3) | 0x01) & 0x79;
-               }
+       /* enable 27MHz clock output */
+       ds3000_writereg(state, 0x29, 0x80);
+       /* enable ac coupling */
+       ds3000_writereg(state, 0x25, 0x8a);
+
+       /* enhance symbol rate performance */
+       if ((c->symbol_rate / 1000) <= 5000) {
+               value = 29777 / (c->symbol_rate / 1000) + 1;
+               if (value % 2 != 0)
+                       value++;
+               ds3000_writereg(state, 0xc3, 0x0d);
+               ds3000_writereg(state, 0xc8, value);
+               ds3000_writereg(state, 0xc4, 0x10);
+               ds3000_writereg(state, 0xc7, 0x0e);
+       } else if ((c->symbol_rate / 1000) <= 10000) {
+               value = 92166 / (c->symbol_rate / 1000) + 1;
+               if (value % 2 != 0)
+                       value++;
+               ds3000_writereg(state, 0xc3, 0x07);
+               ds3000_writereg(state, 0xc8, value);
+               ds3000_writereg(state, 0xc4, 0x09);
+               ds3000_writereg(state, 0xc7, 0x12);
+       } else if ((c->symbol_rate / 1000) <= 20000) {
+               value = 64516 / (c->symbol_rate / 1000) + 1;
+               ds3000_writereg(state, 0xc3, value);
+               ds3000_writereg(state, 0xc8, 0x0e);
+               ds3000_writereg(state, 0xc4, 0x07);
+               ds3000_writereg(state, 0xc7, 0x18);
+       } else {
+               value = 129032 / (c->symbol_rate / 1000) + 1;
+               ds3000_writereg(state, 0xc3, value);
+               ds3000_writereg(state, 0xc8, 0x0a);
+               ds3000_writereg(state, 0xc4, 0x05);
+               ds3000_writereg(state, 0xc7, 0x24);
+       }
 
-               ds3000_tuner_writereg(state, 0x60, value);
-               ds3000_tuner_writereg(state, 0x51, 0x17);
-               ds3000_tuner_writereg(state, 0x51, 0x1f);
-               ds3000_tuner_writereg(state, 0x50, 0x08);
-               ds3000_tuner_writereg(state, 0x50, 0x00);
-
-               /* set low-pass filter period */
-               ds3000_tuner_writereg(state, 0x04, 0x2e);
-               ds3000_tuner_writereg(state, 0x51, 0x1b);
-               ds3000_tuner_writereg(state, 0x51, 0x1f);
-               ds3000_tuner_writereg(state, 0x50, 0x04);
-               ds3000_tuner_writereg(state, 0x50, 0x00);
-               msleep(5);
-
-               f3db = ((state->dcur.symbol_rate / 1000) << 2) / 5 + 2000;
-               if ((state->dcur.symbol_rate / 1000) < 5000)
-                       f3db += 3000;
-               if (f3db < 7000)
-                       f3db = 7000;
-               if (f3db > 40000)
-                       f3db = 40000;
-
-               /* set low-pass filter baseband */
-               value = ds3000_tuner_readreg(state, 0x26);
-               mlpf = 0x2e * 207 / ((value << 1) + 151);
-               mlpf_max = mlpf * 135 / 100;
-               mlpf_min = mlpf * 78 / 100;
-               if (mlpf_max > 63)
-                       mlpf_max = 63;
-
-               /* rounded to the closest integer */
-               nlpf = ((mlpf * f3db * 1000) + (2766 * DS3000_XTAL_FREQ / 2))
-                               / (2766 * DS3000_XTAL_FREQ);
-               if (nlpf > 23)
-                       nlpf = 23;
-               if (nlpf < 1)
-                       nlpf = 1;
-
-               /* rounded to the closest integer */
-               mlpf_new = ((DS3000_XTAL_FREQ * nlpf * 2766) +
-                               (1000 * f3db / 2)) / (1000 * f3db);
+       /* normalized symbol rate rounded to the closest integer */
+       value = (((c->symbol_rate / 1000) << 16) +
+                       (DS3000_SAMPLE_RATE / 2)) / DS3000_SAMPLE_RATE;
+       ds3000_writereg(state, 0x61, value & 0x00ff);
+       ds3000_writereg(state, 0x62, (value & 0xff00) >> 8);
 
-               if (mlpf_new < mlpf_min) {
-                       nlpf++;
-                       mlpf_new = ((DS3000_XTAL_FREQ * nlpf * 2766) +
-                                       (1000 * f3db / 2)) / (1000 * f3db);
-               }
+       /* co-channel interference cancellation disabled */
+       ds3000_writereg(state, 0x56, 0x00);
+
+       /* equalizer disabled */
+       ds3000_writereg(state, 0x76, 0x00);
 
-               if (mlpf_new > mlpf_max)
-                       mlpf_new = mlpf_max;
-
-               ds3000_tuner_writereg(state, 0x04, mlpf_new);
-               ds3000_tuner_writereg(state, 0x06, nlpf);
-               ds3000_tuner_writereg(state, 0x51, 0x1b);
-               ds3000_tuner_writereg(state, 0x51, 0x1f);
-               ds3000_tuner_writereg(state, 0x50, 0x04);
-               ds3000_tuner_writereg(state, 0x50, 0x00);
-               msleep(5);
-
-               /* unknown */
-               ds3000_tuner_writereg(state, 0x51, 0x1e);
-               ds3000_tuner_writereg(state, 0x51, 0x1f);
-               ds3000_tuner_writereg(state, 0x50, 0x01);
-               ds3000_tuner_writereg(state, 0x50, 0x00);
-               msleep(60);
-
-               /* ds3000 global reset */
-               ds3000_writereg(state, 0x07, 0x80);
-               ds3000_writereg(state, 0x07, 0x00);
-               /* ds3000 build-in uC reset */
-               ds3000_writereg(state, 0xb2, 0x01);
-               /* ds3000 software reset */
-               ds3000_writereg(state, 0x00, 0x01);
+       /*ds3000_writereg(state, 0x08, 0x03);
+       ds3000_writereg(state, 0xfd, 0x22);
+       ds3000_writereg(state, 0x08, 0x07);
+       ds3000_writereg(state, 0xfd, 0x42);
+       ds3000_writereg(state, 0x08, 0x07);*/
 
+       if (state->config->ci_mode) {
                switch (c->delivery_system) {
                case SYS_DVBS:
-                       /* initialise the demod in DVB-S mode */
-                       for (i = 0; i < sizeof(ds3000_dvbs_init_tab); i += 2)
-                               ds3000_writereg(state,
-                                       ds3000_dvbs_init_tab[i],
-                                       ds3000_dvbs_init_tab[i + 1]);
-                       value = ds3000_readreg(state, 0xfe);
-                       value &= 0xc0;
-                       value |= 0x1b;
-                       ds3000_writereg(state, 0xfe, value);
-                       break;
+               default:
+                       ds3000_writereg(state, 0xfd, 0x80);
+               break;
                case SYS_DVBS2:
-                       /* initialise the demod in DVB-S2 mode */
-                       for (i = 0; i < sizeof(ds3000_dvbs2_init_tab); i += 2)
-                               ds3000_writereg(state,
-                                       ds3000_dvbs2_init_tab[i],
-                                       ds3000_dvbs2_init_tab[i + 1]);
-                       ds3000_writereg(state, 0xfe, 0x54);
+                       ds3000_writereg(state, 0xfd, 0x01);
                        break;
-               default:
-                       return 1;
                }
+       }
 
-               /* enable 27MHz clock output */
-               ds3000_writereg(state, 0x29, 0x80);
-               /* enable ac coupling */
-               ds3000_writereg(state, 0x25, 0x8a);
-
-               /* enhance symbol rate performance */
-               if ((state->dcur.symbol_rate / 1000) <= 5000) {
-                       value = 29777 / (state->dcur.symbol_rate / 1000) + 1;
-                       if (value % 2 != 0)
-                               value++;
-                       ds3000_writereg(state, 0xc3, 0x0d);
-                       ds3000_writereg(state, 0xc8, value);
-                       ds3000_writereg(state, 0xc4, 0x10);
-                       ds3000_writereg(state, 0xc7, 0x0e);
-               } else if ((state->dcur.symbol_rate / 1000) <= 10000) {
-                       value = 92166 / (state->dcur.symbol_rate / 1000) + 1;
-                       if (value % 2 != 0)
-                               value++;
-                       ds3000_writereg(state, 0xc3, 0x07);
-                       ds3000_writereg(state, 0xc8, value);
-                       ds3000_writereg(state, 0xc4, 0x09);
-                       ds3000_writereg(state, 0xc7, 0x12);
-               } else if ((state->dcur.symbol_rate / 1000) <= 20000) {
-                       value = 64516 / (state->dcur.symbol_rate / 1000) + 1;
-                       ds3000_writereg(state, 0xc3, value);
-                       ds3000_writereg(state, 0xc8, 0x0e);
-                       ds3000_writereg(state, 0xc4, 0x07);
-                       ds3000_writereg(state, 0xc7, 0x18);
-               } else {
-                       value = 129032 / (state->dcur.symbol_rate / 1000) + 1;
-                       ds3000_writereg(state, 0xc3, value);
-                       ds3000_writereg(state, 0xc8, 0x0a);
-                       ds3000_writereg(state, 0xc4, 0x05);
-                       ds3000_writereg(state, 0xc7, 0x24);
-               }
+       /* ds3000 out of software reset */
+       ds3000_writereg(state, 0x00, 0x00);
+       /* start ds3000 build-in uC */
+       ds3000_writereg(state, 0xb2, 0x00);
 
-               /* normalized symbol rate rounded to the closest integer */
-               value = (((state->dcur.symbol_rate / 1000) << 16) +
-                               (DS3000_SAMPLE_RATE / 2)) / DS3000_SAMPLE_RATE;
-               ds3000_writereg(state, 0x61, value & 0x00ff);
-               ds3000_writereg(state, 0x62, (value & 0xff00) >> 8);
-
-               /* co-channel interference cancellation disabled */
-               ds3000_writereg(state, 0x56, 0x00);
-
-               /* equalizer disabled */
-               ds3000_writereg(state, 0x76, 0x00);
-
-               /*ds3000_writereg(state, 0x08, 0x03);
-               ds3000_writereg(state, 0xfd, 0x22);
-               ds3000_writereg(state, 0x08, 0x07);
-               ds3000_writereg(state, 0xfd, 0x42);
-               ds3000_writereg(state, 0x08, 0x07);*/
-
-               /* ds3000 out of software reset */
-               ds3000_writereg(state, 0x00, 0x00);
-               /* start ds3000 build-in uC */
-               ds3000_writereg(state, 0xb2, 0x00);
-
-               /* TODO: calculate and set carrier offset */
-
-               /* wait before retrying */
-               for (i = 0; i < 30 ; i++) {
-                       if (ds3000_is_tuned(fe)) {
-                               dprintk("%s: Tuned\n", __func__);
-                               ds3000_dump_registers(fe);
-                               goto tuned;
-                       }
-                       msleep(1);
-               }
+       ds3000_set_carrier_offset(fe, offset_khz);
 
-               dprintk("%s: Not tuned\n", __func__);
-               ds3000_dump_registers(fe);
+       for (i = 0; i < 30 ; i++) {
+               ds3000_read_status(fe, &status);
+               if (status && FE_HAS_LOCK)
+                       break;
 
-       } while (--retune);
+               msleep(10);
+       }
 
-tuned:
-       return ret;
+       return 0;
+}
+
+static int ds3000_tune(struct dvb_frontend *fe,
+                       struct dvb_frontend_parameters *p,
+                       unsigned int mode_flags,
+                       unsigned int *delay,
+                       fe_status_t *status)
+{
+       if (p) {
+               int ret = ds3000_set_frontend(fe, p);
+               if (ret)
+                       return ret;
+       }
+
+       *delay = HZ / 5;
+
+       return ds3000_read_status(fe, status);
 }
 
 static enum dvbfe_algo ds3000_get_algo(struct dvb_frontend *fe)
 {
        dprintk("%s()\n", __func__);
-       return DVBFE_ALGO_SW;
+       return DVBFE_ALGO_HW;
 }
 
 /*
@@ -1306,7 +1249,25 @@ static enum dvbfe_algo ds3000_get_algo(struct dvb_frontend *fe)
  */
 static int ds3000_initfe(struct dvb_frontend *fe)
 {
+       struct ds3000_state *state = fe->demodulator_priv;
+       int ret;
+
        dprintk("%s()\n", __func__);
+       /* hard reset */
+       ds3000_writereg(state, 0x08, 0x01 | ds3000_readreg(state, 0x08));
+       msleep(1);
+
+       /* TS2020 init */
+       ds3000_tuner_writereg(state, 0x42, 0x73);
+       ds3000_tuner_writereg(state, 0x05, 0x01);
+       ds3000_tuner_writereg(state, 0x62, 0xf5);
+       /* Load the firmware if required */
+       ret = ds3000_firmware_ondemand(fe);
+       if (ret != 0) {
+               printk(KERN_ERR "%s: Unable initialize firmware\n", __func__);
+               return ret;
+       }
+
        return 0;
 }
 
@@ -1345,6 +1306,7 @@ static struct dvb_frontend_ops ds3000_ops = {
        .read_signal_strength = ds3000_read_signal_strength,
        .read_snr = ds3000_read_snr,
        .read_ucblocks = ds3000_read_ucblocks,
+       .set_voltage = ds3000_set_voltage,
        .set_tone = ds3000_set_tone,
        .diseqc_send_master_cmd = ds3000_send_diseqc_msg,
        .diseqc_send_burst = ds3000_diseqc_send_burst,
@@ -1352,7 +1314,8 @@ static struct dvb_frontend_ops ds3000_ops = {
 
        .set_property = ds3000_set_property,
        .get_property = ds3000_get_property,
-       .set_frontend = ds3000_tune,
+       .set_frontend = ds3000_set_frontend,
+       .tune = ds3000_tune,
 };
 
 module_param(debug, int, 0644);