]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/media/dvb/frontends/s5h1411.c
Merge branch 'x86-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-omap-h63xx.git] / drivers / media / dvb / frontends / s5h1411.c
index 2febfb5a846bc0922e31d75daf779c7cb0fe5ed3..40644aacffcb218dbbee77ee8a8b80e15b2b0164 100644 (file)
@@ -38,6 +38,7 @@ struct s5h1411_state {
        struct dvb_frontend frontend;
 
        fe_modulation_t current_modulation;
+       unsigned int first_tune:1;
 
        u32 current_frequency;
        int if_freq;
@@ -62,7 +63,7 @@ static struct init_tab {
        { S5H1411_I2C_TOP_ADDR, 0x08, 0x0047, },
        { S5H1411_I2C_TOP_ADDR, 0x1c, 0x0400, },
        { S5H1411_I2C_TOP_ADDR, 0x1e, 0x0370, },
-       { S5H1411_I2C_TOP_ADDR, 0x1f, 0x342a, },
+       { S5H1411_I2C_TOP_ADDR, 0x1f, 0x342c, },
        { S5H1411_I2C_TOP_ADDR, 0x24, 0x0231, },
        { S5H1411_I2C_TOP_ADDR, 0x25, 0x1011, },
        { S5H1411_I2C_TOP_ADDR, 0x26, 0x0f07, },
@@ -100,7 +101,6 @@ static struct init_tab {
        { S5H1411_I2C_TOP_ADDR, 0x78, 0x3141, },
        { S5H1411_I2C_TOP_ADDR, 0x7a, 0x3141, },
        { S5H1411_I2C_TOP_ADDR, 0xb3, 0x8003, },
-       { S5H1411_I2C_TOP_ADDR, 0xb5, 0xafbb, },
        { S5H1411_I2C_TOP_ADDR, 0xb5, 0xa6bb, },
        { S5H1411_I2C_TOP_ADDR, 0xb6, 0x0609, },
        { S5H1411_I2C_TOP_ADDR, 0xb7, 0x2f06, },
@@ -393,7 +393,7 @@ static int s5h1411_set_if_freq(struct dvb_frontend *fe, int KHz)
 
        switch (KHz) {
        case 3250:
-               s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x38, 0x10d9);
+               s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x38, 0x10d5);
                s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x39, 0x5342);
                s5h1411_writereg(state, S5H1411_I2C_QAM_ADDR, 0x2c, 0x10d9);
                break;
@@ -464,13 +464,25 @@ static int s5h1411_set_spectralinversion(struct dvb_frontend *fe, int inversion)
 
        if (inversion == 1)
                val |= 0x1000; /* Inverted */
-       else
-               val |= 0x0000;
 
        state->inversion = inversion;
        return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x24, val);
 }
 
+static int s5h1411_set_serialmode(struct dvb_frontend *fe, int serial)
+{
+       struct s5h1411_state *state = fe->demodulator_priv;
+       u16 val;
+
+       dprintk("%s(%d)\n", __func__, serial);
+       val = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xbd) & ~0x100;
+
+       if (serial == 1)
+               val |= 0x100;
+
+       return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xbd, val);
+}
+
 static int s5h1411_enable_modulation(struct dvb_frontend *fe,
                                     fe_modulation_t m)
 {
@@ -478,6 +490,12 @@ static int s5h1411_enable_modulation(struct dvb_frontend *fe,
 
        dprintk("%s(0x%08x)\n", __func__, m);
 
+       if ((state->first_tune == 0) && (m == state->current_modulation)) {
+               dprintk("%s() Already at desired modulation.  Skipping...\n",
+                       __func__);
+               return 0;
+       }
+
        switch (m) {
        case VSB_8:
                dprintk("%s() VSB_8\n", __func__);
@@ -502,6 +520,7 @@ static int s5h1411_enable_modulation(struct dvb_frontend *fe,
        }
 
        state->current_modulation = m;
+       state->first_tune = 0;
        s5h1411_softreset(fe);
 
        return 0;
@@ -535,7 +554,7 @@ static int s5h1411_set_gpio(struct dvb_frontend *fe, int enable)
                return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xe0, val);
 }
 
-static int s5h1411_sleep(struct dvb_frontend *fe, int enable)
+static int s5h1411_set_powerstate(struct dvb_frontend *fe, int enable)
 {
        struct s5h1411_state *state = fe->demodulator_priv;
 
@@ -551,6 +570,11 @@ static int s5h1411_sleep(struct dvb_frontend *fe, int enable)
        return 0;
 }
 
+static int s5h1411_sleep(struct dvb_frontend *fe)
+{
+       return s5h1411_set_powerstate(fe, 1);
+}
+
 static int s5h1411_register_reset(struct dvb_frontend *fe)
 {
        struct s5h1411_state *state = fe->demodulator_priv;
@@ -574,9 +598,6 @@ static int s5h1411_set_frontend(struct dvb_frontend *fe,
 
        s5h1411_enable_modulation(fe, p->u.vsb.modulation);
 
-       /* Allow the demod to settle */
-       msleep(100);
-
        if (fe->ops.tuner_ops.set_params) {
                if (fe->ops.i2c_gate_ctrl)
                        fe->ops.i2c_gate_ctrl(fe, 1);
@@ -587,6 +608,10 @@ static int s5h1411_set_frontend(struct dvb_frontend *fe,
                        fe->ops.i2c_gate_ctrl(fe, 0);
        }
 
+       /* Issue a reset to the demod so it knows to resync against the
+          newly tuned frequency */
+       s5h1411_softreset(fe);
+
        return 0;
 }
 
@@ -599,7 +624,7 @@ static int s5h1411_init(struct dvb_frontend *fe)
 
        dprintk("%s()\n", __func__);
 
-       s5h1411_sleep(fe, 0);
+       s5h1411_set_powerstate(fe, 0);
        s5h1411_register_reset(fe);
 
        for (i = 0; i < ARRAY_SIZE(init_tab); i++)
@@ -610,12 +635,17 @@ static int s5h1411_init(struct dvb_frontend *fe)
        /* The datasheet says that after initialisation, VSB is default */
        state->current_modulation = VSB_8;
 
+       /* Although the datasheet says it's in VSB, empirical evidence
+          shows problems getting lock on the first tuning request.  Make
+          sure we call enable_modulation the first time around */
+       state->first_tune = 1;
+
        if (state->config->output_mode == S5H1411_SERIAL_OUTPUT)
                /* Serial */
-               s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xbd, 0x1101);
+               s5h1411_set_serialmode(fe, 1);
        else
                /* Parallel */
-               s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xbd, 0x1001);
+               s5h1411_set_serialmode(fe, 0);
 
        s5h1411_set_spectralinversion(fe, state->config->inversion);
        s5h1411_set_if_freq(fe, state->config->vsb_if);
@@ -637,28 +667,29 @@ static int s5h1411_read_status(struct dvb_frontend *fe, fe_status_t *status)
 
        *status = 0;
 
-       /* Get the demodulator status */
-       reg = (s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xf2) >> 15)
-               & 0x0001;
-       if (reg)
-               *status |= FE_HAS_LOCK | FE_HAS_CARRIER | FE_HAS_SIGNAL;
+       /* Register F2 bit 15 = Master Lock, removed */
 
        switch (state->current_modulation) {
        case QAM_64:
        case QAM_256:
                reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xf0);
-               if (reg & 0x100)
-                       *status |= FE_HAS_VITERBI;
-               if (reg & 0x10)
-                       *status |= FE_HAS_SYNC;
+               if (reg & 0x10) /* QAM FEC Lock */
+                       *status |= FE_HAS_SYNC | FE_HAS_LOCK;
+               if (reg & 0x100) /* QAM EQ Lock */
+                       *status |= FE_HAS_VITERBI | FE_HAS_CARRIER | FE_HAS_SIGNAL;
+
                break;
        case VSB_8:
-               reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0x5e);
-               if (reg & 0x0001)
-                       *status |= FE_HAS_SYNC;
                reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xf2);
-               if (reg & 0x1000)
-                       *status |= FE_HAS_VITERBI;
+               if (reg & 0x1000) /* FEC Lock */
+                       *status |= FE_HAS_SYNC | FE_HAS_LOCK;
+               if (reg & 0x2000) /* EQ Lock */
+                       *status |= FE_HAS_VITERBI | FE_HAS_CARRIER | FE_HAS_SIGNAL;
+
+               reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0x53);
+               if (reg & 0x1) /* AFC Lock */
+                       *status |= FE_HAS_SIGNAL;
+
                break;
        default:
                return -EINVAL;
@@ -863,6 +894,7 @@ static struct dvb_frontend_ops s5h1411_ops = {
        },
 
        .init                 = s5h1411_init,
+       .sleep                = s5h1411_sleep,
        .i2c_gate_ctrl        = s5h1411_i2c_gate_ctrl,
        .set_frontend         = s5h1411_set_frontend,
        .get_frontend         = s5h1411_get_frontend,