diff options
author | Andrew de Quincy <devnull@localhost> | 2004-11-09 09:54:11 +0000 |
---|---|---|
committer | Andrew de Quincy <devnull@localhost> | 2004-11-09 09:54:11 +0000 |
commit | aef71b24f260b4df387aa15ec2b5a4c5d40499b9 (patch) | |
tree | 8d180025d278463de065fe0c0aac4d1117a39e7e /linux/drivers/media | |
parent | 32115d6f2fd9c9aea933e8163e30a29c4f5a981f (diff) | |
download | mediapointer-dvb-s2-aef71b24f260b4df387aa15ec2b5a4c5d40499b9.tar.gz mediapointer-dvb-s2-aef71b24f260b4df387aa15ec2b5a4c5d40499b9.tar.bz2 |
Added support for stv0297 based cards
Diffstat (limited to 'linux/drivers/media')
-rw-r--r-- | linux/drivers/media/dvb/frontends/stv0297.c | 873 | ||||
-rw-r--r-- | linux/drivers/media/dvb/frontends/stv0297.h | 5 | ||||
-rw-r--r-- | linux/drivers/media/dvb/ttpci/av7110.c | 66 | ||||
-rw-r--r-- | linux/drivers/media/dvb/ttpci/av7110.h | 2 |
4 files changed, 646 insertions, 300 deletions
diff --git a/linux/drivers/media/dvb/frontends/stv0297.c b/linux/drivers/media/dvb/frontends/stv0297.c index 4ef3adac5..8bea1c275 100644 --- a/linux/drivers/media/dvb/frontends/stv0297.c +++ b/linux/drivers/media/dvb/frontends/stv0297.c @@ -1,6 +1,7 @@ /* Driver for STV0297 demodulator + Copyright (C) 2004 Andrew de Quincey <adq_dvb@lidskialf.net> Copyright (C) 2003-2004 Dennis Noermann <dennis.noermann@noernet.de> This program is free software; you can redistribute it and/or modify @@ -16,7 +17,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ +*/ #include <linux/init.h> #include <linux/kernel.h> @@ -29,13 +30,19 @@ struct stv0297_state { - struct i2c_adapter* i2c; + struct i2c_adapter* i2c; + + struct dvb_frontend_ops ops; + + const struct stv0297_config* config; - struct dvb_frontend_ops ops; + struct dvb_frontend frontend; - const struct stv0297_config* config; + int freq_off; - struct dvb_frontend frontend; + unsigned long base_freq; + + u8 pwm; }; #if 0 @@ -47,433 +54,707 @@ struct stv0297_state { #define STV0297_CLOCK 28900 static u8 init_tab [] = { - 0x80, 0x01, /* soft_reset */ - 0x80, 0x00, /* cleared soft_reset */ - 0x81, 0x01, /* deinterleaver descrambler reset */ - 0x81, 0x00, /* cleared deinterleaver descrambler reset */ - 0x83, 0x10, /* the Reed-Solomon block reset*/ - 0x83, 0x00, /* cleared the Reed-Solomon block reset */ - 0x84, 0x2b, /* clears the equalizer and also reinitializes the Reg. 00through 04. */ - 0x84, 0x2a, /* cleares it .. */ - 0x03, 0x00, - 0x25, 0x88, - 0x30, 0x97, - 0x31, 0x4C, - 0x32, 0xFF, - 0x33, 0x55, - 0x34, 0x00, - 0x35, 0x65, - 0x36, 0x80, - 0x40, 0x1C, - 0x42, 0x3C, - 0x43, 0x00, - 0x52, 0x28, - 0x5A, 0x1E, - 0x5B, 0x05, - 0x62, 0x06, - 0x6A, 0x02, - 0x70, 0xFF, - 0x71, 0x84, - 0x83, 0x10, - 0x84, 0x25, - 0x85, 0x00, - 0x86, 0x78, - 0x87, 0x73, - 0x88, 0x08, - 0x89, 0x00, - 0x90, 0x05, - 0xA0, 0x00, - 0xB0, 0x91, - 0xB1, 0x0B, - 0xC0, 0x4B, - 0xC1, 0x01, - 0xC2, 0x00, - 0xDE, 0x00, - 0xDF, 0x03, - 0x87, 0x73 + 0x00, 0x09, + 0x01, 0x69, + 0x03, 0x00, + 0x04, 0x00, + 0x07, 0x00, + 0x08, 0x00, + 0x20, 0x00, + 0x21, 0x40, + 0x22, 0x00, + 0x23, 0x00, + 0x24, 0x40, + 0x25, 0x88, + 0x30, 0xff, + 0x31, 0x00, + 0x32, 0xff, + 0x33, 0x00, + 0x34, 0x50, + 0x35, 0x7f, + 0x36, 0x00, + 0x37, 0x20, + 0x38, 0x00, + 0x40, 0x1c, + 0x41, 0xff, + 0x42, 0x29, + 0x43, 0x00, + 0x44, 0xff, + 0x45, 0x00, + 0x46, 0x00, + 0x49, 0x04, + 0x4a, 0xff, + 0x4b, 0x7f, + 0x52, 0x30, + 0x55, 0xae, + 0x56, 0x47, + 0x57, 0xe1, + 0x58, 0x3a, + 0x5a, 0x1e, + 0x5b, 0x34, + 0x60, 0x00, + 0x63, 0x00, + 0x64, 0x00, + 0x65, 0x00, + 0x66, 0x00, + 0x67, 0x00, + 0x68, 0x00, + 0x69, 0x00, + 0x6a, 0x02, + 0x6b, 0x00, + 0x70, 0xff, + 0x71, 0x00, + 0x72, 0x00, + 0x73, 0x00, + 0x74, 0x0c, + 0x80, 0x00, + 0x81, 0x00, + 0x82, 0x00, + 0x83, 0x00, + 0x84, 0x04, + 0x85, 0x80, + 0x86, 0x24, + 0x87, 0x78, + 0x88, 0x00, + 0x89, 0x00, + 0x90, 0x01, + 0x91, 0x01, + 0xa0, 0x00, + 0xa1, 0x00, + 0xa2, 0x00, + 0xb0, 0x91, + 0xb1, 0x0b, + 0xc0, 0x53, + 0xc1, 0x70, + 0xc2, 0x12, + 0xd0, 0x00, + 0xd1, 0x00, + 0xd2, 0x00, + 0xd3, 0x00, + 0xd4, 0x00, + 0xd5, 0x00, + 0xde, 0x00, + 0xdf, 0x00, + 0x61, 0x49, + 0x62, 0x0b, + 0x53, 0x08, + 0x59, 0x08, }; static int stv0297_writereg (struct stv0297_state* state, u8 reg, u8 data) { - int ret; - u8 buf [] = { reg, data }; - struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; - - ret = i2c_transfer (state->i2c, &msg, 1); - - if (ret != 1) - dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, " - "ret == %i)\n", __FUNCTION__, reg, data, ret); - - return (ret != 1) ? -1 : 0; -} - -static int stv0297_writeregs (struct stv0297_state* state, u8 *data, int len) -{ int ret; - struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = data, .len = len }; - + u8 buf [] = { reg, data }; + struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; + ret = i2c_transfer (state->i2c, &msg, 1); - + if (ret != 1) - dprintk("%s: writeregs error\n ", __FUNCTION__); + dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, " + "ret == %i)\n", __FUNCTION__, reg, data, ret); return (ret != 1) ? -1 : 0; } static u8 stv0297_readreg (struct stv0297_state* state, u8 reg) { - int ret; u8 b0[] = { reg }; u8 b1[] = { 0 }; - struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }, - { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; + struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }, + { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; - ret = i2c_transfer (state->i2c, msg, 2); + ret = i2c_transfer (state->i2c, msg, 2); - if (ret != 2) - dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", - __FUNCTION__, reg, ret); + if (ret != 2) + dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", + __FUNCTION__, reg, ret); return b1[0]; } +static int stv0297_writereg_mask (struct stv0297_state* state, u8 reg, u8 mask, u8 data) +{ + int val; + + val = stv0297_readreg(state, reg); + val &= ~mask; + val |= (data & mask); + stv0297_writereg(state, reg, val); + + return 0; +} + static int stv0297_readregs (struct stv0297_state* state, u8 reg1, u8 *b, u8 len) { - 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 } }; + 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); + 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 stv0297_set_symbolrate (struct stv0297_state* state, u32 srate) +static int stv0297_set_symbolrate (struct stv0297_state* state, u32 srate) { -/* - Betanova sniff : 690000 - stv0297_writereg (i2c, 0x55, 0x4E); - stv0297_writereg (i2c, 0x56, 0x00); - stv0297_writereg (i2c, 0x57, 0x1F); - stv0297_writereg (i2c, 0x58, 0x3D); -*/ - long tmp, ExtClk; - - ExtClk = (long)(STV0297_CLOCK) / 4; /* 1/4 = 2^-2 */ - tmp = 131072L * srate; /* 131072 = 2^17 */ - tmp = tmp /ExtClk; - tmp = tmp * 8192L; /* 8192 = 2^13 */ - - stv0297_writereg (state, 0x55,(unsigned char)(tmp & 0xFF)); - stv0297_writereg (state, 0x56,(unsigned char)(tmp>> 8)); - stv0297_writereg (state, 0x57,(unsigned char)(tmp>>16)); - stv0297_writereg (state, 0x58,(unsigned char)(tmp>>24)); - - return 0; + u64 tmp; + + tmp = srate; + tmp <<= 32; + do_div(tmp, STV0297_CLOCK); + + stv0297_writereg (state, 0x55,(unsigned char)(tmp & 0xFF)); + stv0297_writereg (state, 0x56,(unsigned char)(tmp>> 8)); + stv0297_writereg (state, 0x57,(unsigned char)(tmp>>16)); + stv0297_writereg (state, 0x58,(unsigned char)(tmp>>24)); + + return 0; } -void stv0297_set_sweeprate(struct stv0297_state* state, short _FShift, long _SymbolRate) +static u32 stv0297_get_symbolrate (struct stv0297_state* state) { - long long_tmp; - short FShift ; - unsigned char carrier; - int RegSymbolRate; + u64 tmp; + + tmp = stv0297_readreg(state, 0x55); + tmp |= (stv0297_readreg(state, 0x56) << 8); + tmp |= (stv0297_readreg(state, 0x57) << 16); + tmp |= (stv0297_readreg(state, 0x57) << 24); + + tmp *= STV0297_CLOCK; + tmp >>= 32; + return tmp; +} - FShift = _FShift; /* in mS .. +/- 5,100 S von 6975 S */ - RegSymbolRate = _SymbolRate; //RegGetSRate() ; /* in KHz */ - if(RegSymbolRate <= 0) return ; +static void stv0297_set_sweeprate(struct stv0297_state* state, short fshift) +{ + s64 tmp; + u32 symrate; - long_tmp = (long)FShift * 262144L ; // 262144 = 2*18 - long_tmp /= RegSymbolRate ; - long_tmp *= 1024 ; // 1024 = 2*10 + symrate = stv0297_get_symbolrate(state); - if(long_tmp >= 0) - long_tmp += 500000 ; - else long_tmp -= 500000 ; - long_tmp /= 1000000 ; + // cannot use shifts - it is signed + tmp = fshift * (1<<28); + do_div(tmp, symrate); - stv0297_writereg (state, 0x60,(unsigned char)(long_tmp & 0xFF)); + // adjust + if (tmp >= 0) { + tmp += 500000; + } else { + tmp -= 500000; + } + do_div(tmp, 1000000); - carrier = stv0297_readreg(state, 0x69) & ~ 0xF0; - carrier |= (unsigned char)((long_tmp>>4) & 0xF0); - stv0297_writereg (state, 0x69, carrier); + stv0297_writereg(state, 0x60, tmp & 0xFF); + stv0297_writereg_mask(state, 0x69, 0xF0, (tmp >> 4) & 0xf0); return; } -void stv0297_set_frequencyoffset(struct stv0297_state* state, long _CarrierOffset) +static void stv0297_set_carrieroffset(struct stv0297_state* state, long offset) { - long long_tmp; - unsigned char sweep; + long long_tmp; - long_tmp = _CarrierOffset * 26844L ; /* (2**28)/10000 */ + // symrate is hardcoded to 10000 here - don't ask me why + long_tmp = offset * 26844L ; /* (2**28)/10000 */ if(long_tmp < 0) long_tmp += 0x10000000 ; long_tmp &= 0x0FFFFFFF ; stv0297_writereg (state,0x66,(unsigned char)(long_tmp & 0xFF)); // iphase0 stv0297_writereg (state,0x67,(unsigned char)(long_tmp>>8)); // iphase1 stv0297_writereg (state,0x68,(unsigned char)(long_tmp>>16)); // iphase2 - - sweep = stv0297_readreg(state,0x69) & 0xF0; - sweep |= ((unsigned char)(long_tmp>>24) & 0x0F); - stv0297_writereg (state,0x69,sweep); + stv0297_writereg_mask(state, 0x69, 0x0F, (long_tmp >> 24) & 0x0f); return; } +static long stv0297_get_carrieroffset(struct stv0297_state* state) +{ + s32 raw; + s64 tmp; + u32 symbol_rate; + + stv0297_writereg(state,0x6B, 0x00); + + symbol_rate = stv0297_get_symbolrate(state); + + raw = stv0297_readreg(state,0x66); + raw |= (stv0297_readreg(state,0x67) << 8); + raw |= (stv0297_readreg(state,0x68) << 16); + raw |= (stv0297_readreg(state,0x69) & 0x0F) << 24; + + // cannot just use a shift here 'cos it is signed + tmp = raw; + tmp *= symbol_rate; + do_div(tmp, 1<<28); + + return (s32) tmp; +} + +static void stv0297_set_initialdemodfreq(struct stv0297_state* state, long freq) +{ + u64 tmp; + + if (freq > 10000) freq -= STV0297_CLOCK; + if (freq < 0) freq = 0; + + tmp = freq << 16; + do_div(tmp, STV0297_CLOCK); + if (tmp > 0xffff) tmp = 0xffff; + + stv0297_writereg_mask(state, 0x25, 0x80, 0x80); + stv0297_writereg(state, 0x21, tmp >> 8); + stv0297_writereg(state, 0x20, tmp); +} + +static int stv0297_set_qam(struct stv0297_state* state, fe_modulation_t modulation) +{ + int val = 0; + switch(modulation) { + case QAM_16: + val = 0; + break; + case QAM_32: + val = 1; + break; + case QAM_64: + val = 4; + break; + case QAM_128: + val = 2; + break; + case QAM_256: + val = 3; + break; + default: + return -EINVAL; + } + stv0297_writereg_mask(state, 0x00, 0x70, val << 4); + return 0; +} +static int stv0297_set_inversion(struct stv0297_state* state, fe_spectral_inversion_t inversion) +{ + int val = 0; + switch(inversion) { + case INVERSION_OFF: + val = 0; + break; + case INVERSION_ON: + val = 1; + break; + default: + return -EINVAL; + } + + stv0297_writereg_mask(state, 0x83, 0x08, val << 3); + + return 0; +} + + + + + + + + + + + + + +int stv0297_enable_plli2c(struct dvb_frontend* fe) +{ + struct stv0297_state* state = (struct stv0297_state*) fe->demodulator_priv; + + stv0297_writereg(state, 0x87, 0x78); + stv0297_writereg(state, 0x86, 0xc8); + + return 0; +} static int stv0297_init (struct dvb_frontend* fe) { struct stv0297_state* state = (struct stv0297_state*) fe->demodulator_priv; - int i; + int i; - dprintk("stv0297: init chip\n"); + stv0297_writereg(state, 0x80, stv0297_readreg(state, 0x80) | 1); + stv0297_writereg(state, 0x80, stv0297_readreg(state, 0x80) & 0xfe); + stv0297_writereg(state, 0x81, stv0297_readreg(state, 0x81) | 1); + stv0297_writereg(state, 0x81, stv0297_readreg(state, 0x81) & 0xfe); - for (i=0; i<sizeof(init_tab); i+=2) { - stv0297_writereg (state, init_tab[i], init_tab[i+1]); - } + for (i=0; i<sizeof(init_tab); i+=2) { + stv0297_writereg (state, init_tab[i], init_tab[i+1]); + } - return 0; + stv0297_set_symbolrate(state, 7000); + stv0297_writereg(state, 0x88, stv0297_readreg(state, 0x88) | 0x10); + stv0297_writereg(state, 0xa0, (stv0297_readreg(state, 0xa0) & 0x60) | 0x04); + stv0297_writereg(state, 0x4a, 0x00); + stv0297_writereg(state, 0x4b, state->pwm); + + if (state->config->pll_init) state->config->pll_init(fe); + + return 0; } static int stv0297_read_status(struct dvb_frontend* fe, fe_status_t* status) { struct stv0297_state* state = (struct stv0297_state*) fe->demodulator_priv; - u8 sync = stv0297_readreg (state, 0xDF); - - *status = 0; - if (sync & 0x80) - *status |= FE_HAS_SYNC | FE_HAS_SIGNAL; - if (sync & 0x80) - *status |= FE_HAS_CARRIER; - if (sync & 0x80) - *status |= FE_HAS_VITERBI; - if (sync & 0x80) - *status |= FE_HAS_LOCK; - return 0; + u8 sync = stv0297_readreg (state, 0xDF); + + *status = 0; + if (sync & 0x80) + *status |= FE_HAS_SYNC | FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_LOCK; + return 0; } static int stv0297_read_ber(struct dvb_frontend* fe, u32* ber) { struct stv0297_state* state = (struct stv0297_state*) fe->demodulator_priv; - u8 BER[3]; + u8 BER[3]; - stv0297_writereg (state, 0xA0, 0x80); // Start Counting bit errors for 4096 Bytes - mdelay(25); // Hopefully got 4096 Bytes - stv0297_readregs (state, 0xA0, BER, 3); - mdelay(25); - *ber = (BER[2] << 8 | BER[1]) / ( 8 * 4096); + stv0297_writereg (state, 0xA0, 0x80); // Start Counting bit errors for 4096 Bytes + mdelay(25); // Hopefully got 4096 Bytes + stv0297_readregs (state, 0xA0, BER, 3); + mdelay(25); + *ber = (BER[2] << 8 | BER[1]) / ( 8 * 4096); - return 0; + return 0; } static int stv0297_read_signal_strength(struct dvb_frontend* fe, u16* strength) { struct stv0297_state* state = (struct stv0297_state*) fe->demodulator_priv; - u8 STRENGTH[2]; + u8 STRENGTH[2]; - mdelay(25); - stv0297_readregs (state, 0x41, STRENGTH, 2); - *strength = (STRENGTH[1] & 0x03) << 8 | STRENGTH[0]; + stv0297_readregs (state, 0x41, STRENGTH, 2); + *strength = (STRENGTH[1] & 0x03) << 8 | STRENGTH[0]; - return 0; + return 0; } static int stv0297_read_snr(struct dvb_frontend* fe, u16* snr) { struct stv0297_state* state = (struct stv0297_state*) fe->demodulator_priv; - u8 SNR[2]; + u8 SNR[2]; - mdelay(25); - stv0297_readregs (state, 0x07, SNR, 2); - *snr = SNR[1] << 8 | SNR[0]; + stv0297_readregs (state, 0x07, SNR, 2); + *snr = SNR[1] << 8 | SNR[0]; - return 0; + return 0; } static int stv0297_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) { struct stv0297_state* state = (struct stv0297_state*) fe->demodulator_priv; - *ucblocks = (stv0297_readreg (state, 0xD5) << 8) + *ucblocks = (stv0297_readreg (state, 0xD5) << 8) | stv0297_readreg (state, 0xD4); - return 0; + return 0; } static int stv0297_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters * p) { struct stv0297_state* state = (struct stv0297_state*) fe->demodulator_priv; - u8 buf2[] = { 0x83, 0x10, 0x25, 0x00, 0x78, 0x73 }; - u8 buf3[] = { 0xC0, 0x4B, 0x01, 0x00 }; - int CarrierOffset = -500; - int SweepRate = 1380; - int SpectrumInversion = 0; - - if (SpectrumInversion) { - SweepRate = -SweepRate ; - CarrierOffset = -CarrierOffset ; - } - else { - SweepRate = SweepRate ; - CarrierOffset = CarrierOffset ; - } - - stv0297_writereg(state, 0x86, 0xF8); + int u_threshold; + int initial_u; + int blind_u; + int delay; + int locked; + int sweeprate; + int carrieroffset; + unsigned long starttime; + unsigned long timeout; + + switch(p->u.qam.modulation) { + case QAM_16: + case QAM_32: + case QAM_64: + delay = 100; + sweeprate = 1500; + break; + + case QAM_128: + delay = 150; + sweeprate = 1000; + break; + + case QAM_256: + delay = 200; + sweeprate = 500; + break; + + default: + return -EINVAL; + } + + // determine inversion dependant parameters + carrieroffset = -330; + switch(p->inversion) { + case INVERSION_OFF: + break; + + case INVERSION_ON: + sweeprate = -sweeprate; + carrieroffset = -carrieroffset; + break; + + default: + return -EINVAL; + } + state->config->pll_set(fe, p); - - stv0297_writeregs (state, buf2, sizeof(buf2)); - stv0297_writereg (state, 0x84, 0x24); - stv0297_writeregs (state, buf3, sizeof(buf3)); - stv0297_writereg (state, 0x88, 0x08); - stv0297_writereg (state, 0x90, 0x01); - stv0297_writereg (state, 0x37, 0x20); - stv0297_writereg (state, 0x40, 0x19); - stv0297_writereg (state, 0x43, 0x40); - stv0297_writereg (state, 0x41, 0xE4); - stv0297_writereg (state, 0x42, 0x3C); - stv0297_writereg (state, 0x44, 0xFF); - stv0297_writereg (state, 0x49, 0x04); - stv0297_writereg (state, 0x4A, 0xFF); - stv0297_writereg (state, 0x4B, 0xFF); - stv0297_writereg (state, 0x71, 0x04); - stv0297_writereg (state, 0x53, 0x08); - stv0297_writereg (state, 0x5A, 0x3E); //3E forces the direct path to be immediately - stv0297_writereg (state, 0x5B, 0x07); - stv0297_writereg (state, 0x5B, 0x05); - - stv0297_set_symbolrate (state, p->u.qam.symbol_rate/1000); - stv0297_writereg (state, 0x59, 0x08); - stv0297_writereg (state, 0x61, 0x49); - stv0297_writereg (state, 0x62, 0x0E); - stv0297_writereg (state, 0x6A, 0x02); - stv0297_writereg (state, 0x00, 0x48); // set qam-64 - - stv0297_writereg (state, 0x01, 0x58); - stv0297_writereg (state, 0x82, 0x00); - stv0297_writereg (state, 0x83, 0x08); - stv0297_set_sweeprate(state,SweepRate, p->u.qam.symbol_rate/1000); - stv0297_writereg (state, 0x20, 0x00); - stv0297_writereg (state, 0x21, 0x40); - stv0297_set_frequencyoffset(state,CarrierOffset); - - stv0297_writereg (state, 0x82, 0x00); - stv0297_writereg (state, 0x85, 0x04); - stv0297_writereg (state, 0x43, 0x10); - stv0297_writereg (state, 0x5A, 0x5E); - - stv0297_writereg (state, 0x6A, 0x03); - - stv0297_writereg (state, 0x85, 0x04); - stv0297_writereg (state, 0x6B, 0x00); - stv0297_writereg (state, 0x4A, 0xFF); - stv0297_writereg (state, 0x61, 0x49); - stv0297_writereg (state, 0x62, 0x0E); - stv0297_writereg (state, 0xDF, 0x02); - stv0297_writereg (state, 0xDF, 0x01); - - stv0297_writereg (state, 0xDF, 0x02); - stv0297_writereg (state, 0xDF, 0x01); - - stv0297_writereg (state, 0xDF, 0x02); - stv0297_writereg (state, 0xDF, 0x01); + + // reset everything + stv0297_writereg_mask(state, 0x82, 0x4, 0x4); + stv0297_set_initialdemodfreq(state, state->freq_off + 7250); + stv0297_writereg_mask(state, 0x43, 0x10, 0x00); + stv0297_writereg(state, 0x41, 0x00); + stv0297_writereg_mask(state, 0x42, 0x03, 0x01); + stv0297_writereg_mask(state, 0x36, 0x60, 0x00); + stv0297_writereg_mask(state, 0x36, 0x18, 0x00); + stv0297_writereg_mask(state, 0x71, 0x80, 0x80); + stv0297_writereg(state, 0x72, 0x00); + stv0297_writereg(state, 0x73, 0x00); + stv0297_writereg_mask(state, 0x74, 0x0F, 0x00); + stv0297_writereg_mask(state, 0x43, 0x08, 0x00); + stv0297_writereg_mask(state, 0x71, 0x80, 0x00); + stv0297_writereg_mask(state, 0x5a, 0x20, 0x20); + stv0297_writereg_mask(state, 0x5b, 0x02, 0x02); + stv0297_writereg_mask(state, 0x5b, 0x02, 0x00); + stv0297_writereg_mask(state, 0x5b, 0x01, 0x00); + stv0297_writereg_mask(state, 0x5a, 0x40, 0x40); + stv0297_writereg_mask(state, 0x6a, 0x01, 0x00); + stv0297_writereg_mask(state, 0x81, 0x01, 0x01); + stv0297_writereg_mask(state, 0x81, 0x01, 0x00); + stv0297_writereg_mask(state, 0x83, 0x20, 0x20); + stv0297_writereg_mask(state, 0x83, 0x20, 0x00); + u_threshold = stv0297_readreg(state, 0x00) & 0xf; + initial_u = stv0297_readreg(state, 0x01) >> 4; + blind_u = stv0297_readreg(state, 0x01) & 0xf; + stv0297_writereg_mask(state, 0x84, 0x01, 0x01); + stv0297_writereg_mask(state, 0x84, 0x01, 0x00); + stv0297_writereg_mask(state, 0x00, 0x0f, u_threshold); + stv0297_writereg_mask(state, 0x01, 0xf0, initial_u << 4); + stv0297_writereg_mask(state, 0x01, 0x0f, blind_u); + stv0297_writereg_mask(state, 0x87, 0x80, 0x00); + stv0297_writereg(state, 0x63, 0x00); + stv0297_writereg(state, 0x64, 0x00); + stv0297_writereg(state, 0x65, 0x00); + stv0297_writereg(state, 0x66, 0x00); + stv0297_writereg(state, 0x67, 0x00); + stv0297_writereg(state, 0x68, 0x00); + stv0297_writereg_mask(state, 0x69, 0x0f, 0x00); + + // set parameters + stv0297_set_qam(state, p->u.qam.modulation); + stv0297_set_symbolrate(state, p->u.qam.symbol_rate/1000); + stv0297_set_sweeprate(state, sweeprate); + stv0297_set_carrieroffset(state, carrieroffset); + stv0297_set_inversion(state, p->inversion); + + // kick off lock + stv0297_writereg_mask(state, 0x88, 0x08, 0x08); + stv0297_writereg_mask(state, 0x5a, 0x20, 0x00); + stv0297_writereg_mask(state, 0x6a, 0x01, 0x01); + stv0297_writereg_mask(state, 0x43, 0x40, 0x40); + stv0297_writereg_mask(state, 0x5b, 0x30, 0x00); + stv0297_writereg_mask(state, 0x03, 0x0c, 0x0c); + stv0297_writereg_mask(state, 0x03, 0x03, 0x03); + stv0297_writereg_mask(state, 0x43, 0x10, 0x10); + + // wait for WGAGC lock + starttime = jiffies; + timeout = jiffies + (200*HZ)/1000; + while(time_before(jiffies, timeout)) { + msleep(10); + if (stv0297_readreg(state, 0x43) & 0x08) break; + } + if (time_after(jiffies, timeout)) { + goto timeout; + } + msleep(20); + + // wait for equaliser partial convergence + locked = 0; + timeout = jiffies + (50*HZ)/1000; + while(time_before(jiffies, timeout)) { + msleep(10); + + if (stv0297_readreg(state, 0x82) & 0x04) { + locked = 1; + } + } + if (time_after(jiffies, timeout) && (!locked)) { + goto timeout; + } + + // wait for equaliser full convergence + timeout = jiffies + (delay*HZ)/1000; + while(time_before(jiffies, timeout)) { + msleep(10); + + if (stv0297_readreg(state, 0x82) & 0x08) { + break; + } + } + if (time_after(jiffies, timeout)) { + goto timeout; + } + + // disable sweep + stv0297_writereg_mask(state, 0x6a, 1, 0); + stv0297_writereg_mask(state, 0x88, 8, 0); + + // wait for main lock + timeout = jiffies + (20*HZ)/1000; + while(time_before(jiffies, timeout)) { + msleep(10); + + if (stv0297_readreg(state, 0xDF) & 0x80) { + break; + } + } + if (time_after(jiffies, timeout)) { + goto timeout; + } + msleep(100); + + // is it still locked after that delay? + if (!(stv0297_readreg(state, 0xDF) & 0x80)) { + goto timeout; + } + + // success!! + stv0297_writereg_mask(state, 0x5a, 0x40, 0x00); + state->freq_off = stv0297_get_carrieroffset(state); + state->base_freq = p->frequency; + return 0; + +timeout: + stv0297_writereg_mask(state, 0x6a, 0x01, 0x00); + return 0; +} - return 0; +static int stv0297_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters * p) +{ + struct stv0297_state* state = (struct stv0297_state*) fe->demodulator_priv; + int reg_00, reg_83; + + reg_00 = stv0297_readreg(state, 0x00); + reg_83 = stv0297_readreg(state, 0x83); + + p->frequency = state->base_freq + state->freq_off; + p->inversion = (reg_83 & 0x08) ? INVERSION_ON : INVERSION_OFF; + p->u.qam.symbol_rate = stv0297_get_symbolrate(state); + p->u.qam.fec_inner = 0; + + switch((reg_00 >> 4) & 0x7) { + case 0: p->u.qam.modulation = QAM_16; break; + case 1: p->u.qam.modulation = QAM_32; break; + case 2: p->u.qam.modulation = QAM_128; break; + case 3: p->u.qam.modulation = QAM_256; break; + case 4: p->u.qam.modulation = QAM_64; break; + } + + return 0; } static void stv0297_release(struct dvb_frontend* fe) { - struct stv0297_state* state = (struct stv0297_state*) fe->demodulator_priv; - kfree(state); + struct stv0297_state* state = (struct stv0297_state*) fe->demodulator_priv; + kfree(state); } static struct dvb_frontend_ops stv0297_ops; struct dvb_frontend* stv0297_attach(const struct stv0297_config* config, - struct i2c_adapter* i2c) + struct i2c_adapter* i2c, + int pwm) { - struct stv0297_state* state = NULL; - int id; - - /* allocate memory for the internal state */ - state = (struct stv0297_state*) kmalloc(sizeof(struct stv0297_state), GFP_KERNEL); - if (state == NULL) goto error; - - /* setup the state */ - state->config = config; - state->i2c = i2c; - memcpy(&state->ops, &stv0297_ops, sizeof(struct dvb_frontend_ops)); - - /* check if the demod is there */ - stv0297_writereg(state, 0x02, 0x34); /* standby off */ - msleep(200); - id = stv0297_readreg(state, 0x00); - - /* register 0x00 contains 0xa1 for STV0299 and STV0299B */ - /* register 0x00 might contain 0x80 when returning from standby */ - if (id != 0xa1 && id != 0x80) goto error; - - /* create dvb_frontend */ - state->frontend.ops = &state->ops; - state->frontend.demodulator_priv = state; - return &state->frontend; + u8 b0[] = { 0x80 }; + u8 b1[] = { 0 }; + struct i2c_msg msg [] = { { .addr = config->demod_address, .flags = 0, .buf = b0, .len = 1 }, + { .addr = config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; + struct stv0297_state* state = NULL; + + /* allocate memory for the internal state */ + state = (struct stv0297_state*) kmalloc(sizeof(struct stv0297_state), GFP_KERNEL); + if (state == NULL) goto error; + + /* setup the state */ + state->config = config; + state->i2c = i2c; + memcpy(&state->ops, &stv0297_ops, sizeof(struct dvb_frontend_ops)); + state->freq_off = 0; + state->base_freq = 0; + state->pwm = pwm; + + /* check if the demod is there */ + if (i2c_transfer (state->i2c, msg, 2) != 2) 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; + if (state) kfree(state); + return NULL; } static struct dvb_frontend_ops stv0297_ops = { - .info = { - .name = "ST STV0297 DVB-C", - .type = FE_QAM, - .frequency_min = 64000000, - .frequency_max = 1300000000, - .frequency_stepsize = 62500, - .symbol_rate_min = 870000, - .symbol_rate_max = 11700000, - .caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | - FE_CAN_QAM_128 | FE_CAN_QAM_256 | - FE_CAN_FEC_AUTO | FE_CAN_INVERSION_AUTO | - FE_CAN_RECOVER - }, - - .release = stv0297_release, - - .init = stv0297_init, - - .set_frontend = stv0297_set_frontend, - - .read_status = stv0297_read_status, - .read_ber = stv0297_read_ber, - .read_signal_strength = stv0297_read_signal_strength, - .read_snr = stv0297_read_snr, - .read_ucblocks = stv0297_read_ucblocks, + .info = { + .name = "ST STV0297 DVB-C", + .type = FE_QAM, + .frequency_min = 64000000, + .frequency_max = 1300000000, + .frequency_stepsize = 62500, + .symbol_rate_min = 870000, + .symbol_rate_max = 11700000, + .caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | + FE_CAN_QAM_128 | FE_CAN_QAM_256 | + FE_CAN_FEC_AUTO | FE_CAN_INVERSION_AUTO | + FE_CAN_RECOVER + }, + + .release = stv0297_release, + + .init = stv0297_init, + + .set_frontend = stv0297_set_frontend, + .get_frontend = stv0297_get_frontend, + + .read_status = stv0297_read_status, + .read_ber = stv0297_read_ber, + .read_signal_strength = stv0297_read_signal_strength, + .read_snr = stv0297_read_snr, + .read_ucblocks = stv0297_read_ucblocks, }; MODULE_DESCRIPTION("ST STV0297 DVB-C Demodulator driver"); -MODULE_AUTHOR("Dennis Noermann"); +MODULE_AUTHOR("Dennis Noermann and Andrew de Quincey"); MODULE_LICENSE("GPL"); EXPORT_SYMBOL(stv0297_attach); diff --git a/linux/drivers/media/dvb/frontends/stv0297.h b/linux/drivers/media/dvb/frontends/stv0297.h index cb9aead87..355aa8720 100644 --- a/linux/drivers/media/dvb/frontends/stv0297.h +++ b/linux/drivers/media/dvb/frontends/stv0297.h @@ -16,7 +16,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ +*/ #ifndef STV0297_H #define STV0297_H @@ -35,6 +35,7 @@ struct stv0297_config }; extern struct dvb_frontend* stv0297_attach(const struct stv0297_config* config, - struct i2c_adapter* i2c); + struct i2c_adapter* i2c, int pwm); +extern int stv0297_enable_plli2c(struct dvb_frontend* fe); #endif // STV0297_H diff --git a/linux/drivers/media/dvb/ttpci/av7110.c b/linux/drivers/media/dvb/ttpci/av7110.c index 9fa22046c..c2ff00fc7 100644 --- a/linux/drivers/media/dvb/ttpci/av7110.c +++ b/linux/drivers/media/dvb/ttpci/av7110.c @@ -1643,6 +1643,47 @@ static struct sp8870_config alps_tdlb7_config = { }; + +static int nexusca_stv0297_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +{ + struct av7110* av7110 = (struct av7110*) fe->dvb->priv; + u32 div; + u8 data[4]; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; + + // this calculation does not match the TDA6405TS datasheet! + div = (params->frequency + 36150000) / 62500; + + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = 0xce; // this value does not match the TDA6405TS datasheet! + + if (params->frequency < 45000000) + return -EINVAL; + else if (params->frequency < 137000000) + data[3] = 0x01; + else if (params->frequency < 403000000) + data[3] = 0x02; + else if (params->frequency < 860000000) + data[3] = 0x04; + else + return -EINVAL; + + stv0297_enable_plli2c(fe); + if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1) + return -EIO; + msleep(20); + + return 0; +} + +static struct stv0297_config nexusca_stv0297_config = { + + .demod_address = 0x1C, + .pll_set = nexusca_stv0297_pll_set, +}; + + static void av7110_fe_lock_fix(struct av7110* av7110, fe_status_t status) { msleep (50); @@ -1815,6 +1856,28 @@ static void frontend_init(struct av7110 *av7110) if (av7110->fe) break; break; + + case 0x000A: { // Hauppauge/TT Nexus-CA rev1.X + u8 b = 0x00; + u8 revbuf[4]; + int revision; + struct i2c_msg msg[] = { { .addr = 0x50,.flags = 0,.buf = &b,.len = 1 }, + { .addr = 0x50,.flags = I2C_M_RD,.buf = revbuf,.len = sizeof(revbuf)} }; + + // retrieve board revision + if (i2c_transfer(&av7110->i2c_adap, msg, 2) != 2) + break; + printk("revbuf[0] = 0x%x\n", revbuf[0]); + printk("revbuf[1] = 0x%x\n", revbuf[1]); + printk("revbuf[2] = 0x%x\n", revbuf[2]); + printk("revbuf[3] = 0x%x\n", revbuf[3]); + revision = revbuf[0] | (revbuf[1] << 8); + + av7110->fe = stv0297_attach(&nexusca_stv0297_config, &av7110->i2c_adap, (revision < 10) ? 0x64 : 0x7b); + if (av7110->fe) + break; + break; + } } } @@ -2076,6 +2139,7 @@ static struct saa7146_pci_extension_data x_var = { \ MAKE_AV7110_INFO(tts_1_X, "Technotrend/Hauppauge WinTV DVB-S rev1.X"); MAKE_AV7110_INFO(ttt_1_X, "Technotrend/Hauppauge WinTV DVB-T rev1.X"); +MAKE_AV7110_INFO(ttc_1_X, "Technotrend/Hauppauge WinTV Nexus-CA rev1.X"); MAKE_AV7110_INFO(ttc_2_X, "Technotrend/Hauppauge WinTV DVB-C rev2.X"); MAKE_AV7110_INFO(tts_2_X, "Technotrend/Hauppauge WinTV Nexus-S rev2.X"); MAKE_AV7110_INFO(tts_1_3se, "Technotrend/Hauppauge WinTV Nexus-S rev1.3"); @@ -2088,13 +2152,13 @@ static struct pci_device_id pci_tbl[] = { MAKE_EXTENSION_PCI(tts_2_X, 0x13c2, 0x0003), MAKE_EXTENSION_PCI(tts_1_3se, 0x13c2, 0x1002), MAKE_EXTENSION_PCI(fsc, 0x110a, 0x0000), + MAKE_EXTENSION_PCI(ttc_1_X, 0x13c2, 0x000a), /* MAKE_EXTENSION_PCI(???, 0x13c2, 0x0004), UNDEFINED CARD */ // Galaxis DVB PC-Sat-Carte /* MAKE_EXTENSION_PCI(???, 0x13c2, 0x0005), UNDEFINED CARD */ // Technisat SkyStar1 /* MAKE_EXTENSION_PCI(???, 0x13c2, 0x0006), UNDEFINED CARD */ // TT/Hauppauge WinTV Nexus-S v???? /* MAKE_EXTENSION_PCI(???, 0x13c2, 0x0008), UNDEFINED CARD */ // TT/Hauppauge WinTV DVB-T v???? /* MAKE_EXTENSION_PCI(???, 0x13c2, 0x0009), UNDEFINED CARD */ // TT/Hauppauge WinTV Nexus-CA v???? -/* MAKE_EXTENSION_PCI(???, 0x13c2, 0x000a), UNDEFINED CARD */ // TT/Hauppauge WinTV Nexus-CA v???? { .vendor = 0, diff --git a/linux/drivers/media/dvb/ttpci/av7110.h b/linux/drivers/media/dvb/ttpci/av7110.h index 5d2da07f8..86752bc91 100644 --- a/linux/drivers/media/dvb/ttpci/av7110.h +++ b/linux/drivers/media/dvb/ttpci/av7110.h @@ -30,7 +30,7 @@ #include "stv0299.h" #include "tda8083.h" #include "sp8870.h" - +#include "stv0297.h" #include <media/saa7146_vv.h> |