diff options
author | Andrew de Quincy <devnull@localhost> | 2004-02-23 23:20:29 +0000 |
---|---|---|
committer | Andrew de Quincy <devnull@localhost> | 2004-02-23 23:20:29 +0000 |
commit | a3601efd36d390b7437a57e8f8301d80cffe4c13 (patch) | |
tree | 013994aa5e7b6e4c3a323d32b435fc8a6f155689 /linux/drivers/media/dvb/frontends/stv0299.c | |
parent | eac35592452cdc3b7e6d9a0684d17c03fac94aba (diff) | |
download | mediapointer-dvb-s2-a3601efd36d390b7437a57e8f8301d80cffe4c13.tar.gz mediapointer-dvb-s2-a3601efd36d390b7437a57e8f8301d80cffe4c13.tar.bz2 |
Fixes to sort out tuning at low symbol rates
Diffstat (limited to 'linux/drivers/media/dvb/frontends/stv0299.c')
-rw-r--r-- | linux/drivers/media/dvb/frontends/stv0299.c | 119 |
1 files changed, 84 insertions, 35 deletions
diff --git a/linux/drivers/media/dvb/frontends/stv0299.c b/linux/drivers/media/dvb/frontends/stv0299.c index 19988e4f4..97036259a 100644 --- a/linux/drivers/media/dvb/frontends/stv0299.c +++ b/linux/drivers/media/dvb/frontends/stv0299.c @@ -49,6 +49,7 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/string.h> +#include <linux/slab.h> #include <asm/div64.h> #include "dvb_frontend.h" @@ -68,12 +69,12 @@ static int stv0299_status = 0; /* frontend types */ #define UNKNOWN_FRONTEND -1 -#define PHILIPS_SU1278_TSA 0 // SU1278 with TSA5959 synth and datasheet recommended settings +#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 TSA5959 synth and TechnoTrend settings +#define PHILIPS_SU1278_TSA_TT 5 // SU1278 with TSA5059 synth and TechnoTrend settings /* Master Clock = 88 MHz */ #define M_CLK (88000000UL) @@ -95,11 +96,18 @@ static struct dvb_frontend_info uni0299_info = { .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 | FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_AUTO | FE_CAN_CLEAN_SETUP }; +struct stv0299_state { + u8 tuner_type; + u8 initialised:1; + u32 tuner_frequency; +}; + + static u8 init_tab [] = { 0x04, 0x7d, /* F22FR = 0x7d */ /* F22 = f_VCO / 128 / 0x7d = 22 kHz */ @@ -349,7 +357,7 @@ static int tsa5059_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq, int ftype, in u8 addr; u32 div; u8 buf[4]; - int i, divisor, regcode; + int divisor, regcode; dprintk ("%s: freq %i, ftype %i\n", __FUNCTION__, freq, ftype); @@ -357,7 +365,7 @@ static int tsa5059_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq, int ftype, in divisor = 500; regcode = 2; - + // setup frequency divisor div = freq / divisor; buf[0] = (div >> 8) & 0x7f; @@ -374,10 +382,10 @@ static int tsa5059_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq, int ftype, in 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; + 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: @@ -579,7 +587,7 @@ static int stv0299_init (struct dvb_i2c_bus *i2c, int ftype) 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: @@ -895,6 +903,7 @@ static int stv0299_set_symbolrate (struct dvb_i2c_bus *i2c, u32 srate, int tuner stv0299_writereg (i2c, 0x1c, 0x12); stv0299_writereg (i2c, 0x2d, 0x05); } + stv0299_writereg (i2c, 0x0e, 0x23); stv0299_writereg (i2c, 0x0f, 0x94); stv0299_writereg (i2c, 0x10, 0x39); @@ -984,9 +993,9 @@ static int stv0299_get_symbolrate (struct dvb_i2c_bus *i2c, int tuner_type) static int uni0299_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg) { - int tuner_type = (long) fe->data; struct dvb_i2c_bus *i2c = fe->i2c; - + struct stv0299_state *state = (struct stv0299_state *) fe->data; + dprintk ("%s\n", __FUNCTION__); switch (cmd) { @@ -995,7 +1004,7 @@ static int uni0299_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg) struct dvb_frontend_info* tmp = (struct dvb_frontend_info*) arg; memcpy (arg, &uni0299_info, sizeof(struct dvb_frontend_info)); - if (tuner_type == PHILIPS_SU1278_TSA_TT) { + if (state->tuner_type == PHILIPS_SU1278_TSA_TT) { tmp->frequency_tolerance = M_CLK_SU1278_TSA_TT / 2000; } break; @@ -1072,25 +1081,46 @@ static int uni0299_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg) case FE_SET_FRONTEND: { - struct dvb_frontend_parameters *p = arg; + struct dvb_frontend_parameters *p = arg; - dprintk ("%s : FE_SET_FRONTEND\n", __FUNCTION__); + dprintk ("%s : FE_SET_FRONTEND\n", __FUNCTION__); - pll_set_tv_freq (i2c, p->frequency, tuner_type, - p->u.qpsk.symbol_rate); + if (p->inversion == INVERSION_OFF) { + stv0299_writereg(i2c, 0x0c, stv0299_readreg(i2c, 0x0c) & 0xfe); + } else if (p->inversion == INVERSION_ON) { + stv0299_writereg(i2c, 0x0c, stv0299_readreg(i2c, 0x0c) | 1); + } else { + printk("stv0299 does not support auto-inversion\n"); + return -EINVAL; + } stv0299_set_FEC (i2c, p->u.qpsk.fec_inner); - stv0299_set_symbolrate (i2c, p->u.qpsk.symbol_rate, tuner_type); - stv0299_writereg (i2c, 0x22, 0x00); - stv0299_writereg (i2c, 0x23, 0x00); - if (tuner_type != PHILIPS_SU1278_TSA_TT) { - stv0299_readreg (i2c, 0x23); - stv0299_writereg (i2c, 0x12, 0xb9); + stv0299_set_symbolrate (i2c, p->u.qpsk.symbol_rate, state->tuner_type); + + if (state->tuner_type == 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 / 1000; + if ((frequency_delta > -minmax) && (frequency_delta < minmax)) { + int Drot_freq = ((frequency_delta) << 16) / (M_CLK_SU1278_TSA_TT /1000); + stv0299_writereg (i2c, 0x22, Drot_freq >> 8); + stv0299_writereg (i2c, 0x23, Drot_freq); + break; + } } - stv0299_check_inversion (i2c); - /* printk ("%s: tsa5059 status: %x\n", __FUNCTION__, tsa5059_read_status(i2c)); */ - break; + /* A "normal" tune is requested */ + pll_set_tv_freq (i2c, p->frequency, state->tuner_type, + p->u.qpsk.symbol_rate); + stv0299_writereg (i2c, 0x22, 0x00); + stv0299_writereg (i2c, 0x23, 0x00); + if (state->tuner_type != PHILIPS_SU1278_TSA_TT) { + stv0299_readreg (i2c, 0x23); + stv0299_writereg (i2c, 0x12, 0xb9); + } + + state->tuner_frequency = p->frequency; + break; } case FE_GET_FRONTEND: @@ -1099,7 +1129,7 @@ static int uni0299_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg) s32 derot_freq; int Mclk = M_CLK; - if (tuner_type == PHILIPS_SU1278_TSA_TT) Mclk = M_CLK_SU1278_TSA_TT; + 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)); @@ -1112,7 +1142,7 @@ static int uni0299_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg) p->inversion = (stv0299_readreg (i2c, 0x0c) & 1) ? INVERSION_OFF : INVERSION_ON; p->u.qpsk.fec_inner = stv0299_get_fec (i2c); - p->u.qpsk.symbol_rate = stv0299_get_symbolrate (i2c, tuner_type); + p->u.qpsk.symbol_rate = stv0299_get_symbolrate (i2c, state->tuner_type); break; } @@ -1123,7 +1153,16 @@ static int uni0299_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg) break; case FE_INIT: - return stv0299_init (i2c, tuner_type); + if ((!state->initialised) || (state->tuner_type != PHILIPS_SU1278_TSA_TT)) { + state->initialised = 1; + return stv0299_init (i2c, state->tuner_type); + } else { + stv0299_writereg (i2c, 0x0c, 0x01); /* LNB power on! */ + stv0299_writereg (i2c, 0x08, 0x02); /* LNB power on! */ + stv0299_writereg (i2c, 0x02, 0x30); + return 0; + } + case FE_DISEQC_SEND_MASTER_CMD: return stv0299_send_diseqc_msg (i2c, arg); @@ -1177,11 +1216,11 @@ static long probe_tuner (struct dvb_i2c_bus *i2c) 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 (TSA5959 synth) on TechnoTrend hardware\n", __FILE__); + 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 (TSA5959 synth)\n", __FILE__); + printk ("%s: setup for tuner SU1278 (TSA5059 synth)\n", __FILE__); return PHILIPS_SU1278_TSA; } } @@ -1218,7 +1257,8 @@ static long probe_tuner (struct dvb_i2c_bus *i2c) static int uni0299_attach (struct dvb_i2c_bus *i2c, void **data) { - long tuner_type; + struct stv0299_state* state; + int tuner_type; u8 id; stv0299_writereg (i2c, 0x02, 0x00); /* standby off */ @@ -1233,8 +1273,16 @@ static int uni0299_attach (struct dvb_i2c_bus *i2c, void **data) if ((tuner_type = probe_tuner(i2c)) < 0) return -ENODEV; - - return dvb_register_frontend (uni0299_ioctl, i2c, (void*) tuner_type, + + if ((state = kmalloc(sizeof(struct stv0299_state), GFP_KERNEL)) == NULL) { + return -ENOMEM; + } + + *data = state; + state->tuner_type = tuner_type; + state->initialised = 0; + state->tuner_frequency = 0; + return dvb_register_frontend (uni0299_ioctl, i2c, (void *) state, &uni0299_info); } @@ -1242,6 +1290,7 @@ static int uni0299_attach (struct dvb_i2c_bus *i2c, void **data) static void uni0299_detach (struct dvb_i2c_bus *i2c, void *data) { dprintk ("%s\n", __FUNCTION__); + kfree(data); dvb_unregister_frontend (uni0299_ioctl, i2c); } @@ -1263,7 +1312,7 @@ 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"); +MODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Peter Schildmann, Felix Domke, Andreas Oberritter, Andrew de Quincey"); MODULE_LICENSE("GPL"); MODULE_PARM(stv0299_status, "i"); |