summaryrefslogtreecommitdiff
path: root/linux/drivers/media
diff options
context:
space:
mode:
authorAndrew de Quincy <devnull@localhost>2004-11-09 09:54:11 +0000
committerAndrew de Quincy <devnull@localhost>2004-11-09 09:54:11 +0000
commitaef71b24f260b4df387aa15ec2b5a4c5d40499b9 (patch)
tree8d180025d278463de065fe0c0aac4d1117a39e7e /linux/drivers/media
parent32115d6f2fd9c9aea933e8163e30a29c4f5a981f (diff)
downloadmediapointer-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.c873
-rw-r--r--linux/drivers/media/dvb/frontends/stv0297.h5
-rw-r--r--linux/drivers/media/dvb/ttpci/av7110.c66
-rw-r--r--linux/drivers/media/dvb/ttpci/av7110.h2
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 = &reg1, .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 = &reg1, .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>