diff options
Diffstat (limited to 'linux/drivers')
-rw-r--r-- | linux/drivers/media/dvb/frontends/s5h1420.c | 67 | ||||
-rw-r--r-- | linux/drivers/media/dvb/ttpci/budget.c | 3 |
2 files changed, 60 insertions, 10 deletions
diff --git a/linux/drivers/media/dvb/frontends/s5h1420.c b/linux/drivers/media/dvb/frontends/s5h1420.c index 6a8ede614..c8f5dbfa4 100644 --- a/linux/drivers/media/dvb/frontends/s5h1420.c +++ b/linux/drivers/media/dvb/frontends/s5h1420.c @@ -31,6 +31,9 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #include "s5h1420.h" + +#define TONE_FREQ 22000 + struct s5h1420_state { struct i2c_adapter* i2c; struct dvb_frontend_ops ops; @@ -40,9 +43,12 @@ struct s5h1420_state { u8 postlocked:1; u32 fclk; u32 tunedfreq; + fe_code_rate_t fec_inner; + u32 symbol_rate; }; static u32 s5h1420_getsymbolrate(struct s5h1420_state* state); +static int s5h1420_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings); static int debug = 0; @@ -431,7 +437,9 @@ static void s5h1420_setfreqoffset(struct s5h1420_state* state, int freqoffset) { int val; - val = -(int) (((freqoffset / 1000) * (1<<24)) / (state->fclk / 1000000)); + /* remember freqoffset is in kHz, but the chip wants the offset in Hz, so + * divide fclk by 1000000 to get the correct value. */ + val = -(int) ((freqoffset * (1<<24)) / (state->fclk / 1000000)); s5h1420_writereg(state, 0x09, s5h1420_readreg(state, 0x09) & 0xbf); s5h1420_writereg(state, 0x0e, val >> 16); @@ -453,7 +461,9 @@ static int s5h1420_getfreqoffset(struct s5h1420_state* state) if (val & 0x800000) val |= 0xff000000; - val = - ((val * (state->fclk/1000)) / (1<<24)); + /* remember freqoffset is in kHz, but the chip wants the offset in Hz, so + * divide fclk by 1000000 to get the correct value. */ + val = - ((val * (state->fclk/1000000)) / (1<<24)); return val; } @@ -553,8 +563,21 @@ static fe_spectral_inversion_t s5h1420_getinversion(struct s5h1420_state* state) static int s5h1420_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) { struct s5h1420_state* state = fe->demodulator_priv; - - // FIXME: fast tune + u32 frequency_delta; + struct dvb_frontend_tune_settings fesettings; + + /* check if we should do a fast-tune */ + memcpy(&fesettings.parameters, p, sizeof(struct dvb_frontend_parameters)); + s5h1420_get_tune_settings(fe, &fesettings); + frequency_delta = p->frequency - state->tunedfreq; + if ((frequency_delta > -fesettings.max_drift) && (frequency_delta < fesettings.max_drift) && + (frequency_delta != 0) && + (state->fec_inner == p->u.qpsk.fec_inner) && + (state->symbol_rate == p->u.qpsk.symbol_rate)) { + + s5h1420_setfreqoffset(state, frequency_delta); + return 0; + } /* first of all, software reset */ s5h1420_reset(state); @@ -595,7 +618,7 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par s5h1420_writereg(state, 0x35, 0x33); s5h1420_writereg(state, 0x38, 0x01); s5h1420_writereg(state, 0x39, 0x7d); - s5h1420_writereg(state, 0x3a, (state->fclk + (22000*32) - 1) / (22000*32)); + s5h1420_writereg(state, 0x3a, (state->fclk + (TONE_FREQ * 32) - 1) / (TONE_FREQ * 32)); s5h1420_writereg(state, 0x3c, 0x00); s5h1420_writereg(state, 0x45, 0x61); s5h1420_writereg(state, 0x46, 0x1d); @@ -603,8 +626,8 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par /* start QPSK */ s5h1420_writereg(state, 0x05, s5h1420_readreg(state, 0x05) | 1); - /* set the frequency offset to 0 initially */ - s5h1420_setfreqoffset(state, 0); + /* set the frequency offset to adjust for PLL inaccuracy */ + s5h1420_setfreqoffset(state, p->frequency - state->tunedfreq); /* set the symbolrate */ s5h1420_setsymbolrate(state, p); @@ -615,6 +638,8 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par /* set the FEC */ s5h1420_setfec(state, p); + state->fec_inner = p->u.qpsk.fec_inner; + state->symbol_rate = p->u.qpsk.symbol_rate; state->postlocked = 0; return 0; } @@ -633,7 +658,31 @@ static int s5h1420_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_par static int s5h1420_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) { - // FIXME + if (fesettings->parameters.u.qpsk.symbol_rate > 20000000) { + fesettings->min_delay_ms = 50; + fesettings->step_size = 2000; + fesettings->max_drift = 8000; + } else if (fesettings->parameters.u.qpsk.symbol_rate > 12000000) { + fesettings->min_delay_ms = 100; + fesettings->step_size = 1500; + fesettings->max_drift = 9000; + } else if (fesettings->parameters.u.qpsk.symbol_rate > 8000000) { + fesettings->min_delay_ms = 100; + fesettings->step_size = 1000; + fesettings->max_drift = 8000; + } else if (fesettings->parameters.u.qpsk.symbol_rate > 4000000) { + fesettings->min_delay_ms = 100; + fesettings->step_size = 500; + fesettings->max_drift = 7000; + } else if (fesettings->parameters.u.qpsk.symbol_rate > 2000000) { + fesettings->min_delay_ms = 200; + fesettings->step_size = (fesettings->parameters.u.qpsk.symbol_rate / 8000); + fesettings->max_drift = 14 * fesettings->step_size; + } else { + fesettings->min_delay_ms = 200; + fesettings->step_size = (fesettings->parameters.u.qpsk.symbol_rate / 8000); + fesettings->max_drift = 18 * fesettings->step_size; + } return 0; } @@ -689,6 +738,8 @@ struct dvb_frontend* s5h1420_attach(const struct s5h1420_config* config, struct state->postlocked = 0; state->fclk = 88000000; state->tunedfreq = 0; + state->fec_inner = FEC_NONE; + state->symbol_rate = 0; /* check if the demod is there + identify it */ identity = s5h1420_readreg(state, 0x00); diff --git a/linux/drivers/media/dvb/ttpci/budget.c b/linux/drivers/media/dvb/ttpci/budget.c index 550140a00..9961917e8 100644 --- a/linux/drivers/media/dvb/ttpci/budget.c +++ b/linux/drivers/media/dvb/ttpci/budget.c @@ -548,7 +548,7 @@ static void frontend_init(struct budget *budget) break; } break; -/* + case 0x1016: // Hauppauge/TT Nova-S SE (samsung s5h1420/????(tda8260)) budget->dvb_frontend = s5h1420_attach(&s5h1420_config, &budget->i2c_adap); if (budget->dvb_frontend) { @@ -557,7 +557,6 @@ static void frontend_init(struct budget *budget) lnbp21_init(budget); break; } -*/ } if (budget->dvb_frontend == NULL) { |