summaryrefslogtreecommitdiff
path: root/linux/drivers/media/dvb/frontends/stv0299.c
diff options
context:
space:
mode:
Diffstat (limited to 'linux/drivers/media/dvb/frontends/stv0299.c')
-rw-r--r--linux/drivers/media/dvb/frontends/stv0299.c1522
1 files changed, 383 insertions, 1139 deletions
diff --git a/linux/drivers/media/dvb/frontends/stv0299.c b/linux/drivers/media/dvb/frontends/stv0299.c
index bfa7b2575..12e45376f 100644
--- a/linux/drivers/media/dvb/frontends/stv0299.c
+++ b/linux/drivers/media/dvb/frontends/stv0299.c
@@ -1,8 +1,5 @@
/*
- Universal driver for STV0299/TDA5059/SL1935 based
- DVB QPSK frontends
-
- Alps BSRU6, LG TDQB-S00x
+ Driver for ST STV0299 demodulator
Copyright (C) 2001-2002 Convergence Integrated Media GmbH
<ralph@convergence.de>,
@@ -54,236 +51,42 @@
#include <asm/div64.h>
#include "dvb_frontend.h"
+#include "stv0299.h"
-#define FRONTEND_NAME "dvbfe_stv0299"
-
-#define dprintk(args...) \
- do { \
- if (debug) printk(KERN_DEBUG FRONTEND_NAME ": " args); \
- } while (0)
-
-static int debug;
-static int stv0299_status;
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-module_param(stv0299_status, int, 0444);
-MODULE_PARM_DESC(stv0299_status, "Which status value to support "
- "(0 == BER (default), 1 == UCBLOCKS)");
+struct stv0299_state {
-#define STATUS_BER 0
-#define STATUS_UCBLOCKS 1
+ struct i2c_adapter* i2c;
+ struct dvb_frontend_ops ops;
-/* frontend types */
-#define UNKNOWN_FRONTEND -1
-#define PHILIPS_SU1278_TSA 0 // SU1278 with TSA5059 synth and datasheet recommended settings
-#define ALPS_BSRU6 1
-#define LG_TDQF_S001F 2
-#define PHILIPS_SU1278_TUA 3 // SU1278 with TUA6100 synth
-#define SAMSUNG_TBMU24112IMB 4
-#define PHILIPS_SU1278_TSA_TT 5 // SU1278 with TSA5059 synth and TechnoTrend settings
-#define PHILIPS_SU1278_TSA_TY 6 // SU1278 with TUA5059 synth and Typhoon wiring
-#define PHILIPS_SU1278_TSA_CI 7 // SU1278 with TUA5059 synth and TerraTec Cinergy wiring
-
-/* Master Clock = 88 MHz */
-#define M_CLK (88000000UL)
-
-/* Master Clock for TT cards = 64 MHz */
-#define M_CLK_SU1278_TSA_TT (64000000UL)
-
-static struct dvb_frontend_info uni0299_info = {
- .name = "STV0299/TSA5059/SL1935 based",
- .type = FE_QPSK,
- .frequency_min = 950000,
- .frequency_max = 2150000,
- .frequency_stepsize = 125, /* kHz for QPSK frontends */
- .frequency_tolerance = M_CLK/2000,
- .symbol_rate_min = 1000000,
- .symbol_rate_max = 45000000,
- .symbol_rate_tolerance = 500, /* ppm */
- .notifier_delay = 0,
- .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
- FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
- FE_CAN_QPSK |
- FE_CAN_FEC_AUTO
-};
+ const struct stv0299_config* config;
+ struct dvb_frontend frontend;
-struct stv0299_state {
- u8 tuner_type;
u8 initialised:1;
u32 tuner_frequency;
u32 symbol_rate;
fe_code_rate_t fec_inner;
- struct i2c_adapter *i2c;
- struct dvb_adapter *dvb;
+ int errmode;
};
+#define STATUS_BER 0
+#define STATUS_UCBLOCKS 1
-static u8 init_tab [] = {
- 0x04, 0x7d, /* F22FR = 0x7d */
- /* F22 = f_VCO / 128 / 0x7d = 22 kHz */
-
- /* I2C bus repeater */
- 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */
-
- /* general purpose DAC registers */
- 0x06, 0x40, /* DAC not used, set to high impendance mode */
- 0x07, 0x00, /* DAC LSB */
-
- /* DiSEqC registers */
- 0x08, 0x40, /* DiSEqC off, LNB power on OP2/LOCK pin on */
- 0x09, 0x00, /* FIFO */
-
- /* Input/Output configuration register */
- 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
- /* OP0 ctl = Normal, OP0 val = 1 (18 V) */
- /* Nyquist filter = 00, QPSK reverse = 0 */
-
- /* AGC1 control register */
- 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */
-
- /* Timing loop register */
- 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */
-
- 0x10, 0x3f, // AGC2 0x3d
-
- 0x11, 0x84,
- 0x12, 0xb5, // Lock detect: -64 Carrier freq detect:on
-
- 0x15, 0xc9, // lock detector threshold
-
- 0x16, 0x00,
- 0x17, 0x00,
- 0x18, 0x00,
- 0x19, 0x00,
- 0x1a, 0x00,
-
- 0x1f, 0x50,
-
- 0x20, 0x00,
- 0x21, 0x00,
- 0x22, 0x00,
- 0x23, 0x00,
-
- 0x28, 0x00, // out imp: normal out type: parallel FEC mode:0
-
- 0x29, 0x1e, // 1/2 threshold
- 0x2a, 0x14, // 2/3 threshold
- 0x2b, 0x0f, // 3/4 threshold
- 0x2c, 0x09, // 5/6 threshold
- 0x2d, 0x05, // 7/8 threshold
- 0x2e, 0x01,
-
- 0x31, 0x1f, // test all FECs
-
- 0x32, 0x19, // viterbi and synchro search
- 0x33, 0xfc, // rs control
- 0x34, 0x93, // error control
-};
-
-
-static u8 init_tab_samsung [] = {
- 0x01, 0x15,
- 0x02, 0x00,
- 0x03, 0x00,
- 0x04, 0x7D,
- 0x05, 0x35,
- 0x06, 0x02,
- 0x07, 0x00,
- 0x08, 0xC3,
- 0x0C, 0x00,
- 0x0D, 0x81,
- 0x0E, 0x23,
- 0x0F, 0x12,
- 0x10, 0x7E,
- 0x11, 0x84,
- 0x12, 0xB9,
- 0x13, 0x88,
- 0x14, 0x89,
- 0x15, 0xC9,
- 0x16, 0x00,
- 0x17, 0x5C,
- 0x18, 0x00,
- 0x19, 0x00,
- 0x1A, 0x00,
- 0x1C, 0x00,
- 0x1D, 0x00,
- 0x1E, 0x00,
- 0x1F, 0x3A,
- 0x20, 0x2E,
- 0x21, 0x80,
- 0x22, 0xFF,
- 0x23, 0xC1,
- 0x28, 0x00,
- 0x29, 0x1E,
- 0x2A, 0x14,
- 0x2B, 0x0F,
- 0x2C, 0x09,
- 0x2D, 0x05,
- 0x31, 0x1F,
- 0x32, 0x19,
- 0x33, 0xFE,
- 0x34, 0x93
-};
-
-
-static u8 init_tab_su1278_tsa_tt [] = {
- 0x01, 0x0f,
- 0x02, 0x30,
- 0x03, 0x00,
- 0x04, 0x5b,
- 0x05, 0x85,
- 0x06, 0x02,
- 0x07, 0x00,
- 0x08, 0x02,
- 0x09, 0x00,
- 0x0C, 0x01,
- 0x0D, 0x81,
- 0x0E, 0x44,
- 0x0f, 0x14,
- 0x10, 0x3c,
- 0x11, 0x84,
- 0x12, 0xda,
- 0x13, 0x97,
- 0x14, 0x95,
- 0x15, 0xc9,
- 0x16, 0x19,
- 0x17, 0x8c,
- 0x18, 0x59,
- 0x19, 0xf8,
- 0x1a, 0xfe,
- 0x1c, 0x7f,
- 0x1d, 0x00,
- 0x1e, 0x00,
- 0x1f, 0x50,
- 0x20, 0x00,
- 0x21, 0x00,
- 0x22, 0x00,
- 0x23, 0x00,
- 0x28, 0x00,
- 0x29, 0x28,
- 0x2a, 0x14,
- 0x2b, 0x0f,
- 0x2c, 0x09,
- 0x2d, 0x09,
- 0x31, 0x1f,
- 0x32, 0x19,
- 0x33, 0xfc,
- 0x34, 0x13
-};
+static int debug;
+#define dprintk(args...) \
+ do { \
+ if (debug) printk(KERN_DEBUG "stv0299: " args); \
+ } while (0)
-static int stv0299_set_FEC (struct i2c_adapter *i2c, fe_code_rate_t fec);
-static int stv0299_set_symbolrate (struct i2c_adapter *i2c, u32 srate, int tuner_type);
-static int stv0299_writereg (struct i2c_adapter *i2c, u8 reg, u8 data)
+static int stv0299_writeregI (struct stv0299_state* state, u8 reg, u8 data)
{
int ret;
u8 buf [] = { reg, data };
- struct i2c_msg msg = { .addr = 0x68, .flags = 0, .buf = buf, .len = 2 };
+ struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
- ret = i2c_transfer (i2c, &msg, 1);
+ ret = i2c_transfer (state->i2c, &msg, 1);
if (ret != 1)
dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, "
@@ -292,16 +95,23 @@ static int stv0299_writereg (struct i2c_adapter *i2c, u8 reg, u8 data)
return (ret != 1) ? -EREMOTEIO : 0;
}
+int stv0299_writereg (struct dvb_frontend* fe, u8 reg, u8 data)
+{
+ struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
+
+ return stv0299_writeregI(state, reg, data);
+}
+
-static u8 stv0299_readreg (struct i2c_adapter *i2c, u8 reg)
+static u8 stv0299_readreg (struct stv0299_state* state, u8 reg)
{
int ret;
u8 b0 [] = { reg };
u8 b1 [] = { 0 };
- struct i2c_msg msg [] = { { .addr = 0x68, .flags = 0, .buf = b0, .len = 1 },
- { .addr = 0x68, .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 (i2c, msg, 2);
+ ret = i2c_transfer (state->i2c, msg, 2);
if (ret != 2)
dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n",
@@ -311,13 +121,13 @@ static u8 stv0299_readreg (struct i2c_adapter *i2c, u8 reg)
}
-static int stv0299_readregs (struct i2c_adapter *i2c, u8 reg1, u8 *b, u8 len)
+static int stv0299_readregs (struct stv0299_state* state, u8 reg1, u8 *b, u8 len)
{
int ret;
- struct i2c_msg msg [] = { { .addr = 0x68, .flags = 0, .buf = &reg1, .len = 1 },
- { .addr = 0x68, .flags = I2C_M_RD, .buf = b, .len = len } };
+ 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 (i2c, msg, 2);
+ ret = i2c_transfer (state->i2c, msg, 2);
if (ret != 2)
dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
@@ -326,373 +136,44 @@ static int stv0299_readregs (struct i2c_adapter *i2c, u8 reg1, u8 *b, u8 len)
}
-static int pll_write (struct i2c_adapter *i2c, u8 addr, u8 *data, int len)
-{
- int ret;
- struct i2c_msg msg = { .addr = addr, .buf = data, .len = len };
-
-
- stv0299_writereg(i2c, 0x05, 0xb5); /* enable i2c repeater on stv0299 */
-
- ret = i2c_transfer (i2c, &msg, 1);
-
- stv0299_writereg(i2c, 0x05, 0x35); /* disable i2c repeater on stv0299 */
-
- if (ret != 1)
- dprintk("%s: i/o error (ret == %i)\n", __FUNCTION__, ret);
-
- return (ret != 1) ? -1 : 0;
-}
-
-
-static int sl1935_set_tv_freq (struct i2c_adapter *i2c, u32 freq, int ftype)
-{
- u8 buf[4];
- u32 div;
-
- div = freq / 125;
-
- dprintk("%s : freq = %i, div = %i\n", __FUNCTION__, freq, div);
-
- buf[0] = (div >> 8) & 0x7f;
- buf[1] = div & 0xff;
- buf[2] = 0x84; // 0xC4
- buf[3] = 0x08;
-
- if (freq < 1500000) buf[3] |= 0x10;
-
- return pll_write (i2c, 0x61, buf, sizeof(buf));
-}
-
-/**
- * set up the downconverter frequency divisor for a
- * reference clock comparision frequency of 125 kHz.
- */
-static int tsa5059_set_tv_freq (struct i2c_adapter *i2c, u32 freq, int ftype, int srate)
-{
- u8 addr;
- u32 div;
- u8 buf[4];
- int divisor, regcode;
-
- dprintk ("%s: freq %i, ftype %i\n", __FUNCTION__, freq, ftype);
-
- if ((freq < 950000) || (freq > 2150000)) return -EINVAL;
-
- if (ftype == PHILIPS_SU1278_TSA_TT) {
- divisor = 500;
- regcode = 2;
- } else {
- divisor = 125;
- regcode = 4;
- }
-
- // setup frequency divisor
- div = (freq + (divisor - 1)) / divisor; // round correctly
- buf[0] = (div >> 8) & 0x7f;
- buf[1] = div & 0xff;
- buf[2] = 0x80 | ((div & 0x18000) >> 10) | regcode;
- buf[3] = 0;
-
- // tuner-specific settings
- switch(ftype) {
- case PHILIPS_SU1278_TSA:
- case PHILIPS_SU1278_TSA_TT:
- case PHILIPS_SU1278_TSA_TY:
- case PHILIPS_SU1278_TSA_CI:
- if (ftype == PHILIPS_SU1278_TSA_TY || ftype == PHILIPS_SU1278_TSA_CI)
- addr = 0x61;
- else
- addr = 0x60;
-
- buf[3] |= 0x20;
-
- if (srate < 4000000) buf[3] |= 1;
-
- if (freq < 1250000) buf[3] |= 0;
- else if (freq < 1550000) buf[3] |= 0x40;
- else if (freq < 2050000) buf[3] |= 0x80;
- else if (freq < 2150000) buf[3] |= 0xC0;
- break;
-
- case ALPS_BSRU6:
- addr = 0x61;
- buf[3] = 0xC4;
- if (freq > 1530000) buf[3] = 0xc0;
- break;
-
- default:
- return -EINVAL;
- }
-
- return pll_write (i2c, addr, buf, sizeof(buf));
-}
-
-
-#define MIN2(a,b) ((a) < (b) ? (a) : (b))
-#define MIN3(a,b,c) MIN2(MIN2(a,b),c)
-
-static int tua6100_set_tv_freq (struct i2c_adapter *i2c, u32 freq,
- int ftype, int srate)
-{
- u8 reg0 [2] = { 0x00, 0x00 };
- u8 reg1 [4] = { 0x01, 0x00, 0x00, 0x00 };
- u8 reg2 [3] = { 0x02, 0x00, 0x00 };
- int _fband;
- int first_ZF;
- int R, A, N, P, M;
- int err;
-
- first_ZF = (freq) / 1000;
-
- if (abs(MIN2(abs(first_ZF-1190),abs(first_ZF-1790))) <
- abs(MIN3(abs(first_ZF-1202),abs(first_ZF-1542),abs(first_ZF-1890))))
- _fband = 2;
- else
- _fband = 3;
-
- if (_fband == 2) {
- if (((first_ZF >= 950) && (first_ZF < 1350)) ||
- ((first_ZF >= 1430) && (first_ZF < 1950)))
- reg0[1] = 0x07;
- else if (((first_ZF >= 1350) && (first_ZF < 1430)) ||
- ((first_ZF >= 1950) && (first_ZF < 2150)))
- reg0[1] = 0x0B;
- }
-
- if(_fband == 3) {
- if (((first_ZF >= 950) && (first_ZF < 1350)) ||
- ((first_ZF >= 1455) && (first_ZF < 1950)))
- reg0[1] = 0x07;
- else if (((first_ZF >= 1350) && (first_ZF < 1420)) ||
- ((first_ZF >= 1950) && (first_ZF < 2150)))
- reg0[1] = 0x0B;
- else if ((first_ZF >= 1420) && (first_ZF < 1455))
- reg0[1] = 0x0F;
- }
-
- if (first_ZF > 1525)
- reg1[1] |= 0x80;
- else
- reg1[1] &= 0x7F;
-
- if (_fband == 2) {
- if (first_ZF > 1430) { /* 1430MHZ */
- reg1[1] &= 0xCF; /* N2 */
- reg2[1] &= 0xCF; /* R2 */
- reg2[1] |= 0x10;
- } else {
- reg1[1] &= 0xCF; /* N2 */
- reg1[1] |= 0x20;
- reg2[1] &= 0xCF; /* R2 */
- reg2[1] |= 0x10;
- }
- }
-
- if (_fband == 3) {
- if ((first_ZF >= 1455) &&
- (first_ZF < 1630)) {
- reg1[1] &= 0xCF; /* N2 */
- reg1[1] |= 0x20;
- reg2[1] &= 0xCF; /* R2 */
- } else {
- if (first_ZF < 1455) {
- reg1[1] &= 0xCF; /* N2 */
- reg1[1] |= 0x20;
- reg2[1] &= 0xCF; /* R2 */
- reg2[1] |= 0x10;
- } else {
- if (first_ZF >= 1630) {
- reg1[1] &= 0xCF; /* N2 */
- reg2[1] &= 0xCF; /* R2 */
- reg2[1] |= 0x10;
- }
- }
- }
- }
-
- /* set ports, enable P0 for symbol rates > 4Ms/s */
- if (srate >= 4000000)
- reg1[1] |= 0x0c;
- else
- reg1[1] |= 0x04;
-
- reg2[1] |= 0x0c;
-
- R = 64;
- A = 64;
- P = 64; //32
-
- M = (freq * R) / 4; /* in Mhz */
- N = (M - A * 1000) / (P * 1000);
-
- reg1[1] |= (N >> 9) & 0x03;
- reg1[2] = (N >> 1) & 0xff;
- reg1[3] = (N << 7) & 0x80;
-
- reg2[1] |= (R >> 8) & 0x03;
- reg2[2] = R & 0xFF; /* R */
-
- reg1[3] |= A & 0x7f; /* A */
-
- if (P == 64)
- reg1[1] |= 0x40; /* Prescaler 64/65 */
-
- reg0[1] |= 0x03;
-
- if ((err = pll_write(i2c, 0x60, reg0, sizeof(reg0))))
- return err;
-
- if ((err = pll_write(i2c, 0x60, reg1, sizeof(reg1))))
- return err;
-
- if ((err = pll_write(i2c, 0x60, reg2, sizeof(reg2))))
- return err;
-
- return 0;
-}
-
-
-static int pll_set_tv_freq (struct i2c_adapter *i2c, u32 freq, int ftype, int srate)
-{
- switch(ftype) {
- case SAMSUNG_TBMU24112IMB:
- return sl1935_set_tv_freq(i2c, freq, ftype);
-
- case LG_TDQF_S001F:
- return sl1935_set_tv_freq(i2c, freq, ftype);
-
- case PHILIPS_SU1278_TUA:
- return tua6100_set_tv_freq(i2c, freq, ftype, srate);
-
- default:
- return tsa5059_set_tv_freq(i2c, freq, ftype, srate);
- }
-}
-
-#if 0
-static int tsa5059_read_status (struct i2c_adapter *i2c)
-{
- int ret;
- u8 rpt1 [] = { 0x05, 0xb5 };
- u8 stat [] = { 0 };
-
- struct i2c_msg msg [] = {{ .addr = 0x68, .flags = 0, .buf = rpt1, .len = 2 },
- { .addr = 0x60, .flags = I2C_M_RD, .buf = stat, .len = 1 }};
-
- dprintk ("%s\n", __FUNCTION__);
-
- ret = i2c_transfer (i2c, msg, 2);
-
- if (ret != 2)
- dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
-
- return stat[0];
-}
-#endif
-
-
-static int stv0299_init (struct i2c_adapter *i2c, int ftype)
-{
- int i;
-
- dprintk("stv0299: init chip\n");
-
- switch(ftype) {
- case SAMSUNG_TBMU24112IMB:
- dprintk("%s: init stv0299 chip for Samsung TBMU24112IMB\n", __FUNCTION__);
-
- for (i=0; i<sizeof(init_tab_samsung); i+=2)
- {
- dprintk("%s: reg == 0x%02x, val == 0x%02x\n", __FUNCTION__, init_tab_samsung[i], init_tab_samsung[i+1]);
-
- stv0299_writereg (i2c, init_tab_samsung[i], init_tab_samsung[i+1]);
- }
- break;
-
- case PHILIPS_SU1278_TSA_TT:
- for (i=0; i<sizeof(init_tab_su1278_tsa_tt); i+=2) {
- stv0299_writereg (i2c, init_tab_su1278_tsa_tt[i], init_tab_su1278_tsa_tt[i+1]);
- }
- break;
-
- default:
- stv0299_writereg (i2c, 0x01, 0x15);
- stv0299_writereg (i2c, 0x02, ftype == PHILIPS_SU1278_TUA ? 0x00 : 0x30);
- stv0299_writereg (i2c, 0x03, 0x00);
-
- for (i=0; i<sizeof(init_tab); i+=2)
- stv0299_writereg (i2c, init_tab[i], init_tab[i+1]);
-
- /* AGC1 reference register setup */
- if (ftype == PHILIPS_SU1278_TSA || ftype == PHILIPS_SU1278_TSA_TY || ftype == PHILIPS_SU1278_TSA_CI)
- stv0299_writereg (i2c, 0x0f, 0x92); /* Iagc = Inverse, m1 = 18 */
- else if (ftype == PHILIPS_SU1278_TUA)
- stv0299_writereg (i2c, 0x0f, 0x94); /* Iagc = Inverse, m1 = 20 */
- else
- stv0299_writereg (i2c, 0x0f, 0x52); /* Iagc = Normal, m1 = 18 */
- break;
- }
-
- switch(stv0299_status) {
- case STATUS_BER:
- stv0299_writereg(i2c, 0x34, 0x93);
- break;
-
- case STATUS_UCBLOCKS:
- stv0299_writereg(i2c, 0x34, 0xB3);
- break;
- }
-
- return 0;
-}
-
-
-static int stv0299_set_FEC (struct i2c_adapter *i2c, fe_code_rate_t fec)
+static int stv0299_set_FEC (struct stv0299_state* state, fe_code_rate_t fec)
{
dprintk ("%s\n", __FUNCTION__);
switch (fec) {
case FEC_AUTO:
{
- dprintk ("%s : FEC_AUTO\n", __FUNCTION__);
- return stv0299_writereg (i2c, 0x31, 0x1f);
+ return stv0299_writeregI (state, 0x31, 0x1f);
}
case FEC_1_2:
{
- dprintk ("%s : FEC_1_2\n", __FUNCTION__);
- return stv0299_writereg (i2c, 0x31, 0x01);
+ return stv0299_writeregI (state, 0x31, 0x01);
}
case FEC_2_3:
{
- dprintk ("%s : FEC_2_3\n", __FUNCTION__);
- return stv0299_writereg (i2c, 0x31, 0x02);
+ return stv0299_writeregI (state, 0x31, 0x02);
}
case FEC_3_4:
{
- dprintk ("%s : FEC_3_4\n", __FUNCTION__);
- return stv0299_writereg (i2c, 0x31, 0x04);
+ return stv0299_writeregI (state, 0x31, 0x04);
}
case FEC_5_6:
{
- dprintk ("%s : FEC_5_6\n", __FUNCTION__);
- return stv0299_writereg (i2c, 0x31, 0x08);
+ return stv0299_writeregI (state, 0x31, 0x08);
}
case FEC_7_8:
{
- dprintk ("%s : FEC_7_8\n", __FUNCTION__);
- return stv0299_writereg (i2c, 0x31, 0x10);
+ return stv0299_writeregI (state, 0x31, 0x10);
}
default:
{
- dprintk ("%s : FEC invalid\n", __FUNCTION__);
return -EINVAL;
}
}
}
-static fe_code_rate_t stv0299_get_fec (struct i2c_adapter *i2c)
+static fe_code_rate_t stv0299_get_fec (struct stv0299_state* state)
{
static fe_code_rate_t fec_tab [] = { FEC_2_3, FEC_3_4, FEC_5_6,
FEC_7_8, FEC_1_2 };
@@ -700,7 +181,7 @@ static fe_code_rate_t stv0299_get_fec (struct i2c_adapter *i2c)
dprintk ("%s\n", __FUNCTION__);
- index = stv0299_readreg (i2c, 0x1b);
+ index = stv0299_readreg (state, 0x1b);
index &= 0x7;
if (index > 4)
@@ -710,13 +191,13 @@ static fe_code_rate_t stv0299_get_fec (struct i2c_adapter *i2c)
}
-static int stv0299_wait_diseqc_fifo (struct i2c_adapter *i2c, int timeout)
+static int stv0299_wait_diseqc_fifo (struct stv0299_state* state, int timeout)
{
unsigned long start = jiffies;
dprintk ("%s\n", __FUNCTION__);
- while (stv0299_readreg(i2c, 0x0a) & 1) {
+ while (stv0299_readreg(state, 0x0a) & 1) {
if (jiffies - start > timeout) {
dprintk ("%s: timeout!!\n", __FUNCTION__);
return -ETIMEDOUT;
@@ -728,13 +209,13 @@ static int stv0299_wait_diseqc_fifo (struct i2c_adapter *i2c, int timeout)
}
-static int stv0299_wait_diseqc_idle (struct i2c_adapter *i2c, int timeout)
+static int stv0299_wait_diseqc_idle (struct stv0299_state* state, int timeout)
{
unsigned long start = jiffies;
dprintk ("%s\n", __FUNCTION__);
- while ((stv0299_readreg(i2c, 0x0a) & 3) != 2 ) {
+ while ((stv0299_readreg(state, 0x0a) & 3) != 2 ) {
if (jiffies - start > timeout) {
dprintk ("%s: timeout!!\n", __FUNCTION__);
return -ETIMEDOUT;
@@ -745,101 +226,156 @@ static int stv0299_wait_diseqc_idle (struct i2c_adapter *i2c, int timeout)
return 0;
}
+static int stv0299_set_symbolrate (struct dvb_frontend* fe, u32 srate)
+{
+ struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
+ u64 big = srate;
+ u32 ratio;
+
+ // check rate is within limits
+ if ((srate < 1000000) || (srate > 45000000)) return -EINVAL;
-static int stv0299_send_diseqc_msg (struct i2c_adapter *i2c,
- struct dvb_diseqc_master_cmd *m)
+ // calculate value to program
+ big = big << 20;
+ big += (state->config->mclk-1); // round correctly
+ do_div(big, state->config->mclk);
+ ratio = big << 4;
+
+ return state->config->set_symbol_rate(fe, srate, ratio);
+}
+
+
+static int stv0299_get_symbolrate (struct stv0299_state* state)
{
+ u32 Mclk = state->config->mclk / 4096L;
+ u32 srate;
+ s32 offset;
+ u8 sfr[3];
+ s8 rtf;
+
+ dprintk ("%s\n", __FUNCTION__);
+
+ stv0299_readregs (state, 0x1f, sfr, 3);
+ stv0299_readregs (state, 0x1a, &rtf, 1);
+
+ srate = (sfr[0] << 8) | sfr[1];
+ srate *= Mclk;
+ srate /= 16;
+ srate += (sfr[2] >> 4) * Mclk / 256;
+ offset = (s32) rtf * (srate / 4096L);
+ offset /= 128;
+
+ dprintk ("%s : srate = %i\n", __FUNCTION__, srate);
+ dprintk ("%s : ofset = %i\n", __FUNCTION__, offset);
+
+ srate += offset;
+
+ srate += 1000;
+ srate /= 2000;
+ srate *= 2000;
+
+ return srate;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+static int stv0299_send_diseqc_msg (struct dvb_frontend* fe,
+ struct dvb_diseqc_master_cmd *m)
+{
+ struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
u8 val;
int i;
dprintk ("%s\n", __FUNCTION__);
- if (stv0299_wait_diseqc_idle (i2c, 100) < 0)
+ if (stv0299_wait_diseqc_idle (state, 100) < 0)
return -ETIMEDOUT;
- val = stv0299_readreg (i2c, 0x08);
+ val = stv0299_readreg (state, 0x08);
- if (stv0299_writereg (i2c, 0x08, (val & ~0x7) | 0x6)) /* DiSEqC mode */
+ if (stv0299_writeregI (state, 0x08, (val & ~0x7) | 0x6)) /* DiSEqC mode */
return -EREMOTEIO;
for (i=0; i<m->msg_len; i++) {
- if (stv0299_wait_diseqc_fifo (i2c, 100) < 0)
+ if (stv0299_wait_diseqc_fifo (state, 100) < 0)
return -ETIMEDOUT;
- if (stv0299_writereg (i2c, 0x09, m->msg[i]))
+ if (stv0299_writeregI (state, 0x09, m->msg[i]))
return -EREMOTEIO;
}
- if (stv0299_wait_diseqc_idle (i2c, 100) < 0)
+ if (stv0299_wait_diseqc_idle (state, 100) < 0)
return -ETIMEDOUT;
return 0;
}
-static int stv0299_send_diseqc_burst (struct i2c_adapter *i2c, fe_sec_mini_cmd_t burst)
+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;
u8 val;
dprintk ("%s\n", __FUNCTION__);
- if (stv0299_wait_diseqc_idle (i2c, 100) < 0)
+ if (stv0299_wait_diseqc_idle (state, 100) < 0)
return -ETIMEDOUT;
- val = stv0299_readreg (i2c, 0x08);
+ val = stv0299_readreg (state, 0x08);
- if (stv0299_writereg (i2c, 0x08, (val & ~0x7) | 0x2)) /* burst mode */
+ if (stv0299_writeregI (state, 0x08, (val & ~0x7) | 0x2)) /* burst mode */
return -EREMOTEIO;
- if (stv0299_writereg (i2c, 0x09, burst == SEC_MINI_A ? 0x00 : 0xff))
+ if (stv0299_writeregI (state, 0x09, burst == SEC_MINI_A ? 0x00 : 0xff))
return -EREMOTEIO;
- if (stv0299_wait_diseqc_idle (i2c, 100) < 0)
+ if (stv0299_wait_diseqc_idle (state, 100) < 0)
return -ETIMEDOUT;
- if (stv0299_writereg (i2c, 0x08, val))
+ if (stv0299_writeregI (state, 0x08, val))
return -EREMOTEIO;
return 0;
}
-static int stv0299_set_tone (struct i2c_adapter *i2c, fe_sec_tone_mode_t tone)
+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;
u8 val;
- dprintk("%s: %s\n", __FUNCTION__,
- tone == SEC_TONE_ON ? "SEC_TONE_ON" :
- tone == SEC_TONE_OFF ? "SEC_TONE_OFF" : "??");
-
- if (stv0299_wait_diseqc_idle (i2c, 100) < 0)
+ if (stv0299_wait_diseqc_idle (state, 100) < 0)
return -ETIMEDOUT;
- val = stv0299_readreg (i2c, 0x08);
+ val = stv0299_readreg (state, 0x08);
switch (tone) {
case SEC_TONE_ON:
- {
- dprintk("%s: TONE_ON\n", __FUNCTION__);
- return stv0299_writereg (i2c, 0x08, val | 0x3);
- }
+ return stv0299_writeregI (state, 0x08, val | 0x3);
+
case SEC_TONE_OFF:
- {
- dprintk("%s: TONE_OFF\n", __FUNCTION__);
- return stv0299_writereg (i2c, 0x08, (val & ~0x3) | 0x02);
- }
+ return stv0299_writeregI (state, 0x08, (val & ~0x3) | 0x02);
+
default:
- {
- dprintk("%s: TONE INVALID\n", __FUNCTION__);
return -EINVAL;
}
- };
}
-static int stv0299_set_voltage (struct i2c_adapter *i2c, fe_sec_voltage_t voltage,
- int tuner_type)
+static int stv0299_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage)
{
+ struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
u8 reg0x08;
u8 reg0x0c;
@@ -847,46 +383,37 @@ static int stv0299_set_voltage (struct i2c_adapter *i2c, fe_sec_voltage_t voltag
voltage == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" :
voltage == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??");
- reg0x08 = stv0299_readreg (i2c, 0x08);
- reg0x0c = stv0299_readreg (i2c, 0x0c);
-
+ reg0x08 = stv0299_readreg (state, 0x08);
+ reg0x0c = stv0299_readreg (state, 0x0c);
+
/**
* H/V switching over OP0, OP1 and OP2 are LNB power enable bits
*/
reg0x0c &= 0x0f;
if (voltage == SEC_VOLTAGE_OFF) {
- stv0299_writereg (i2c, 0x0c, 0x00); /* LNB power off! */
- return stv0299_writereg (i2c, 0x08, 0x00); /* LNB power off! */
- }
-
- if (tuner_type == PHILIPS_SU1278_TSA_CI)
- {
- stv0299_writereg (i2c, 0x08, reg0x08 & 0xBF); // switch LNB power on OP2/LOCK pin off
- }
- else
- {
- stv0299_writereg (i2c, 0x08, reg0x08 | 0x40);
+ 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) {
case SEC_VOLTAGE_13:
- if (tuner_type == PHILIPS_SU1278_TSA_TY || tuner_type == PHILIPS_SU1278_TSA_CI)
- return stv0299_writereg (i2c, 0x0c, reg0x0c | 0x10);
- else
- return stv0299_writereg (i2c, 0x0c, reg0x0c | 0x40);
+ if (state->config->volt13_op0_op1 == STV0299_VOLT13_OP0) reg0x0c |= 0x10;
+ else reg0x0c |= 0x40;
- case SEC_VOLTAGE_18:
- return stv0299_writereg (i2c, 0x0c, reg0x0c | 0x50);
+ return stv0299_writeregI(state, 0x0c, reg0x0c);
+ case SEC_VOLTAGE_18:
+ return stv0299_writeregI(state, 0x0c, reg0x0c | 0x50);
default:
return -EINVAL;
};
}
-static int stv0299_send_legacy_dish_cmd(struct i2c_adapter *i2c, u32 cmd,
- int tuner_type)
+static int stv0299_send_legacy_dish_cmd(struct dvb_frontend* fe, u32 cmd)
{
u8 last = 1;
int i;
@@ -901,15 +428,14 @@ static int stv0299_send_legacy_dish_cmd(struct i2c_adapter *i2c, u32 cmd,
cmd = cmd << 1;
dprintk("%s switch command: 0x%04x\n",__FUNCTION__, cmd);
- stv0299_set_voltage(i2c,SEC_VOLTAGE_18,tuner_type);
+ stv0299_set_voltage(fe,SEC_VOLTAGE_18);
msleep(32);
for (i=0; i<9; i++) {
if((cmd & 0x01) != last) {
- stv0299_set_voltage(i2c,
+ stv0299_set_voltage(fe,
last ? SEC_VOLTAGE_13 :
- SEC_VOLTAGE_18,
- tuner_type);
+ SEC_VOLTAGE_18);
last = (last) ? 0 : 1;
}
@@ -922,598 +448,316 @@ static int stv0299_send_legacy_dish_cmd(struct i2c_adapter *i2c, u32 cmd,
return 0;
}
-static int stv0299_set_symbolrate (struct i2c_adapter *i2c, u32 srate, int tuner_type)
+
+static int stv0299_init (struct dvb_frontend* fe)
{
- u64 big = srate;
- u32 ratio;
- u8 aclk = 0;
- u8 bclk = 0;
- u8 m1;
- int Mclk = M_CLK;
-
- // check rate is within limits
- if ((srate < 1000000) || (srate > 45000000)) return -EINVAL;
-
- // calculate value to program
- if (tuner_type == PHILIPS_SU1278_TSA_TT) Mclk = M_CLK_SU1278_TSA_TT;
- big = big << 20;
- big += (Mclk-1); // round correctly
- do_div(big, Mclk);
- ratio = big << 4;
-
- // program registers
- switch(tuner_type) {
- case PHILIPS_SU1278_TSA_TT:
- stv0299_writereg (i2c, 0x0e, 0x44);
- if (srate >= 10000000) {
- stv0299_writereg (i2c, 0x13, 0x97);
- stv0299_writereg (i2c, 0x14, 0x95);
- stv0299_writereg (i2c, 0x15, 0xc9);
- stv0299_writereg (i2c, 0x17, 0x8c);
- stv0299_writereg (i2c, 0x1a, 0xfe);
- stv0299_writereg (i2c, 0x1c, 0x7f);
- stv0299_writereg (i2c, 0x2d, 0x09);
- } else {
- stv0299_writereg (i2c, 0x13, 0x99);
- stv0299_writereg (i2c, 0x14, 0x8d);
- stv0299_writereg (i2c, 0x15, 0xce);
- stv0299_writereg (i2c, 0x17, 0x43);
- stv0299_writereg (i2c, 0x1a, 0x1d);
- stv0299_writereg (i2c, 0x1c, 0x12);
- stv0299_writereg (i2c, 0x2d, 0x05);
- }
+ struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
+ int i;
- stv0299_writereg (i2c, 0x0e, 0x23);
- stv0299_writereg (i2c, 0x0f, 0x94);
- stv0299_writereg (i2c, 0x10, 0x39);
- stv0299_writereg (i2c, 0x15, 0xc9);
-
- stv0299_writereg (i2c, 0x1f, (ratio >> 16) & 0xff);
- stv0299_writereg (i2c, 0x20, (ratio >> 8) & 0xff);
- stv0299_writereg (i2c, 0x21, (ratio ) & 0xf0);
- break;
-
- case PHILIPS_SU1278_TSA_TY:
- case PHILIPS_SU1278_TSA_CI:
- case PHILIPS_SU1278_TSA:
- aclk = 0xb5;
- if (srate < 2000000) bclk = 0x86;
- else if (srate < 5000000) bclk = 0x89;
- else if (srate < 15000000) bclk = 0x8f;
- else if (srate < 45000000) bclk = 0x95;
-
- m1 = 0x14;
- if (srate < 4000000) m1 = 0x10;
-
- stv0299_writereg (i2c, 0x13, aclk);
- stv0299_writereg (i2c, 0x14, bclk);
- stv0299_writereg (i2c, 0x1f, (ratio >> 16) & 0xff);
- stv0299_writereg (i2c, 0x20, (ratio >> 8) & 0xff);
- stv0299_writereg (i2c, 0x21, (ratio ) & 0xf0);
- stv0299_writereg (i2c, 0x0f, (stv0299_readreg(i2c, 0x0f) & 0xc0) | m1);
- break;
-
- case ALPS_BSRU6:
- default:
- if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; }
- else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; }
- else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; }
- else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; }
- else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; }
- else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; }
-
- stv0299_writereg (i2c, 0x13, aclk);
- stv0299_writereg (i2c, 0x14, bclk);
- stv0299_writereg (i2c, 0x1f, (ratio >> 16) & 0xff);
- stv0299_writereg (i2c, 0x20, (ratio >> 8) & 0xff);
- stv0299_writereg (i2c, 0x21, (ratio ) & 0xf0);
- break;
+ dprintk("stv0299: init chip\n");
+
+ for (i=0; state->config->inittab[i] != 0xff && state->config->inittab[i+1] != 0xff; i+=2)
+ stv0299_writeregI(state, state->config->inittab[i], state->config->inittab[i+1]);
+
+ if (state->config->pll_init) {
+ stv0299_writeregI(state, 0x05, 0xb5); /* enable i2c repeater on stv0299 */
+ state->config->pll_init(fe);
+ stv0299_writeregI(state, 0x05, 0x35); /* disable i2c repeater on stv0299 */
}
-
return 0;
}
-static int stv0299_get_symbolrate (struct i2c_adapter *i2c, int tuner_type)
+static int stv0299_read_status(struct dvb_frontend* fe, fe_status_t* status)
{
- u32 Mclk = M_CLK / 4096L;
- u32 srate;
- s32 offset;
- u8 sfr[3];
- s8 rtf;
+ struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
- dprintk ("%s\n", __FUNCTION__);
+ u8 signal = 0xff - stv0299_readreg (state, 0x18);
+ u8 sync = stv0299_readreg (state, 0x1b);
- if (tuner_type == PHILIPS_SU1278_TSA_TT) Mclk = M_CLK_SU1278_TSA_TT / 4096L;
-
- stv0299_readregs (i2c, 0x1f, sfr, 3);
- stv0299_readregs (i2c, 0x1a, &rtf, 1);
+ dprintk ("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __FUNCTION__, sync);
+ *status = 0;
- srate = (sfr[0] << 8) | sfr[1];
- srate *= Mclk;
- srate /= 16;
- srate += (sfr[2] >> 4) * Mclk / 256;
- offset = (s32) rtf * (srate / 4096L);
- offset /= 128;
+ if (signal > 10)
+ *status |= FE_HAS_SIGNAL;
- dprintk ("%s : srate = %i\n", __FUNCTION__, srate);
- dprintk ("%s : ofset = %i\n", __FUNCTION__, offset);
+ if (sync & 0x80)
+ *status |= FE_HAS_CARRIER;
- srate += offset;
+ if (sync & 0x10)
+ *status |= FE_HAS_VITERBI;
- srate += 1000;
- srate /= 2000;
- srate *= 2000;
+ if (sync & 0x08)
+ *status |= FE_HAS_SYNC;
- return srate;
+ if ((sync & 0x98) == 0x98)
+ *status |= FE_HAS_LOCK;
+
+ return 0;
}
-static int uni0299_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
+static int stv0299_read_ber(struct dvb_frontend* fe, u32* ber)
{
- struct stv0299_state *state = (struct stv0299_state *) fe->data;
- struct i2c_adapter *i2c = state->i2c;
-
- dprintk ("%s\n", __FUNCTION__);
+ struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
- switch (cmd) {
- case FE_GET_INFO:
- {
- struct dvb_frontend_info* tmp = (struct dvb_frontend_info*) arg;
- memcpy (arg, &uni0299_info, sizeof(struct dvb_frontend_info));
-
- if (state->tuner_type == PHILIPS_SU1278_TSA_TT) {
- tmp->frequency_tolerance = M_CLK_SU1278_TSA_TT / 2000;
- }
- break;
- }
-
- case FE_READ_STATUS:
- {
- fe_status_t *status = (fe_status_t *) arg;
- u8 signal = 0xff - stv0299_readreg (i2c, 0x18);
- u8 sync = stv0299_readreg (i2c, 0x1b);
+ if (state->errmode != STATUS_BER) return 0;
+ *ber = (stv0299_readreg (state, 0x1d) << 8) | stv0299_readreg (state, 0x1e);
- dprintk ("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __FUNCTION__, sync);
-
- *status = 0;
-
- if (signal > 10)
- *status |= FE_HAS_SIGNAL;
-
- if (sync & 0x80)
- *status |= FE_HAS_CARRIER;
-
- if (sync & 0x10)
- *status |= FE_HAS_VITERBI;
-
- if (sync & 0x08)
- *status |= FE_HAS_SYNC;
-
- if ((sync & 0x98) == 0x98)
- *status |= FE_HAS_LOCK;
-
- break;
- }
-
- case FE_READ_BER:
- if (stv0299_status == STATUS_BER) {
- *((u32*) arg) = (stv0299_readreg (i2c, 0x1d) << 8)
- | stv0299_readreg (i2c, 0x1e);
- } else {
- *((u32*) arg) = 0;
- }
- break;
-
- case FE_READ_SIGNAL_STRENGTH:
- {
- s32 signal = 0xffff - ((stv0299_readreg (i2c, 0x18) << 8)
- | stv0299_readreg (i2c, 0x19));
-
- dprintk ("%s : FE_READ_SIGNAL_STRENGTH : AGC2I: 0x%02x%02x, signal=0x%04x\n", __FUNCTION__,
- stv0299_readreg (i2c, 0x18),
- stv0299_readreg (i2c, 0x19), (int) signal);
-
- signal = signal * 5 / 4;
- *((u16*) arg) = (signal > 0xffff) ? 0xffff :
- (signal < 0) ? 0 : signal;
- break;
- }
- case FE_READ_SNR:
- {
- s32 snr = 0xffff - ((stv0299_readreg (i2c, 0x24) << 8)
- | stv0299_readreg (i2c, 0x25));
- snr = 3 * (snr - 0xa100);
- *((u16*) arg) = (snr > 0xffff) ? 0xffff :
- (snr < 0) ? 0 : snr;
- break;
- }
- case FE_READ_UNCORRECTED_BLOCKS:
- if (stv0299_status == STATUS_UCBLOCKS) {
- *((u32*) arg) = (stv0299_readreg (i2c, 0x1d) << 8)
- | stv0299_readreg (i2c, 0x1e);
- } else {
- *((u32*) arg) = 0;
- }
- break;
-
- case FE_SET_FRONTEND:
- {
- struct dvb_frontend_parameters *p = arg;
- int invval = 0;
-
- 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;
- }
- if (state->tuner_type == ALPS_BSRU6) invval = (~invval) & 1;
- stv0299_writereg(i2c, 0x0c, (stv0299_readreg(i2c, 0x0c) & 0xfe) | invval);
-
- switch(state->tuner_type) {
- case PHILIPS_SU1278_TSA_TT:
- {
- /* 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) / (M_CLK_SU1278_TSA_TT / 1000);
-
- // zap the derotator registers first
- stv0299_writereg (i2c, 0x22, 0x00);
- stv0299_writereg (i2c, 0x23, 0x00);
-
- // now set them as we want
- stv0299_writereg (i2c, 0x22, Drot_freq >> 8);
- stv0299_writereg (i2c, 0x23, Drot_freq);
- } else {
- /* A "normal" tune is requested */
- pll_set_tv_freq (i2c, p->frequency, state->tuner_type, p->u.qpsk.symbol_rate);
- stv0299_writereg (i2c, 0x32, 0x80);
- stv0299_writereg (i2c, 0x22, 0x00);
- stv0299_writereg (i2c, 0x23, 0x00);
- stv0299_writereg (i2c, 0x32, 0x19);
- stv0299_set_symbolrate (i2c, p->u.qpsk.symbol_rate, state->tuner_type);
- stv0299_set_FEC (i2c, p->u.qpsk.fec_inner);
- }
- break;
- }
-
- default:
- pll_set_tv_freq (i2c, p->frequency, state->tuner_type, p->u.qpsk.symbol_rate);
- stv0299_set_FEC (i2c, p->u.qpsk.fec_inner);
- stv0299_set_symbolrate (i2c, p->u.qpsk.symbol_rate, state->tuner_type);
- stv0299_writereg (i2c, 0x22, 0x00);
- stv0299_writereg (i2c, 0x23, 0x00);
- stv0299_readreg (i2c, 0x23);
- stv0299_writereg (i2c, 0x12, 0xb9);
- break;
- }
-
- state->tuner_frequency = p->frequency;
- state->fec_inner = p->u.qpsk.fec_inner;
- state->symbol_rate = p->u.qpsk.symbol_rate;
- break;
- }
-
- case FE_GET_FRONTEND:
- {
- struct dvb_frontend_parameters *p = arg;
- s32 derot_freq;
- int Mclk = M_CLK;
- int invval;
-
- if (state->tuner_type == PHILIPS_SU1278_TSA_TT) Mclk = M_CLK_SU1278_TSA_TT;
-
- derot_freq = (s32)(s16) ((stv0299_readreg (i2c, 0x22) << 8)
- | stv0299_readreg (i2c, 0x23));
-
- derot_freq *= (Mclk >> 16);
- derot_freq += 500;
- derot_freq /= 1000;
-
- p->frequency += derot_freq;
+ return 0;
+}
- invval = stv0299_readreg (i2c, 0x0c) & 1;
- if (state->tuner_type == ALPS_BSRU6) invval = (~invval) & 1;
- p->inversion = invval ? INVERSION_ON : INVERSION_OFF;
+static int stv0299_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+ struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
- p->u.qpsk.fec_inner = stv0299_get_fec (i2c);
- p->u.qpsk.symbol_rate = stv0299_get_symbolrate (i2c, state->tuner_type);
- break;
- }
+ s32 signal = 0xffff - ((stv0299_readreg (state, 0x18) << 8)
+ | stv0299_readreg (state, 0x19));
- case FE_SLEEP:
- stv0299_writereg (i2c, 0x0c, 0x00); /* LNB power off! */
- stv0299_writereg (i2c, 0x08, 0x00); /* LNB power off! */
- stv0299_writereg (i2c, 0x02, 0x80);
- state->initialised = 0;
- break;
-
- case FE_INIT:
- switch(state->tuner_type) {
- case PHILIPS_SU1278_TSA_TT:
- state->tuner_frequency = 0;
- if (!state->initialised) {
- state->initialised = 1;
- return stv0299_init (i2c, state->tuner_type);
- }
- break;
-
- default:
- return stv0299_init (i2c, state->tuner_type);
- }
- break;
+ 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);
- case FE_DISEQC_SEND_MASTER_CMD:
- return stv0299_send_diseqc_msg (i2c, arg);
+ signal = signal * 5 / 4;
+ *strength = (signal > 0xffff) ? 0xffff : (signal < 0) ? 0 : signal;
- case FE_DISEQC_SEND_BURST:
- return stv0299_send_diseqc_burst (i2c, (fe_sec_mini_cmd_t) arg);
+ return 0;
+}
- case FE_SET_TONE:
- return stv0299_set_tone (i2c, (fe_sec_tone_mode_t) arg);
+static int stv0299_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+ struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
- case FE_SET_VOLTAGE:
- return stv0299_set_voltage (i2c, (fe_sec_voltage_t) arg,
- state->tuner_type);
+ s32 xsnr = 0xffff - ((stv0299_readreg (state, 0x24) << 8)
+ | stv0299_readreg (state, 0x25));
+ xsnr = 3 * (xsnr - 0xa100);
+ *snr = (xsnr > 0xffff) ? 0xffff : (xsnr < 0) ? 0 : xsnr;
- case FE_DISHNETWORK_SEND_LEGACY_CMD:
- return stv0299_send_legacy_dish_cmd (i2c, (u32) arg,
- state->tuner_type);
+ return 0;
+}
- case FE_GET_TUNE_SETTINGS:
- {
- struct dvb_frontend_tune_settings* fesettings = (struct dvb_frontend_tune_settings*) arg;
-
- switch(state->tuner_type) {
- case PHILIPS_SU1278_TSA_TT:
- fesettings->min_delay_ms = 50;
- 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;
- }
- break;
-
- default:
- fesettings->min_delay_ms = 100;
- 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;
- }
- break;
- }
+static int stv0299_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+ struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
- return 0;
- }
-
- default:
- return -EOPNOTSUPP;
- };
+ if (state->errmode != STATUS_UCBLOCKS) *ucblocks = 0;
+ else *ucblocks = (stv0299_readreg (state, 0x1d) << 8) | stv0299_readreg (state, 0x1e);
return 0;
}
-static long probe_tuner (struct i2c_adapter *adapter)
+static int stv0299_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters * p)
{
- struct i2c_adapter *i2c = adapter; /* superfluous */
-
- /* read the status register of TSA5059 */
- u8 rpt[] = { 0x05, 0xb5 };
- u8 stat [] = { 0 };
- u8 tda6100_buf [] = { 0, 0 };
- int ret;
- struct i2c_msg msg1 [] = {{ .addr = 0x68, .flags = 0, .buf = rpt, len: 2 },
- { .addr = 0x60, .flags = I2C_M_RD, .buf = stat, .len = 1 }};
- struct i2c_msg msg2 [] = {{ .addr = 0x68, .flags = 0, .buf = rpt, len: 2 },
- { .addr = 0x61, .flags = I2C_M_RD, .buf = stat, .len = 1 }};
- struct i2c_msg msg3 [] = {{ .addr = 0x68, .flags = 0, .buf = rpt, len: 2 },
- { .addr = 0x60, .flags = 0, .buf = tda6100_buf, .len = 2 }};
+ struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
+ int invval = 0;
- stv0299_writereg (i2c, 0x01, 0x15);
- stv0299_writereg (i2c, 0x02, 0x30);
- stv0299_writereg (i2c, 0x03, 0x00);
+ 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;
+ }
+ if (state->config->invert) invval = (~invval) & 1;
+ stv0299_writeregI(state, 0x0c, (stv0299_readreg(state, 0x0c) & 0xfe) | invval);
- printk("stv0299: try to attach to %s\n", adapter->name);
+ 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 (!strcmp(adapter->name, "SkyStar2")) {
- printk ("stv0299: setup for tuner Samsung TBMU24112IMB\n");
- return SAMSUNG_TBMU24112IMB;
- }
+ 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);
- if ((ret = i2c_transfer(i2c, msg1, 2)) == 2) {
- if ( strcmp(adapter->name, "TT-Budget/WinTV-NOVA-CI PCI") == 0 ) {
- // technotrend cards require non-datasheet settings
- printk ("stv0299: setup for tuner SU1278 (TSA5059 synth) on TechnoTrend hardware\n");
- return PHILIPS_SU1278_TSA_TT;
- } else {
- // fall back to datasheet-recommended settings
- printk ("stv0299: setup for tuner SU1278 (TSA5059 synth)\n");
- return PHILIPS_SU1278_TSA;
- }
- }
+ // zap the derotator registers first
+ stv0299_writeregI(state, 0x22, 0x00);
+ stv0299_writeregI(state, 0x23, 0x00);
- if ((ret = i2c_transfer(i2c, msg2, 2)) == 2) {
- if ( strcmp(adapter->name, "KNC1 DVB-S") == 0 )
- {
- // Typhoon cards have unusual wiring.
- printk ("stv0299: setup for tuner SU1278 (TSA5059 synth) on Typhoon hardware\n");
- return PHILIPS_SU1278_TSA_TY;
- }
- else if ( strcmp(adapter->name, "TerraTec Cinergy 1200 DVB-S") == 0 )
- {
- // Cinergy cards have unusual wiring.
- printk ("%s: setup for tuner SU1278 (TSA5059 synth) on"
- " TerraTec hardware\n", __FILE__);
- return PHILIPS_SU1278_TSA_CI;
- }
- //else if ((stat[0] & 0x3f) == 0) {
- else if (0) {
- printk ("stv0299: setup for tuner TDQF-S001F\n");
- return LG_TDQF_S001F;
+ // now set them as we want
+ stv0299_writeregI(state, 0x22, Drot_freq >> 8);
+ stv0299_writeregI(state, 0x23, Drot_freq);
} else {
- printk ("stv0299: setup for tuner BSRU6, TDQB-S00x\n");
- return ALPS_BSRU6;
+ /* 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 */
+
+ stv0299_writeregI(state, 0x32, 0x80);
+ stv0299_writeregI(state, 0x22, 0x00);
+ stv0299_writeregI(state, 0x23, 0x00);
+ stv0299_writeregI(state, 0x32, 0x19);
+ stv0299_set_symbolrate (fe, p->u.qpsk.symbol_rate);
+ stv0299_set_FEC (state, p->u.qpsk.fec_inner);
}
- }
-
- /**
- * setup i2c timing for SU1278...
- */
- stv0299_writereg (i2c, 0x02, 0x00);
+ } else {
+ 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 */
- if ((ret = i2c_transfer(i2c, msg3, 2)) == 2) {
- printk ("stv0299: setup for tuner Philips SU1278 (TUA6100 synth)\n");
- return PHILIPS_SU1278_TUA;
+ stv0299_set_FEC (state, p->u.qpsk.fec_inner);
+ stv0299_set_symbolrate (fe, p->u.qpsk.symbol_rate);
+ stv0299_writeregI(state, 0x22, 0x00);
+ stv0299_writeregI(state, 0x23, 0x00);
+ stv0299_readreg (state, 0x23);
+ stv0299_writeregI(state, 0x12, 0xb9);
}
- printk ("stv0299: unknown PLL synthesizer (ret == %i), please report to <linuxdvb@linuxtv.org>!!\n", ret);
+ state->tuner_frequency = p->frequency;
+ state->fec_inner = p->u.qpsk.fec_inner;
+ state->symbol_rate = p->u.qpsk.symbol_rate;
- return UNKNOWN_FRONTEND;
+ return 0;
}
-static struct i2c_client client_template;
-
-static int attach_adapter(struct i2c_adapter *adapter)
+static int stv0299_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters * p)
{
- struct i2c_client *client;
- struct stv0299_state* state;
- int tuner_type;
- int ret;
- u8 id;
+ struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
+ s32 derot_freq;
+ int invval;
- stv0299_writereg(adapter, 0x02, 0x34); /* standby off */
- msleep(200);
- id = stv0299_readreg(adapter, 0x00);
+ derot_freq = (s32)(s16) ((stv0299_readreg (state, 0x22) << 8)
+ | stv0299_readreg (state, 0x23));
- dprintk ("%s: id == 0x%02x\n", __FUNCTION__, id);
+ derot_freq *= (state->config->mclk >> 16);
+ derot_freq += 500;
+ derot_freq /= 1000;
- /* register 0x00 contains 0xa1 for STV0299 and STV0299B */
- /* register 0x00 might contain 0x80 when returning from standby */
- if (id != 0xa1 && id != 0x80)
- return -ENODEV;
+ p->frequency += derot_freq;
- if ((tuner_type = probe_tuner(adapter)) < 0)
- return -ENODEV;
+ invval = stv0299_readreg (state, 0x0c) & 1;
+ if (state->config->invert) invval = (~invval) & 1;
+ p->inversion = invval ? INVERSION_ON : INVERSION_OFF;
- if ((state = kmalloc(sizeof(struct stv0299_state), GFP_KERNEL)) == NULL) {
- return -ENOMEM;
- }
+ p->u.qpsk.fec_inner = stv0299_get_fec (state);
+ p->u.qpsk.symbol_rate = stv0299_get_symbolrate (state);
- if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
- kfree(state);
- return -ENOMEM;
- }
-
- state->tuner_type = tuner_type;
- state->tuner_frequency = 0;
- state->initialised = 0;
- state->i2c = adapter;
-
- memcpy(client, &client_template, sizeof(struct i2c_client));
- client->adapter = adapter;
- client->addr = (0x68>>1);
- i2c_set_clientdata(client, (void*)state);
-
- ret = i2c_attach_client(client);
- if (ret) {
- kfree(client);
- kfree(state);
- return -EFAULT;
- }
-
- BUG_ON(!state->dvb);
-
- ret = dvb_register_frontend(uni0299_ioctl, state->dvb, state,
- &uni0299_info, THIS_MODULE);
- if (ret) {
- i2c_detach_client(client);
- kfree(client);
- kfree(state);
- return -EFAULT;
- }
-
return 0;
}
-static int detach_client(struct i2c_client *client)
+static int stv0299_sleep(struct dvb_frontend* fe)
{
- struct stv0299_state *state = (struct stv0299_state*)i2c_get_clientdata(client);
+ struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
+
+ stv0299_writeregI(state, 0x02, 0x80);
+ state->initialised = 0;
- dvb_unregister_frontend (uni0299_ioctl, state->dvb);
- i2c_detach_client(client);
- kfree(client);
- kfree(state);
return 0;
}
-static int command (struct i2c_client *client, unsigned int cmd, void *arg)
+static int stv0299_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
{
- struct stv0299_state *data = (struct stv0299_state*)i2c_get_clientdata(client);
- dprintk ("%s\n", __FUNCTION__);
+ struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
- switch (cmd) {
- case FE_REGISTER: {
- data->dvb = (struct dvb_adapter*)arg;
- break;
- }
- case FE_UNREGISTER: {
- data->dvb = NULL;
- break;
- }
- default:
- return -EOPNOTSUPP;
+ 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;
}
return 0;
}
-static struct i2c_driver driver = {
- .owner = THIS_MODULE,
- .name = FRONTEND_NAME,
- .id = I2C_DRIVERID_DVBFE_STV0299,
- .flags = I2C_DF_NOTIFY,
- .attach_adapter = attach_adapter,
- .detach_client = detach_client,
- .command = command,
-};
-
-static struct i2c_client client_template = {
- .name = FRONTEND_NAME,
- .flags = I2C_CLIENT_ALLOW_USE,
- .driver = &driver,
-};
-
-static int __init init_uni0299 (void)
+static void stv0299_release(struct dvb_frontend* fe)
{
- return i2c_add_driver(&driver);
+ struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
+ kfree(state);
}
-static void __exit exit_uni0299 (void)
+static struct dvb_frontend_ops stv0299_ops;
+
+struct dvb_frontend* stv0299_attach(const struct stv0299_config* config,
+ struct i2c_adapter* i2c)
{
- if (i2c_del_driver(&driver))
- printk("stv0299: driver deregistration failed\n");
+ struct stv0299_state* state = NULL;
+ int id;
+
+ /* allocate memory for the internal state */
+ state = (struct stv0299_state*) kmalloc(sizeof(struct stv0299_state), GFP_KERNEL);
+ if (state == NULL) goto error;
+
+ /* setup the state */
+ state->config = config;
+ state->i2c = i2c;
+ memcpy(&state->ops, &stv0299_ops, sizeof(struct dvb_frontend_ops));
+ state->initialised = 0;
+ state->tuner_frequency = 0;
+ state->symbol_rate = 0;
+ state->fec_inner = 0;
+ state->errmode = STATUS_BER;
+
+ /* check if the demod is there */
+ stv0299_writeregI(state, 0x02, 0x34); /* standby off */
+ msleep(200);
+ id = stv0299_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;
+
+error:
+ if (state) kfree(state);
+ return NULL;
}
-module_init (init_uni0299);
-module_exit (exit_uni0299);
+static struct dvb_frontend_ops stv0299_ops = {
+
+ .info = {
+ .name = "ST STV0299 DVB-S",
+ .type = FE_QPSK,
+ .frequency_min = 950000,
+ .frequency_max = 2150000,
+ .frequency_stepsize = 125, /* kHz for QPSK frontends */
+ .frequency_tolerance = 0,
+ .symbol_rate_min = 1000000,
+ .symbol_rate_max = 45000000,
+ .symbol_rate_tolerance = 500, /* ppm */
+ .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
+ FE_CAN_QPSK |
+ FE_CAN_FEC_AUTO
+ },
+
+ .release = stv0299_release,
+
+ .init = stv0299_init,
+ .sleep = stv0299_sleep,
+
+ .set_frontend = stv0299_set_frontend,
+ .get_frontend = stv0299_get_frontend,
+ .get_tune_settings = stv0299_get_tune_settings,
+
+ .read_status = stv0299_read_status,
+ .read_ber = stv0299_read_ber,
+ .read_signal_strength = stv0299_read_signal_strength,
+ .read_snr = stv0299_read_snr,
+ .read_ucblocks = stv0299_read_ucblocks,
+
+ .diseqc_send_master_cmd = stv0299_send_diseqc_msg,
+ .diseqc_send_burst = stv0299_send_diseqc_burst,
+ .set_tone = stv0299_set_tone,
+ .set_voltage = stv0299_set_voltage,
+ .dishnetwork_send_legacy_command = stv0299_send_legacy_dish_cmd,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-MODULE_DESCRIPTION("Universal STV0299/TSA5059/SL1935 DVB Frontend driver");
+MODULE_DESCRIPTION("ST STV0299 DVB Demodulator driver");
MODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Peter Schildmann, Felix Domke, "
"Andreas Oberritter, Andrew de Quincey, Kenneth Aafløy");
MODULE_LICENSE("GPL");
+EXPORT_SYMBOL(stv0299_writereg);
+EXPORT_SYMBOL(stv0299_attach);