X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fmedia%2Fdvb%2Ffrontends%2Fstv0299.c;h=17c1dd32acd5097a56c09b5746cbcb91ddc3947d;hb=3ec04f3d2903fdf6d9849a8633af59b8628164a5;hp=bf5de103142fada710714c19ff8f95ab992e2d4f;hpb=8d40237c730b8be87c1b80a5d96b9c603fefa829;p=linux-2.6.git diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c index bf5de1031..17c1dd32a 100644 --- a/drivers/media/dvb/frontends/stv0299.c +++ b/drivers/media/dvb/frontends/stv0299.c @@ -1,5 +1,8 @@ /* - Driver for ST STV0299 demodulator + Universal driver for STV0299/TDA5059/SL1935 based + DVB QPSK frontends + + Alps BSRU6, LG TDQB-S00x Copyright (C) 2001-2002 Convergence Integrated Media GmbH , @@ -45,73 +48,250 @@ #include #include #include -#include #include #include #include #include "dvb_frontend.h" -#include "stv0299.h" +#include "dvb_functions.h" -struct stv0299_state { +#if 0 +#define dprintk(x...) printk(x) +#else +#define dprintk(x...) +#endif + +static int stv0299_status = 0; +static int disable_typhoon = 0; - struct i2c_adapter* i2c; +#define STATUS_BER 0 +#define STATUS_UCBLOCKS 1 - struct dvb_frontend_ops ops; - const struct stv0299_config* config; +/* 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 + +/* 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 +}; - 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; - int errmode; }; -#define STATUS_BER 0 -#define STATUS_UCBLOCKS 1 -static int debug; -#define dprintk(args...) \ - do { \ - if (debug) printk(KERN_DEBUG "stv0299: " args); \ - } while (0) +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 -static int stv0299_writeregI (struct stv0299_state* state, u8 reg, u8 data) + 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 stv0299_set_FEC (struct dvb_i2c_bus *i2c, fe_code_rate_t fec); +static int stv0299_set_symbolrate (struct dvb_i2c_bus *i2c, u32 srate, int tuner_type); + +static int stv0299_writereg (struct dvb_i2c_bus *i2c, 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 }; + struct i2c_msg msg = { .addr = 0x68, .flags = 0, .buf = buf, .len = 2 }; - ret = i2c_transfer (state->i2c, &msg, 1); + ret = i2c->xfer (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) ? -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); + return (ret != 1) ? -1 : 0; } -static u8 stv0299_readreg (struct stv0299_state* state, u8 reg) +static u8 stv0299_readreg (struct dvb_i2c_bus *i2c, 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 = 0x68, .flags = 0, .buf = b0, .len = 1 }, + { .addr = 0x68, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; - ret = i2c_transfer (state->i2c, msg, 2); + ret = i2c->xfer (i2c, msg, 2); if (ret != 2) dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", @@ -121,13 +301,13 @@ static u8 stv0299_readreg (struct stv0299_state* state, u8 reg) } -static int stv0299_readregs (struct stv0299_state* state, u8 reg1, u8 *b, u8 len) +static int stv0299_readregs (struct dvb_i2c_bus *i2c, 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 } }; + struct i2c_msg msg [] = { { .addr = 0x68, .flags = 0, .buf = ®1, .len = 1 }, + { .addr = 0x68, .flags = I2C_M_RD, .buf = b, .len = len } }; - ret = i2c_transfer (state->i2c, msg, 2); + ret = i2c->xfer (i2c, msg, 2); if (ret != 2) dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret); @@ -136,44 +316,372 @@ static int stv0299_readregs (struct stv0299_state* state, u8 reg1, u8 *b, u8 len } -static int stv0299_set_FEC (struct stv0299_state* state, fe_code_rate_t fec) +static int pll_write (struct dvb_i2c_bus *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->xfer (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 dvb_i2c_bus *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 dvb_i2c_bus *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: + if (ftype == PHILIPS_SU1278_TSA_TY) + 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 dvb_i2c_bus *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 dvb_i2c_bus *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 dvb_i2c_bus *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->xfer (i2c, msg, 2); + + if (ret != 2) + dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret); + + return stat[0]; +} +#endif + + +static int stv0299_init (struct dvb_i2c_bus *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 4) @@ -191,191 +699,136 @@ static fe_code_rate_t stv0299_get_fec (struct stv0299_state* state) } -static int stv0299_wait_diseqc_fifo (struct stv0299_state* state, int timeout) +static int stv0299_wait_diseqc_fifo (struct dvb_i2c_bus *i2c, int timeout) { unsigned long start = jiffies; dprintk ("%s\n", __FUNCTION__); - while (stv0299_readreg(state, 0x0a) & 1) { + while (stv0299_readreg(i2c, 0x0a) & 1) { if (jiffies - start > timeout) { dprintk ("%s: timeout!!\n", __FUNCTION__); return -ETIMEDOUT; } - msleep(10); + dvb_delay(10); }; return 0; } -static int stv0299_wait_diseqc_idle (struct stv0299_state* state, int timeout) +static int stv0299_wait_diseqc_idle (struct dvb_i2c_bus *i2c, int timeout) { unsigned long start = jiffies; dprintk ("%s\n", __FUNCTION__); - while ((stv0299_readreg(state, 0x0a) & 3) != 2 ) { + while ((stv0299_readreg(i2c, 0x0a) & 3) != 2 ) { if (jiffies - start > timeout) { dprintk ("%s: timeout!!\n", __FUNCTION__); return -ETIMEDOUT; } - msleep(10); + dvb_delay(10); }; 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; - - // 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, +static int stv0299_send_diseqc_msg (struct dvb_i2c_bus *i2c, 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 (state, 100) < 0) + if (stv0299_wait_diseqc_idle (i2c, 100) < 0) return -ETIMEDOUT; - val = stv0299_readreg (state, 0x08); + val = stv0299_readreg (i2c, 0x08); - if (stv0299_writeregI (state, 0x08, (val & ~0x7) | 0x6)) /* DiSEqC mode */ + if (stv0299_writereg (i2c, 0x08, (val & ~0x7) | 0x6)) /* DiSEqC mode */ return -EREMOTEIO; for (i=0; imsg_len; i++) { - if (stv0299_wait_diseqc_fifo (state, 100) < 0) + if (stv0299_wait_diseqc_fifo (i2c, 100) < 0) return -ETIMEDOUT; - if (stv0299_writeregI (state, 0x09, m->msg[i])) + if (stv0299_writereg (i2c, 0x09, m->msg[i])) return -EREMOTEIO; } - if (stv0299_wait_diseqc_idle (state, 100) < 0) + if (stv0299_wait_diseqc_idle (i2c, 100) < 0) return -ETIMEDOUT; return 0; } -static int stv0299_send_diseqc_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t burst) +static int stv0299_send_diseqc_burst (struct dvb_i2c_bus *i2c, 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 (state, 100) < 0) + if (stv0299_wait_diseqc_idle (i2c, 100) < 0) return -ETIMEDOUT; - val = stv0299_readreg (state, 0x08); + val = stv0299_readreg (i2c, 0x08); - if (stv0299_writeregI (state, 0x08, (val & ~0x7) | 0x2)) /* burst mode */ + if (stv0299_writereg (i2c, 0x08, (val & ~0x7) | 0x2)) /* burst mode */ return -EREMOTEIO; - if (stv0299_writeregI (state, 0x09, burst == SEC_MINI_A ? 0x00 : 0xff)) + if (stv0299_writereg (i2c, 0x09, burst == SEC_MINI_A ? 0x00 : 0xff)) return -EREMOTEIO; - if (stv0299_wait_diseqc_idle (state, 100) < 0) + if (stv0299_wait_diseqc_idle (i2c, 100) < 0) return -ETIMEDOUT; - if (stv0299_writeregI (state, 0x08, val)) + if (stv0299_writereg (i2c, 0x08, val)) return -EREMOTEIO; return 0; } -static int stv0299_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +static int stv0299_set_tone (struct dvb_i2c_bus *i2c, fe_sec_tone_mode_t tone) { - struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; u8 val; - if (stv0299_wait_diseqc_idle (state, 100) < 0) + 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) return -ETIMEDOUT; - val = stv0299_readreg (state, 0x08); + val = stv0299_readreg (i2c, 0x08); switch (tone) { case SEC_TONE_ON: - return stv0299_writeregI (state, 0x08, val | 0x3); - + { + dprintk("%s: TONE_ON\n", __FUNCTION__); + return stv0299_writereg (i2c, 0x08, val | 0x3); + } case SEC_TONE_OFF: - return stv0299_writeregI (state, 0x08, (val & ~0x3) | 0x02); - + { + dprintk("%s: TONE_OFF\n", __FUNCTION__); + return stv0299_writereg (i2c, 0x08, (val & ~0x3) | 0x02); + } default: + { + dprintk("%s: TONE INVALID\n", __FUNCTION__); return -EINVAL; } + }; } -static int stv0299_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage) +static int stv0299_set_voltage (struct dvb_i2c_bus *i2c, fe_sec_voltage_t voltage, + int tuner_type) { - struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; u8 reg0x08; u8 reg0x0c; @@ -383,8 +836,8 @@ static int stv0299_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltag voltage == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" : voltage == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??"); - reg0x08 = stv0299_readreg (state, 0x08); - reg0x0c = stv0299_readreg (state, 0x0c); + reg0x08 = stv0299_readreg (i2c, 0x08); + reg0x0c = stv0299_readreg (i2c, 0x0c); /** * H/V switching over OP0, OP1 and OP2 are LNB power enable bits @@ -392,91 +845,181 @@ static int stv0299_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltag reg0x0c &= 0x0f; if (voltage == SEC_VOLTAGE_OFF) { - stv0299_writeregI (state, 0x0c, 0x00); /* LNB power off! */ - return stv0299_writeregI (state, 0x08, 0x00); /* LNB power off! */ + stv0299_writereg (i2c, 0x0c, 0x00); /* LNB power off! */ + return stv0299_writereg (i2c, 0x08, 0x00); /* LNB power off! */ } - stv0299_writeregI (state, 0x08, (reg0x08 & 0x3f) | (state->config->lock_output << 6)); + stv0299_writereg (i2c, 0x08, reg0x08 | 0x40); switch (voltage) { case SEC_VOLTAGE_13: - if (state->config->volt13_op0_op1 == STV0299_VOLT13_OP0) reg0x0c |= 0x10; - else reg0x0c |= 0x40; - - return stv0299_writeregI(state, 0x0c, reg0x0c); + if (tuner_type == PHILIPS_SU1278_TSA_TY) + return stv0299_writereg (i2c, 0x0c, reg0x0c | 0x10); + else + return stv0299_writereg (i2c, 0x0c, reg0x0c | 0x40); case SEC_VOLTAGE_18: - return stv0299_writeregI(state, 0x0c, reg0x0c | 0x50); + return stv0299_writereg (i2c, 0x0c, reg0x0c | 0x50); + default: return -EINVAL; }; } -static int stv0299_send_legacy_dish_cmd(struct dvb_frontend* fe, u32 cmd) +static int stv0299_set_symbolrate (struct dvb_i2c_bus *i2c, u32 srate, int tuner_type) { - u8 last = 1; - int i; - - /* reset voltage at the end - if((0x50 & stv0299_readreg (i2c, 0x0c)) == 0x50) - cmd |= 0x80; - else - cmd &= 0x7F; - */ - - cmd = cmd << 1; - dprintk("%s switch command: 0x%04x\n",__FUNCTION__, cmd); + u64 big = srate; + u32 ratio; + u8 aclk = 0; + u8 bclk = 0; + u8 m1; + int Mclk = M_CLK; - stv0299_set_voltage(fe,SEC_VOLTAGE_18); - msleep(32); + // check rate is within limits + if ((srate < 1000000) || (srate > 45000000)) return -EINVAL; - for (i=0; i<9; i++) { - if((cmd & 0x01) != last) { - stv0299_set_voltage(fe, - last ? SEC_VOLTAGE_13 : - SEC_VOLTAGE_18); - last = (last) ? 0 : 1; + // 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); } - - cmd = cmd >> 1; - - if (i != 8) - msleep(8); + 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: + 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; } + return 0; } -static int stv0299_init (struct dvb_frontend* fe) +static int stv0299_get_symbolrate (struct dvb_i2c_bus *i2c, int tuner_type) { - struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; - int i; + u32 Mclk = M_CLK / 4096L; + u32 srate; + s32 offset; + u8 sfr[3]; + s8 rtf; - dprintk("stv0299: init chip\n"); + dprintk ("%s\n", __FUNCTION__); - 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 (tuner_type == PHILIPS_SU1278_TSA_TT) Mclk = M_CLK_SU1278_TSA_TT / 4096L; - 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 */ - } + stv0299_readregs (i2c, 0x1f, sfr, 3); + stv0299_readregs (i2c, 0x1a, &rtf, 1); - return 0; + 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 uni0299_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg) +{ + struct dvb_i2c_bus *i2c = fe->i2c; + struct stv0299_state *state = (struct stv0299_state *) fe->data; + + dprintk ("%s\n", __FUNCTION__); -static int stv0299_read_status(struct dvb_frontend* fe, fe_status_t* status) + switch (cmd) { + case FE_GET_INFO: { - struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; + struct dvb_frontend_info* tmp = (struct dvb_frontend_info*) arg; + memcpy (arg, &uni0299_info, sizeof(struct dvb_frontend_info)); - u8 signal = 0xff - stv0299_readreg (state, 0x18); - u8 sync = stv0299_readreg (state, 0x1b); + 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); dprintk ("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __FUNCTION__, sync); + *status = 0; if (signal > 10) @@ -494,61 +1037,53 @@ static int stv0299_read_status(struct dvb_frontend* fe, fe_status_t* status) if ((sync & 0x98) == 0x98) *status |= FE_HAS_LOCK; - return 0; + break; } -static int stv0299_read_ber(struct dvb_frontend* fe, u32* ber) -{ - struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; - - if (state->errmode != STATUS_BER) return 0; - *ber = (stv0299_readreg (state, 0x1d) << 8) | stv0299_readreg (state, 0x1e); - - return 0; + 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; -static int stv0299_read_signal_strength(struct dvb_frontend* fe, u16* strength) + case FE_READ_SIGNAL_STRENGTH: { - struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; - - s32 signal = 0xffff - ((stv0299_readreg (state, 0x18) << 8) - | stv0299_readreg (state, 0x19)); + 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 (state, 0x18), - stv0299_readreg (state, 0x19), (int) signal); + stv0299_readreg (i2c, 0x18), + stv0299_readreg (i2c, 0x19), (int) signal); signal = signal * 5 / 4; - *strength = (signal > 0xffff) ? 0xffff : (signal < 0) ? 0 : signal; - - return 0; + *((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; -static int stv0299_read_snr(struct dvb_frontend* fe, u16* snr) + case FE_SET_FRONTEND: { - struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; - - s32 xsnr = 0xffff - ((stv0299_readreg (state, 0x24) << 8) - | stv0299_readreg (state, 0x25)); - xsnr = 3 * (xsnr - 0xa100); - *snr = (xsnr > 0xffff) ? 0xffff : (xsnr < 0) ? 0 : xsnr; - - return 0; -} - -static int stv0299_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) -{ - struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; - - if (state->errmode != STATUS_UCBLOCKS) *ucblocks = 0; - else *ucblocks = (stv0299_readreg (state, 0x1d) << 8) | stv0299_readreg (state, 0x1e); - - return 0; -} - -static int stv0299_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters * p) -{ - struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; + struct dvb_frontend_parameters *p = arg; int invval = 0; dprintk ("%s : FE_SET_FRONTEND\n", __FUNCTION__); @@ -560,10 +1095,12 @@ static int stv0299_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par printk("stv0299 does not support auto-inversion\n"); return -EINVAL; } - if (state->config->invert) invval = (~invval) & 1; - stv0299_writeregI(state, 0x0c, (stv0299_readreg(state, 0x0c) & 0xfe) | invval); + if (state->tuner_type == ALPS_BSRU6) invval = (~invval) & 1; + stv0299_writereg(i2c, 0x0c, (stv0299_readreg(i2c, 0x0c) & 0xfe) | invval); - if (state->config->enhanced_tuning) { + 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; @@ -572,88 +1109,125 @@ static int stv0299_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par 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); + int Drot_freq = (frequency_delta << 16) / (M_CLK_SU1278_TSA_TT / 1000); // zap the derotator registers first - stv0299_writeregI(state, 0x22, 0x00); - stv0299_writeregI(state, 0x23, 0x00); + stv0299_writereg (i2c, 0x22, 0x00); + stv0299_writereg (i2c, 0x23, 0x00); // now set them as we want - stv0299_writeregI(state, 0x22, Drot_freq >> 8); - stv0299_writeregI(state, 0x23, Drot_freq); + stv0299_writereg (i2c, 0x22, Drot_freq >> 8); + stv0299_writereg (i2c, 0x23, Drot_freq); } else { /* A "normal" tune is requested */ - stv0299_writeregI(state, 0x05, 0xb5); /* enable i2c repeater on stv0299 */ - state->config->pll_set(fe, p); - stv0299_writeregI(state, 0x05, 0x35); /* disable i2c repeater on stv0299 */ - - 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); + 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; } - } 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 */ - - 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); + + 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; - - return 0; + break; } -static int stv0299_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters * p) + case FE_GET_FRONTEND: { - struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; + struct dvb_frontend_parameters *p = arg; s32 derot_freq; + int Mclk = M_CLK; int invval; - derot_freq = (s32)(s16) ((stv0299_readreg (state, 0x22) << 8) - | stv0299_readreg (state, 0x23)); + 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 *= (state->config->mclk >> 16); + derot_freq *= (Mclk >> 16); derot_freq += 500; derot_freq /= 1000; p->frequency += derot_freq; - invval = stv0299_readreg (state, 0x0c) & 1; - if (state->config->invert) invval = (~invval) & 1; + invval = stv0299_readreg (i2c, 0x0c) & 1; + if (state->tuner_type == ALPS_BSRU6) invval = (~invval) & 1; p->inversion = invval ? INVERSION_ON : INVERSION_OFF; - p->u.qpsk.fec_inner = stv0299_get_fec (state); - p->u.qpsk.symbol_rate = stv0299_get_symbolrate (state); + p->u.qpsk.fec_inner = stv0299_get_fec (i2c); + p->u.qpsk.symbol_rate = stv0299_get_symbolrate (i2c, state->tuner_type); + break; + } - return 0; + 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; -static int stv0299_sleep(struct dvb_frontend* fe) -{ - struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; + case FE_DISEQC_SEND_MASTER_CMD: + return stv0299_send_diseqc_msg (i2c, arg); - stv0299_writeregI(state, 0x02, 0x80); - state->initialised = 0; + 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); + + case FE_SET_VOLTAGE: + return stv0299_set_voltage (i2c, (fe_sec_voltage_t) arg, + state->tuner_type); -static int stv0299_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) + case FE_GET_TUNE_SETTINGS: { - struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; + 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; - fesettings->min_delay_ms = state->config->min_delay_ms; + 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; @@ -661,103 +1235,166 @@ static int stv0299_get_tune_settings(struct dvb_frontend* fe, struct dvb_fronten fesettings->step_size = fesettings->parameters.u.qpsk.symbol_rate / 16000; fesettings->max_drift = fesettings->parameters.u.qpsk.symbol_rate / 2000; } + break; + } + + return 0; + } + + default: + return -EOPNOTSUPP; + }; + return 0; } -static void stv0299_release(struct dvb_frontend* fe) +static long probe_tuner (struct dvb_i2c_bus *i2c) +{ + struct dvb_adapter * adapter = (struct dvb_adapter *) i2c->adapter; + + /* 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, .buf = rpt, .len = 2 }, + { .addr = 0x60, .flags = I2C_M_RD, .buf = stat, .len = 1 }}; + struct i2c_msg msg2 [] = {{ .addr = 0x68, .buf = rpt, .len = 2 }, + { .addr = 0x61, .flags = I2C_M_RD, .buf = stat, .len = 1 }}; + struct i2c_msg msg3 [] = {{ .addr = 0x68, .buf = rpt, .len = 2 }, + { .addr = 0x60, .buf = tda6100_buf, .len = 2 }}; + + stv0299_writereg (i2c, 0x01, 0x15); + stv0299_writereg (i2c, 0x02, 0x30); + stv0299_writereg (i2c, 0x03, 0x00); + + + printk ("%s: try to attach to %s\n", __FUNCTION__, adapter->name); + + if ( strcmp(adapter->name, "SkyStar2") == 0 ) + { + printk ("%s: setup for tuner Samsung TBMU24112IMB\n", __FILE__); + + return SAMSUNG_TBMU24112IMB; + } + + if ((ret = i2c->xfer(i2c, msg1, 2)) == 2) { + if ( strcmp(adapter->name, "TT-Budget/WinTV-NOVA-CI PCI") == 0 ) { + // technotrend cards require non-datasheet settings + printk ("%s: setup for tuner SU1278 (TSA5059 synth) on" + " TechnoTrend hardware\n", __FILE__); + return PHILIPS_SU1278_TSA_TT; + } else { + // fall back to datasheet-recommended settings + printk ("%s: setup for tuner SU1278 (TSA5059 synth)\n", + __FILE__); + return PHILIPS_SU1278_TSA; + } + } + + if ((ret = i2c->xfer(i2c, msg2, 2)) == 2) { + if ( strcmp(adapter->name, "KNC1 DVB-S") == 0 && + !disable_typhoon ) { - struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; - kfree(state); + // Typhoon cards have unusual wiring. + printk ("%s: setup for tuner SU1278 (TSA5059 synth) on" + " Typhoon hardware\n", __FILE__); + return PHILIPS_SU1278_TSA_TY; + } + //else if ((stat[0] & 0x3f) == 0) { + else if (0) { + printk ("%s: setup for tuner TDQF-S001F\n", __FILE__); + return LG_TDQF_S001F; + } else { + printk ("%s: setup for tuner BSRU6, TDQB-S00x\n", + __FILE__); + return ALPS_BSRU6; + } + } + + /** + * setup i2c timing for SU1278... + */ + stv0299_writereg (i2c, 0x02, 0x00); + + if ((ret = i2c->xfer(i2c, msg3, 2)) == 2) { + printk ("%s: setup for tuner Philips SU1278 (TUA6100 synth)\n", + __FILE__); + return PHILIPS_SU1278_TUA; + } + + printk ("%s: unknown PLL synthesizer (ret == %i), " + "please report to !!\n", + __FILE__, ret); + + return UNKNOWN_FRONTEND; } -static struct dvb_frontend_ops stv0299_ops; -struct dvb_frontend* stv0299_attach(const struct stv0299_config* config, - struct i2c_adapter* i2c) +static int uni0299_attach (struct dvb_i2c_bus *i2c, void **data) { - struct stv0299_state* state = NULL; - int id; + struct stv0299_state* state; + int tuner_type; + u8 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; + stv0299_writereg (i2c, 0x02, 0x34); /* standby off */ + dvb_delay(200); + id = stv0299_readreg (i2c, 0x00); - /* check if the demod is there */ - stv0299_writeregI(state, 0x02, 0x34); /* standby off */ - msleep(200); - id = stv0299_readreg(state, 0x00); + dprintk ("%s: id == 0x%02x\n", __FUNCTION__, id); /* register 0x00 contains 0xa1 for STV0299 and STV0299B */ /* register 0x00 might contain 0x80 when returning from standby */ - if (id != 0xa1 && id != 0x80) goto error; + if (id != 0xa1 && id != 0x80) + return -ENODEV; - /* create dvb_frontend */ - state->frontend.ops = &state->ops; - state->frontend.demodulator_priv = state; - return &state->frontend; + if ((tuner_type = probe_tuner(i2c)) < 0) + return -ENODEV; -error: - if (state) kfree(state); - return NULL; + if ((state = kmalloc(sizeof(struct stv0299_state), GFP_KERNEL)) == NULL) { + return -ENOMEM; + } + + *data = state; + state->tuner_type = tuner_type; + state->tuner_frequency = 0; + state->initialised = 0; + return dvb_register_frontend (uni0299_ioctl, i2c, (void *) state, + &uni0299_info); } -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)."); +static void uni0299_detach (struct dvb_i2c_bus *i2c, void *data) +{ + dprintk ("%s\n", __FUNCTION__); + kfree(data); + dvb_unregister_frontend (uni0299_ioctl, i2c); +} + -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"); +static int __init init_uni0299 (void) +{ + dprintk ("%s\n", __FUNCTION__); + return dvb_register_i2c_device (NULL, uni0299_attach, uni0299_detach); +} + + +static void __exit exit_uni0299 (void) +{ + dprintk ("%s\n", __FUNCTION__); + + dvb_unregister_i2c_device (uni0299_attach); +} + +module_init (init_uni0299); +module_exit (exit_uni0299); + +MODULE_DESCRIPTION("Universal STV0299/TSA5059/SL1935 DVB Frontend driver"); +MODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Peter Schildmann, Felix Domke, Andreas Oberritter, Andrew de Quincey"); MODULE_LICENSE("GPL"); -EXPORT_SYMBOL(stv0299_writereg); -EXPORT_SYMBOL(stv0299_attach); +MODULE_PARM(stv0299_status, "i"); +MODULE_PARM_DESC(stv0299_status, "Which status value to support (0: BER, 1: UCBLOCKS)"); + +MODULE_PARM(disable_typhoon, "i"); +MODULE_PARM_DESC(disable_typhoon, "Disable support for Philips SU1278 on Typhoon hardware.");