X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fmedia%2Fdvb%2Ffrontends%2Fstv0299.c;h=cfa3928bb487bab6d61cb0991833dadf7326819a;hb=f7f1b0f1e2fbadeab12d24236000e778aa9b1ead;hp=bf5de103142fada710714c19ff8f95ab992e2d4f;hpb=e3f6fb6212a7102bdb56ba38fa1e98fe72950475;p=linux-2.6.git diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c index bf5de1031..cfa3928bb 100644 --- a/drivers/media/dvb/frontends/stv0299.c +++ b/drivers/media/dvb/frontends/stv0299.c @@ -5,7 +5,7 @@ , , - + Philips SU1278/SH @@ -15,7 +15,7 @@ LG TDQF-S001F Copyright (C) 2002 Felix Domke - & Andreas Oberritter + & Andreas Oberritter Support for Samsung TBMU24112IMB used on Technisat SkyStar2 rev. 2.6B @@ -40,7 +40,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ +*/ #include #include @@ -54,13 +54,9 @@ #include "stv0299.h" struct stv0299_state { - struct i2c_adapter* i2c; - struct dvb_frontend_ops ops; - const struct stv0299_config* config; - struct dvb_frontend frontend; u8 initialised:1; @@ -74,6 +70,7 @@ struct stv0299_state { #define STATUS_UCBLOCKS 1 static int debug; +static int debug_legacy_dish_switch; #define dprintk(args...) \ do { \ if (debug) printk(KERN_DEBUG "stv0299: " args); \ @@ -88,7 +85,7 @@ static int stv0299_writeregI (struct stv0299_state* state, u8 reg, u8 data) ret = i2c_transfer (state->i2c, &msg, 1); - if (ret != 1) + if (ret != 1) dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, " "ret == %i)\n", __FUNCTION__, reg, data, ret); @@ -97,12 +94,11 @@ static int stv0299_writeregI (struct stv0299_state* state, u8 reg, u8 data) int stv0299_writereg (struct dvb_frontend* fe, u8 reg, u8 data) { - struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; + struct stv0299_state* state = fe->demodulator_priv; return stv0299_writeregI(state, reg, data); } - static u8 stv0299_readreg (struct stv0299_state* state, u8 reg) { int ret; @@ -112,30 +108,28 @@ static u8 stv0299_readreg (struct stv0299_state* state, u8 reg) { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; ret = i2c_transfer (state->i2c, msg, 2); - - if (ret != 2) + + if (ret != 2) dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret); return b1[0]; } - static int stv0299_readregs (struct stv0299_state* state, u8 reg1, u8 *b, u8 len) { - int ret; + int ret; struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = ®1, .len = 1 }, { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b, .len = len } }; ret = i2c_transfer (state->i2c, msg, 2); - if (ret != 2) - dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret); + if (ret != 2) + dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret); - return ret == 2 ? 0 : ret; + return ret == 2 ? 0 : ret; } - static int stv0299_set_FEC (struct stv0299_state* state, fe_code_rate_t fec) { dprintk ("%s\n", __FUNCTION__); @@ -169,9 +163,8 @@ static int stv0299_set_FEC (struct stv0299_state* state, fe_code_rate_t fec) { return -EINVAL; } + } } -} - static fe_code_rate_t stv0299_get_fec (struct stv0299_state* state) { @@ -190,7 +183,6 @@ static fe_code_rate_t stv0299_get_fec (struct stv0299_state* state) return fec_tab [index]; } - static int stv0299_wait_diseqc_fifo (struct stv0299_state* state, int timeout) { unsigned long start = jiffies; @@ -208,7 +200,6 @@ static int stv0299_wait_diseqc_fifo (struct stv0299_state* state, int timeout) return 0; } - static int stv0299_wait_diseqc_idle (struct stv0299_state* state, int timeout) { unsigned long start = jiffies; @@ -228,7 +219,7 @@ static int stv0299_wait_diseqc_idle (struct stv0299_state* state, int timeout) static int stv0299_set_symbolrate (struct dvb_frontend* fe, u32 srate) { - struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; + struct stv0299_state* state = fe->demodulator_priv; u64 big = srate; u32 ratio; @@ -244,7 +235,6 @@ static int stv0299_set_symbolrate (struct dvb_frontend* fe, u32 srate) return state->config->set_symbol_rate(fe, srate, ratio); } - static int stv0299_get_symbolrate (struct stv0299_state* state) { u32 Mclk = state->config->mclk / 4096L; @@ -277,23 +267,10 @@ static int stv0299_get_symbolrate (struct stv0299_state* state) return srate; } - - - - - - - - - - - - - static int stv0299_send_diseqc_msg (struct dvb_frontend* fe, - struct dvb_diseqc_master_cmd *m) + struct dvb_diseqc_master_cmd *m) { - struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; + struct stv0299_state* state = fe->demodulator_priv; u8 val; int i; @@ -321,10 +298,9 @@ static int stv0299_send_diseqc_msg (struct dvb_frontend* fe, return 0; } - static int stv0299_send_diseqc_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t burst) { - struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; + struct stv0299_state* state = fe->demodulator_priv; u8 val; dprintk ("%s\n", __FUNCTION__); @@ -349,10 +325,9 @@ static int stv0299_send_diseqc_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t return 0; } - static int stv0299_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone) { - struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; + struct stv0299_state* state = fe->demodulator_priv; u8 val; if (stv0299_wait_diseqc_idle (state, 100) < 0) @@ -372,15 +347,14 @@ static int stv0299_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone) } } - static int stv0299_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage) { - struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; + struct stv0299_state* state = fe->demodulator_priv; u8 reg0x08; u8 reg0x0c; dprintk("%s: %s\n", __FUNCTION__, - voltage == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" : + voltage == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" : voltage == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??"); reg0x08 = stv0299_readreg (state, 0x08); @@ -395,7 +369,7 @@ static int stv0299_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltag stv0299_writeregI (state, 0x0c, 0x00); /* LNB power off! */ return stv0299_writeregI (state, 0x08, 0x00); /* LNB power off! */ } - + stv0299_writeregI (state, 0x08, (reg0x08 & 0x3f) | (state->config->lock_output << 6)); switch (voltage) { @@ -412,46 +386,92 @@ static int stv0299_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltag }; } +static inline s32 stv0299_calc_usec_delay (struct timeval lasttime, struct timeval curtime) +{ + return ((curtime.tv_usec < lasttime.tv_usec) ? + 1000000 - lasttime.tv_usec + curtime.tv_usec : + curtime.tv_usec - lasttime.tv_usec); +} -static int stv0299_send_legacy_dish_cmd(struct dvb_frontend* fe, u32 cmd) +static void stv0299_sleep_until (struct timeval *waketime, u32 add_usec) { + struct timeval lasttime; + s32 delta, newdelta; + + waketime->tv_usec += add_usec; + if (waketime->tv_usec >= 1000000) { + waketime->tv_usec -= 1000000; + waketime->tv_sec++; + } + + do_gettimeofday (&lasttime); + delta = stv0299_calc_usec_delay (lasttime, *waketime); + if (delta > 2500) { + msleep ((delta - 1500) / 1000); + do_gettimeofday (&lasttime); + newdelta = stv0299_calc_usec_delay (lasttime, *waketime); + delta = (newdelta > delta) ? 0 : newdelta; + } + if (delta > 0) + udelay (delta); +} + +static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, u32 cmd) +{ + struct stv0299_state* state = fe->demodulator_priv; + u8 reg0x08; + u8 reg0x0c; + u8 lv_mask = 0x40; u8 last = 1; int i; + struct timeval nexttime; + struct timeval tv[10]; - /* reset voltage at the end - if((0x50 & stv0299_readreg (i2c, 0x0c)) == 0x50) - cmd |= 0x80; - else - cmd &= 0x7F; - */ + reg0x08 = stv0299_readreg (state, 0x08); + reg0x0c = stv0299_readreg (state, 0x0c); + reg0x0c &= 0x0f; + stv0299_writeregI (state, 0x08, (reg0x08 & 0x3f) | (state->config->lock_output << 6)); + if (state->config->volt13_op0_op1 == STV0299_VOLT13_OP0) + lv_mask = 0x10; cmd = cmd << 1; - dprintk("%s switch command: 0x%04x\n",__FUNCTION__, cmd); + if (debug_legacy_dish_switch) + printk ("%s switch command: 0x%04x\n",__FUNCTION__, cmd); + + do_gettimeofday (&nexttime); + if (debug_legacy_dish_switch) + memcpy (&tv[0], &nexttime, sizeof (struct timeval)); + stv0299_writeregI (state, 0x0c, reg0x0c | 0x50); /* set LNB to 18V */ - stv0299_set_voltage(fe,SEC_VOLTAGE_18); - msleep(32); + stv0299_sleep_until (&nexttime, 32000); for (i=0; i<9; i++) { + if (debug_legacy_dish_switch) + do_gettimeofday (&tv[i+1]); if((cmd & 0x01) != last) { - stv0299_set_voltage(fe, - last ? SEC_VOLTAGE_13 : - SEC_VOLTAGE_18); + /* set voltage to (last ? 13V : 18V) */ + stv0299_writeregI (state, 0x0c, reg0x0c | (last ? lv_mask : 0x50)); last = (last) ? 0 : 1; } cmd = cmd >> 1; if (i != 8) - msleep(8); + stv0299_sleep_until (&nexttime, 8000); + } + if (debug_legacy_dish_switch) { + printk ("%s(%d): switch delay (should be 32k followed by all 8k\n", + __FUNCTION__, fe->dvb->num); + for (i=1; i < 10; i++) + printk ("%d: %d\n", i, stv0299_calc_usec_delay (tv[i-1] , tv[i])); } return 0; } - static int stv0299_init (struct dvb_frontend* fe) { - struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; + struct stv0299_state* state = fe->demodulator_priv; int i; dprintk("stv0299: init chip\n"); @@ -468,65 +488,64 @@ static int stv0299_init (struct dvb_frontend* fe) return 0; } - static int stv0299_read_status(struct dvb_frontend* fe, fe_status_t* status) - { - struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; +{ + struct stv0299_state* state = fe->demodulator_priv; u8 signal = 0xff - stv0299_readreg (state, 0x18); u8 sync = stv0299_readreg (state, 0x1b); - dprintk ("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __FUNCTION__, sync); - *status = 0; + dprintk ("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __FUNCTION__, sync); + *status = 0; - if (signal > 10) - *status |= FE_HAS_SIGNAL; + if (signal > 10) + *status |= FE_HAS_SIGNAL; - if (sync & 0x80) - *status |= FE_HAS_CARRIER; + if (sync & 0x80) + *status |= FE_HAS_CARRIER; - if (sync & 0x10) - *status |= FE_HAS_VITERBI; + if (sync & 0x10) + *status |= FE_HAS_VITERBI; - if (sync & 0x08) - *status |= FE_HAS_SYNC; + if (sync & 0x08) + *status |= FE_HAS_SYNC; - if ((sync & 0x98) == 0x98) - *status |= FE_HAS_LOCK; + if ((sync & 0x98) == 0x98) + *status |= FE_HAS_LOCK; return 0; - } +} static int stv0299_read_ber(struct dvb_frontend* fe, u32* ber) { - struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; + struct stv0299_state* state = fe->demodulator_priv; if (state->errmode != STATUS_BER) return 0; *ber = (stv0299_readreg (state, 0x1d) << 8) | stv0299_readreg (state, 0x1e); return 0; - } +} static int stv0299_read_signal_strength(struct dvb_frontend* fe, u16* strength) - { - struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; +{ + struct stv0299_state* state = fe->demodulator_priv; s32 signal = 0xffff - ((stv0299_readreg (state, 0x18) << 8) | stv0299_readreg (state, 0x19)); - dprintk ("%s : FE_READ_SIGNAL_STRENGTH : AGC2I: 0x%02x%02x, signal=0x%04x\n", __FUNCTION__, + dprintk ("%s : FE_READ_SIGNAL_STRENGTH : AGC2I: 0x%02x%02x, signal=0x%04x\n", __FUNCTION__, stv0299_readreg (state, 0x18), stv0299_readreg (state, 0x19), (int) signal); - signal = signal * 5 / 4; + signal = signal * 5 / 4; *strength = (signal > 0xffff) ? 0xffff : (signal < 0) ? 0 : signal; return 0; - } +} static int stv0299_read_snr(struct dvb_frontend* fe, u16* snr) - { - struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; +{ + struct stv0299_state* state = fe->demodulator_priv; s32 xsnr = 0xffff - ((stv0299_readreg (state, 0x24) << 8) | stv0299_readreg (state, 0x25)); @@ -538,7 +557,7 @@ static int stv0299_read_snr(struct dvb_frontend* fe, u16* snr) static int stv0299_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) { - struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; + struct stv0299_state* state = fe->demodulator_priv; if (state->errmode != STATUS_UCBLOCKS) *ucblocks = 0; else *ucblocks = (stv0299_readreg (state, 0x1d) << 8) | stv0299_readreg (state, 0x1e); @@ -548,41 +567,41 @@ static int stv0299_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) static int stv0299_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters * p) { - struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; - int invval = 0; + struct stv0299_state* state = fe->demodulator_priv; + int invval = 0; - dprintk ("%s : FE_SET_FRONTEND\n", __FUNCTION__); + dprintk ("%s : FE_SET_FRONTEND\n", __FUNCTION__); - // set the inversion - if (p->inversion == INVERSION_OFF) invval = 0; - else if (p->inversion == INVERSION_ON) invval = 1; - else { - printk("stv0299 does not support auto-inversion\n"); - return -EINVAL; - } + // set the inversion + if (p->inversion == INVERSION_OFF) invval = 0; + else if (p->inversion == INVERSION_ON) invval = 1; + else { + printk("stv0299 does not support auto-inversion\n"); + return -EINVAL; + } if (state->config->invert) invval = (~invval) & 1; stv0299_writeregI(state, 0x0c, (stv0299_readreg(state, 0x0c) & 0xfe) | invval); if (state->config->enhanced_tuning) { - /* check if we should do a finetune */ - int frequency_delta = p->frequency - state->tuner_frequency; - int minmax = p->u.qpsk.symbol_rate / 2000; - if (minmax < 5000) minmax = 5000; - - if ((frequency_delta > -minmax) && (frequency_delta < minmax) && (frequency_delta != 0) && - (state->fec_inner == p->u.qpsk.fec_inner) && - (state->symbol_rate == p->u.qpsk.symbol_rate)) { + /* check if we should do a finetune */ + int frequency_delta = p->frequency - state->tuner_frequency; + int minmax = p->u.qpsk.symbol_rate / 2000; + if (minmax < 5000) minmax = 5000; + + if ((frequency_delta > -minmax) && (frequency_delta < minmax) && (frequency_delta != 0) && + (state->fec_inner == p->u.qpsk.fec_inner) && + (state->symbol_rate == p->u.qpsk.symbol_rate)) { int Drot_freq = (frequency_delta << 16) / (state->config->mclk / 1000); - // zap the derotator registers first + // zap the derotator registers first stv0299_writeregI(state, 0x22, 0x00); stv0299_writeregI(state, 0x23, 0x00); - // now set them as we want + // now set them as we want stv0299_writeregI(state, 0x22, Drot_freq >> 8); stv0299_writeregI(state, 0x23, Drot_freq); - } else { - /* A "normal" tune is requested */ + } else { + /* A "normal" tune is requested */ stv0299_writeregI(state, 0x05, 0xb5); /* enable i2c repeater on stv0299 */ state->config->pll_set(fe, p); stv0299_writeregI(state, 0x05, 0x35); /* disable i2c repeater on stv0299 */ @@ -605,43 +624,43 @@ static int stv0299_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par stv0299_writeregI(state, 0x23, 0x00); stv0299_readreg (state, 0x23); stv0299_writeregI(state, 0x12, 0xb9); - } + } - state->tuner_frequency = p->frequency; - state->fec_inner = p->u.qpsk.fec_inner; - state->symbol_rate = p->u.qpsk.symbol_rate; + state->tuner_frequency = p->frequency; + state->fec_inner = p->u.qpsk.fec_inner; + state->symbol_rate = p->u.qpsk.symbol_rate; return 0; - } +} static int stv0299_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters * p) - { - struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; - s32 derot_freq; - int invval; +{ + struct stv0299_state* state = fe->demodulator_priv; + s32 derot_freq; + int invval; derot_freq = (s32)(s16) ((stv0299_readreg (state, 0x22) << 8) | stv0299_readreg (state, 0x23)); derot_freq *= (state->config->mclk >> 16); - derot_freq += 500; - derot_freq /= 1000; + derot_freq += 500; + derot_freq /= 1000; - p->frequency += derot_freq; + p->frequency += derot_freq; invval = stv0299_readreg (state, 0x0c) & 1; if (state->config->invert) invval = (~invval) & 1; - p->inversion = invval ? INVERSION_ON : INVERSION_OFF; + p->inversion = invval ? INVERSION_ON : INVERSION_OFF; p->u.qpsk.fec_inner = stv0299_get_fec (state); p->u.qpsk.symbol_rate = stv0299_get_symbolrate (state); return 0; - } +} static int stv0299_sleep(struct dvb_frontend* fe) { - struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; + struct stv0299_state* state = fe->demodulator_priv; stv0299_writeregI(state, 0x02, 0x80); state->initialised = 0; @@ -650,23 +669,23 @@ static int stv0299_sleep(struct dvb_frontend* fe) } static int stv0299_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) - { - struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; +{ + struct stv0299_state* state = fe->demodulator_priv; fesettings->min_delay_ms = state->config->min_delay_ms; - if (fesettings->parameters.u.qpsk.symbol_rate < 10000000) { - fesettings->step_size = fesettings->parameters.u.qpsk.symbol_rate / 32000; - fesettings->max_drift = 5000; - } else { - fesettings->step_size = fesettings->parameters.u.qpsk.symbol_rate / 16000; - fesettings->max_drift = fesettings->parameters.u.qpsk.symbol_rate / 2000; - } + if (fesettings->parameters.u.qpsk.symbol_rate < 10000000) { + fesettings->step_size = fesettings->parameters.u.qpsk.symbol_rate / 32000; + fesettings->max_drift = 5000; + } else { + fesettings->step_size = fesettings->parameters.u.qpsk.symbol_rate / 16000; + fesettings->max_drift = fesettings->parameters.u.qpsk.symbol_rate / 2000; + } return 0; } static void stv0299_release(struct dvb_frontend* fe) - { - struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; +{ + struct stv0299_state* state = fe->demodulator_priv; kfree(state); } @@ -677,9 +696,9 @@ struct dvb_frontend* stv0299_attach(const struct stv0299_config* config, { struct stv0299_state* state = NULL; int id; - + /* allocate memory for the internal state */ - state = (struct stv0299_state*) kmalloc(sizeof(struct stv0299_state), GFP_KERNEL); + state = kmalloc(sizeof(struct stv0299_state), GFP_KERNEL); if (state == NULL) goto error; /* setup the state */ @@ -707,7 +726,7 @@ struct dvb_frontend* stv0299_attach(const struct stv0299_config* config, return &state->frontend; error: - if (state) kfree(state); + kfree(state); return NULL; } @@ -751,6 +770,9 @@ static struct dvb_frontend_ops stv0299_ops = { .dishnetwork_send_legacy_command = stv0299_send_legacy_dish_cmd, }; +module_param(debug_legacy_dish_switch, int, 0444); +MODULE_PARM_DESC(debug_legacy_dish_switch, "Enable timing analysis for Dish Network legacy switches"); + module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");