Revert to Fedora kernel-2.6.17-1.2187_FC5 patched with vs2.0.2.1; there are too many...
[linux-2.6.git] / drivers / media / dvb / frontends / cx24123.c
index 1e7e790..691dc84 100644 (file)
@@ -41,12 +41,14 @@ static int debug;
 struct cx24123_state
 {
        struct i2c_adapter* i2c;
+       struct dvb_frontend_ops ops;
        const struct cx24123_config* config;
 
        struct dvb_frontend frontend;
 
        u32 lastber;
        u16 snr;
+       u8  lnbreg;
 
        /* Some PLL specifics for tuning */
        u32 VCAarg;
@@ -247,6 +249,29 @@ static int cx24123_writereg(struct cx24123_state* state, int reg, int data)
        return 0;
 }
 
+static int cx24123_writelnbreg(struct cx24123_state* state, int reg, int data)
+{
+       u8 buf[] = { reg, data };
+       /* fixme: put the intersil addr int the config */
+       struct i2c_msg msg = { .addr = 0x08, .flags = 0, .buf = buf, .len = 2 };
+       int err;
+
+       if (debug>1)
+               printk("cx24123: %s:  writeln addr=0x08, reg 0x%02x, value 0x%02x\n",
+                                               __FUNCTION__,reg, data);
+
+       if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
+               printk("%s: writelnbreg error (err == %i, reg == 0x%02x,"
+                        " data == 0x%02x)\n", __FUNCTION__, err, reg, data);
+               return -EREMOTEIO;
+       }
+
+       /* cache the write, no way to read back */
+       state->lnbreg = data;
+
+       return 0;
+}
+
 static int cx24123_readreg(struct cx24123_state* state, u8 reg)
 {
        int ret;
@@ -270,6 +295,11 @@ static int cx24123_readreg(struct cx24123_state* state, u8 reg)
        return b1[0];
 }
 
+static int cx24123_readlnbreg(struct cx24123_state* state, u8 reg)
+{
+       return state->lnbreg;
+}
+
 static int cx24123_set_inversion(struct cx24123_state* state, fe_spectral_inversion_t inversion)
 {
        u8 nom_reg = cx24123_readreg(state, 0x0e);
@@ -428,8 +458,8 @@ static int cx24123_set_symbolrate(struct cx24123_state* state, u32 srate)
        u8 pll_mult;
 
        /*  check if symbol rate is within limits */
-       if ((srate > state->frontend.ops.info.symbol_rate_max) ||
-           (srate < state->frontend.ops.info.symbol_rate_min))
+       if ((srate > state->ops.info.symbol_rate_max) ||
+           (srate < state->ops.info.symbol_rate_min))
                return -EOPNOTSUPP;;
 
        /* choose the sampling rate high enough for the required operation,
@@ -549,8 +579,8 @@ static int cx24123_pll_calculate(struct dvb_frontend* fe, struct dvb_frontend_pa
        ndiv = ( ((p->frequency * vco_div * 10) / (2 * XTAL / 1000)) / 32) & 0x1ff;
        adiv = ( ((p->frequency * vco_div * 10) / (2 * XTAL / 1000)) % 32) & 0x1f;
 
-       if (adiv == 0 && ndiv > 0)
-               ndiv--;
+       if (adiv == 0)
+               ndiv++;
 
        /* control bits 11, refdiv 11, charge pump polarity 1, charge pump current, ndiv, adiv */
        state->pllarg = (3 << 19) | (3 << 17) | (1 << 16) | (pump << 14) | (ndiv << 5) | adiv;
@@ -657,6 +687,13 @@ static int cx24123_initfe(struct dvb_frontend* fe)
        for (i = 0; i < sizeof(cx24123_regdata) / sizeof(cx24123_regdata[0]); i++)
                cx24123_writereg(state, cx24123_regdata[i].reg, cx24123_regdata[i].data);
 
+       if (state->config->pll_init)
+               state->config->pll_init(fe);
+
+       /* Configure the LNB for 14V */
+       if (state->config->use_isl6421)
+               cx24123_writelnbreg(state, 0x0, 0x2a);
+
        return 0;
 }
 
@@ -665,18 +702,50 @@ static int cx24123_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage
        struct cx24123_state *state = fe->demodulator_priv;
        u8 val;
 
-       val = cx24123_readreg(state, 0x29) & ~0x40;
+       switch (state->config->use_isl6421) {
 
-       switch (voltage) {
-       case SEC_VOLTAGE_13:
-               dprintk("%s: setting voltage 13V\n", __FUNCTION__);
-               return cx24123_writereg(state, 0x29, val & 0x7f);
-       case SEC_VOLTAGE_18:
-               dprintk("%s: setting voltage 18V\n", __FUNCTION__);
-               return cx24123_writereg(state, 0x29, val | 0x80);
-       default:
-               return -EINVAL;
-       };
+       case 1:
+
+               val = cx24123_readlnbreg(state, 0x0);
+
+               switch (voltage) {
+               case SEC_VOLTAGE_13:
+                       dprintk("%s:  isl6421 voltage = 13V\n",__FUNCTION__);
+                       return cx24123_writelnbreg(state, 0x0, val & 0x32); /* V 13v */
+               case SEC_VOLTAGE_18:
+                       dprintk("%s:  isl6421 voltage = 18V\n",__FUNCTION__);
+                       return cx24123_writelnbreg(state, 0x0, val | 0x04); /* H 18v */
+               case SEC_VOLTAGE_OFF:
+                       dprintk("%s:  isl5421 voltage off\n",__FUNCTION__);
+                       return cx24123_writelnbreg(state, 0x0, val & 0x30);
+               default:
+                       return -EINVAL;
+               };
+
+       case 0:
+
+               val = cx24123_readreg(state, 0x29);
+
+               switch (voltage) {
+               case SEC_VOLTAGE_13:
+                       dprintk("%s: setting voltage 13V\n", __FUNCTION__);
+                       if (state->config->enable_lnb_voltage)
+                               state->config->enable_lnb_voltage(fe, 1);
+                       return cx24123_writereg(state, 0x29, val | 0x80);
+               case SEC_VOLTAGE_18:
+                       dprintk("%s: setting voltage 18V\n", __FUNCTION__);
+                       if (state->config->enable_lnb_voltage)
+                               state->config->enable_lnb_voltage(fe, 1);
+                       return cx24123_writereg(state, 0x29, val & 0x7f);
+               case SEC_VOLTAGE_OFF:
+                       dprintk("%s: setting voltage off\n", __FUNCTION__);
+                       if (state->config->enable_lnb_voltage)
+                               state->config->enable_lnb_voltage(fe, 0);
+                       return 0;
+               default:
+                       return -EINVAL;
+               };
+       }
 
        return 0;
 }
@@ -697,20 +766,27 @@ static void cx24123_wait_for_diseqc(struct cx24123_state *state)
 static int cx24123_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *cmd)
 {
        struct cx24123_state *state = fe->demodulator_priv;
-       int i, val, tone;
+       int i, val;
 
        dprintk("%s:\n",__FUNCTION__);
 
-       /* stop continuous tone if enabled */
-       tone = cx24123_readreg(state, 0x29);
-       if (tone & 0x10)
-               cx24123_writereg(state, 0x29, tone & ~0x50);
+       /* check if continuous tone has been stopped */
+       if (state->config->use_isl6421)
+               val = cx24123_readlnbreg(state, 0x00) & 0x10;
+       else
+               val = cx24123_readreg(state, 0x29) & 0x10;
+
+
+       if (val) {
+               printk("%s: ERROR: attempt to send diseqc command before tone is off\n", __FUNCTION__);
+               return -ENOTSUPP;
+       }
 
        /* wait for diseqc queue ready */
        cx24123_wait_for_diseqc(state);
 
        /* select tone mode */
-       cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) & 0xfb);
+       cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) & 0xf8);
 
        for (i = 0; i < cmd->msg_len; i++)
                cx24123_writereg(state, 0x2C + i, cmd->msg[i]);
@@ -721,33 +797,36 @@ static int cx24123_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_ma
        /* wait for diseqc message to finish sending */
        cx24123_wait_for_diseqc(state);
 
-       /* restart continuous tone if enabled */
-       if (tone & 0x10) {
-               cx24123_writereg(state, 0x29, tone & ~0x40);
-       }
-
        return 0;
 }
 
 static int cx24123_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t burst)
 {
        struct cx24123_state *state = fe->demodulator_priv;
-       int val, tone;
+       int val;
 
        dprintk("%s:\n", __FUNCTION__);
 
-       /* stop continuous tone if enabled */
-       tone = cx24123_readreg(state, 0x29);
-       if (tone & 0x10)
-               cx24123_writereg(state, 0x29, tone & ~0x50);
+       /* check if continuous tone has been stoped */
+       if (state->config->use_isl6421)
+               val = cx24123_readlnbreg(state, 0x00) & 0x10;
+       else
+               val = cx24123_readreg(state, 0x29) & 0x10;
+
+
+       if (val) {
+               printk("%s: ERROR: attempt to send diseqc command before tone is off\n", __FUNCTION__);
+               return -ENOTSUPP;
+       }
 
-       /* wait for diseqc queue ready */
        cx24123_wait_for_diseqc(state);
 
        /* select tone mode */
-       cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) | 0x4);
-       msleep(30);
+       val = cx24123_readreg(state, 0x2a) & 0xf8;
+       cx24123_writereg(state, 0x2a, val | 0x04);
+
        val = cx24123_readreg(state, 0x29);
+
        if (burst == SEC_MINI_A)
                cx24123_writereg(state, 0x29, ((val & 0x90) | 0x40 | 0x00));
        else if (burst == SEC_MINI_B)
@@ -756,12 +835,7 @@ static int cx24123_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t
                return -EINVAL;
 
        cx24123_wait_for_diseqc(state);
-       cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) & 0xfb);
 
-       /* restart continuous tone if enabled */
-       if (tone & 0x10) {
-               cx24123_writereg(state, 0x29, tone & ~0x40);
-       }
        return 0;
 }
 
@@ -902,21 +976,38 @@ static int cx24123_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
        struct cx24123_state *state = fe->demodulator_priv;
        u8 val;
 
-       /* wait for diseqc queue ready */
-       cx24123_wait_for_diseqc(state);
+       switch (state->config->use_isl6421) {
+       case 1:
 
-       val = cx24123_readreg(state, 0x29) & ~0x40;
+               val = cx24123_readlnbreg(state, 0x0);
+
+               switch (tone) {
+               case SEC_TONE_ON:
+                       dprintk("%s:  isl6421 sec tone on\n",__FUNCTION__);
+                       return cx24123_writelnbreg(state, 0x0, val | 0x10);
+               case SEC_TONE_OFF:
+                       dprintk("%s:  isl6421 sec tone off\n",__FUNCTION__);
+                       return cx24123_writelnbreg(state, 0x0, val & 0x2f);
+               default:
+                       printk("%s: CASE reached default with tone=%d\n", __FUNCTION__, tone);
+                       return -EINVAL;
+               }
 
-       switch (tone) {
-       case SEC_TONE_ON:
-               dprintk("%s: setting tone on\n", __FUNCTION__);
-               return cx24123_writereg(state, 0x29, val | 0x10);
-       case SEC_TONE_OFF:
-               dprintk("%s: setting tone off\n",__FUNCTION__);
-               return cx24123_writereg(state, 0x29, val & 0xef);
-       default:
-               printk("%s: CASE reached default with tone=%d\n", __FUNCTION__, tone);
-               return -EINVAL;
+       case 0:
+
+               val = cx24123_readreg(state, 0x29);
+
+               switch (tone) {
+               case SEC_TONE_ON:
+                       dprintk("%s: setting tone on\n", __FUNCTION__);
+                       return cx24123_writereg(state, 0x29, val | 0x10);
+               case SEC_TONE_OFF:
+                       dprintk("%s: setting tone off\n",__FUNCTION__);
+                       return cx24123_writereg(state, 0x29, val & 0xef);
+               default:
+                       printk("%s: CASE reached default with tone=%d\n", __FUNCTION__, tone);
+                       return -EINVAL;
+               }
        }
 
        return 0;
@@ -949,8 +1040,10 @@ struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,
        /* setup the state */
        state->config = config;
        state->i2c = i2c;
+       memcpy(&state->ops, &cx24123_ops, sizeof(struct dvb_frontend_ops));
        state->lastber = 0;
        state->snr = 0;
+       state->lnbreg = 0;
        state->VCAarg = 0;
        state->VGAarg = 0;
        state->bandselectarg = 0;
@@ -966,7 +1059,7 @@ struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,
        }
 
        /* create dvb_frontend */
-       memcpy(&state->frontend.ops, &cx24123_ops, sizeof(struct dvb_frontend_ops));
+       state->frontend.ops = &state->ops;
        state->frontend.demodulator_priv = state;
        return &state->frontend;