--- v4l-dvb/linux/drivers/media/dvb/frontends/s5h1420.c 2006-06-30 19:59:10.000000000 +0400 +++ mp-bc1/linux/drivers/media/dvb/frontends/s5h1420.c 2006-07-23 11:40:07.000000000 +0400 @@ -419,8 +419,8 @@ static void s5h1420_reset(struct s5h1420 udelay(10); } -static void s5h1420_setsymbolrate(struct s5h1420_state* state, - struct dvb_frontend_parameters *p) +static void s5h1420_setsymbolrate_compat(struct s5h1420_state* state, + struct dvb_frontend_parameters *p) { u64 val; @@ -437,6 +437,24 @@ static void s5h1420_setsymbolrate(struct s5h1420_writereg(state, 0x09, s5h1420_readreg(state, 0x09) | 0x80); } +static void s5h1420_setsymbolrate(struct s5h1420_state* state, + struct dvbfe_params *p) +{ + u64 val; + + val = ((u64) p->delsys.dvbs.symbol_rate / 1000ULL) * (1ULL<<24); + if (p->delsys.dvbs.symbol_rate <= 21000000) { + val *= 2; + } + do_div(val, (state->fclk / 1000)); + + s5h1420_writereg(state, 0x09, s5h1420_readreg(state, 0x09) & 0x7f); + s5h1420_writereg(state, 0x11, val >> 16); + s5h1420_writereg(state, 0x12, val >> 8); + s5h1420_writereg(state, 0x13, val & 0xff); + s5h1420_writereg(state, 0x09, s5h1420_readreg(state, 0x09) | 0x80); +} + static u32 s5h1420_getsymbolrate(struct s5h1420_state* state) { u64 val = 0; @@ -492,8 +510,8 @@ static int s5h1420_getfreqoffset(struct return val; } -static void s5h1420_setfec_inversion(struct s5h1420_state* state, - struct dvb_frontend_parameters *p) +static void s5h1420_setfec_inversion_compat(struct s5h1420_state* state, + struct dvb_frontend_parameters *p) { u8 inversion = 0; @@ -544,7 +562,61 @@ static void s5h1420_setfec_inversion(str } } -static fe_code_rate_t s5h1420_getfec(struct s5h1420_state* state) +static void s5h1420_setfec_inversion(struct s5h1420_state* state, + struct dvbfe_params *p) +{ + u8 inversion = 0; + + if (p->inversion == INVERSION_OFF) { + inversion = state->config->invert ? 0x08 : 0; + } else if (p->inversion == INVERSION_ON) { + inversion = state->config->invert ? 0 : 0x08; + } + + if ((p->delsys.dvbs.fec == DVBFE_FEC_AUTO) || + (p->inversion == INVERSION_AUTO)) { + + s5h1420_writereg(state, 0x30, 0x3f); + s5h1420_writereg(state, 0x31, 0x00 | inversion); + } else { + switch (p->delsys.dvbs.fec) { + case DVBFE_FEC_1_2: + s5h1420_writereg(state, 0x30, 0x01); + s5h1420_writereg(state, 0x31, 0x10 | inversion); + break; + + case DVBFE_FEC_2_3: + s5h1420_writereg(state, 0x30, 0x02); + s5h1420_writereg(state, 0x31, 0x11 | inversion); + break; + + case DVBFE_FEC_3_4: + s5h1420_writereg(state, 0x30, 0x04); + s5h1420_writereg(state, 0x31, 0x12 | inversion); + break; + + case DVBFE_FEC_5_6: + s5h1420_writereg(state, 0x30, 0x08); + s5h1420_writereg(state, 0x31, 0x13 | inversion); + break; + + case DVBFE_FEC_6_7: + s5h1420_writereg(state, 0x30, 0x10); + s5h1420_writereg(state, 0x31, 0x14 | inversion); + break; + + case DVBFE_FEC_7_8: + s5h1420_writereg(state, 0x30, 0x20); + s5h1420_writereg(state, 0x31, 0x15 | inversion); + break; + + default: + return; + } + } +} + +static fe_code_rate_t s5h1420_getfec_compat(struct s5h1420_state* state) { switch(s5h1420_readreg(state, 0x32) & 0x07) { case 0: @@ -569,6 +641,31 @@ static fe_code_rate_t s5h1420_getfec(str return FEC_NONE; } +static fe_code_rate_t s5h1420_getfec(struct s5h1420_state* state) +{ + switch(s5h1420_readreg(state, 0x32) & 0x07) { + case 0: + return DVBFE_FEC_1_2; + + case 1: + return DVBFE_FEC_2_3; + + case 2: + return DVBFE_FEC_3_4; + + case 3: + return DVBFE_FEC_5_6; + + case 4: + return DVBFE_FEC_6_7; + + case 5: + return DVBFE_FEC_7_8; + } + + return DVBFE_FEC_NONE; +} + static fe_spectral_inversion_t s5h1420_getinversion(struct s5h1420_state* state) { if (s5h1420_readreg(state, 0x32) & 0x08) @@ -594,9 +691,10 @@ static int s5h1420_set_frontend(struct d (state->fec_inner == p->u.qpsk.fec_inner) && (state->symbol_rate == p->u.qpsk.symbol_rate)) { - if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); - if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + if (fe->ops.tuner_ops.set_params_compat) { + fe->ops.tuner_ops.set_params_compat(fe, p); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); } if (fe->ops.tuner_ops.get_frequency) { u32 tmp; @@ -651,9 +749,104 @@ static int s5h1420_set_frontend(struct d s5h1420_writereg(state, 0x05, s5h1420_readreg(state, 0x05) | 1); /* set tuner PLL */ + if (fe->ops.tuner_ops.set_params_compat) { + fe->ops.tuner_ops.set_params_compat(fe, p); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + s5h1420_setfreqoffset(state, 0); + } + + /* set the reset of the parameters */ + s5h1420_setsymbolrate_compat(state, p); + s5h1420_setfec_inversion_compat(state, p); + + state->fec_inner = p->u.qpsk.fec_inner; + state->symbol_rate = p->u.qpsk.symbol_rate; + state->postlocked = 0; + state->tunedfreq = p->frequency; + return 0; +} + +static int s5h1420_set_params(struct dvb_frontend* fe, + struct dvbfe_params *p) +{ + struct s5h1420_state* state = fe->demodulator_priv; + int 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)); + memcpy(&fesettings.fe_params, 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->delsys.dvbs.fec) && + (state->symbol_rate == p->delsys.dvbs.symbol_rate)) { + + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, p); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + } + if (fe->ops.tuner_ops.get_frequency) { + u32 tmp; + fe->ops.tuner_ops.get_frequency(fe, &tmp); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + s5h1420_setfreqoffset(state, p->frequency - tmp); + } else { + s5h1420_setfreqoffset(state, 0); + } + return 0; + } + + /* first of all, software reset */ + s5h1420_reset(state); + + /* set s5h1420 fclk PLL according to desired symbol rate */ + if (p->delsys.dvbs.symbol_rate > 28000000) { + state->fclk = 88000000; + s5h1420_writereg(state, 0x03, 0x50); + s5h1420_writereg(state, 0x04, 0x40); + s5h1420_writereg(state, 0x05, 0xae); + } else if (p->delsys.dvbs.symbol_rate > 21000000) { + state->fclk = 59000000; + s5h1420_writereg(state, 0x03, 0x33); + s5h1420_writereg(state, 0x04, 0x40); + s5h1420_writereg(state, 0x05, 0xae); + } else { + state->fclk = 88000000; + s5h1420_writereg(state, 0x03, 0x50); + s5h1420_writereg(state, 0x04, 0x40); + s5h1420_writereg(state, 0x05, 0xac); + } + + /* set misc registers */ + s5h1420_writereg(state, 0x02, 0x00); + s5h1420_writereg(state, 0x06, 0x00); + s5h1420_writereg(state, 0x07, 0xb0); + s5h1420_writereg(state, 0x0a, 0xe7); + s5h1420_writereg(state, 0x0b, 0x78); + s5h1420_writereg(state, 0x0c, 0x48); + s5h1420_writereg(state, 0x0d, 0x6b); + s5h1420_writereg(state, 0x2e, 0x8e); + s5h1420_writereg(state, 0x35, 0x33); + s5h1420_writereg(state, 0x38, 0x01); + s5h1420_writereg(state, 0x39, 0x7d); + 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); + + /* start QPSK */ + s5h1420_writereg(state, 0x05, s5h1420_readreg(state, 0x05) | 1); + + /* set tuner PLL */ if (fe->ops.tuner_ops.set_params) { fe->ops.tuner_ops.set_params(fe, p); - if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); s5h1420_setfreqoffset(state, 0); } @@ -661,8 +854,8 @@ static int s5h1420_set_frontend(struct d s5h1420_setsymbolrate(state, p); s5h1420_setfec_inversion(state, p); - state->fec_inner = p->u.qpsk.fec_inner; - state->symbol_rate = p->u.qpsk.symbol_rate; + state->fec_inner = p->delsys.dvbs.fec; + state->symbol_rate = p->delsys.dvbs.symbol_rate; state->postlocked = 0; state->tunedfreq = p->frequency; return 0; @@ -676,7 +869,20 @@ static int s5h1420_get_frontend(struct d p->frequency = state->tunedfreq + s5h1420_getfreqoffset(state); p->inversion = s5h1420_getinversion(state); p->u.qpsk.symbol_rate = s5h1420_getsymbolrate(state); - p->u.qpsk.fec_inner = s5h1420_getfec(state); + p->u.qpsk.fec_inner = s5h1420_getfec_compat(state); + + return 0; +} + +static int s5h1420_get_params(struct dvb_frontend* fe, + struct dvbfe_params *p) +{ + struct s5h1420_state* state = fe->demodulator_priv; + + p->frequency = state->tunedfreq + s5h1420_getfreqoffset(state); + p->inversion = s5h1420_getinversion(state); + p->delsys.dvbs.symbol_rate = s5h1420_getsymbolrate(state); + p->delsys.dvbs.fec = s5h1420_getfec(state); return 0; } @@ -684,32 +890,59 @@ static int s5h1420_get_frontend(struct d static int s5h1420_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) { - 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; + if (fe->legacy) { + 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; + } } else { - fesettings->min_delay_ms = 200; - fesettings->step_size = (fesettings->parameters.u.qpsk.symbol_rate / 8000); - fesettings->max_drift = 18 * fesettings->step_size; + if (fesettings->fe_params.delsys.dvbs.symbol_rate > 20000000) { + fesettings->min_delay_ms = 50; + fesettings->step_size = 2000; + fesettings->max_drift = 8000; + } else if (fesettings->fe_params.delsys.dvbs.symbol_rate > 12000000) { + fesettings->min_delay_ms = 100; + fesettings->step_size = 1500; + fesettings->max_drift = 9000; + } else if (fesettings->fe_params.delsys.dvbs.symbol_rate > 8000000) { + fesettings->min_delay_ms = 100; + fesettings->step_size = 1000; + fesettings->max_drift = 8000; + } else if (fesettings->fe_params.delsys.dvbs.symbol_rate > 4000000) { + fesettings->min_delay_ms = 100; + fesettings->step_size = 500; + fesettings->max_drift = 7000; + } else if (fesettings->fe_params.delsys.dvbs.symbol_rate > 2000000) { + fesettings->min_delay_ms = 200; + fesettings->step_size = (fesettings->fe_params.delsys.dvbs.symbol_rate / 8000); + fesettings->max_drift = 14 * fesettings->step_size; + } else { + fesettings->min_delay_ms = 200; + fesettings->step_size = (fesettings->fe_params.delsys.dvbs.symbol_rate / 8000); + fesettings->max_drift = 18 * fesettings->step_size; + } } - return 0; } @@ -786,6 +1019,38 @@ error: return NULL; } +static struct dvbfe_info dvbs_info = { + .name = "Samsung S5H1420 DVB-S", + .delivery = DVBFE_DELSYS_DVBS, + .delsys = { + .dvbs.modulation = DVBFE_DELSYS_DVBS, + .dvbs.fec = DVBFE_FEC_1_2 | DVBFE_FEC_2_3 | + DVBFE_FEC_3_4 | DVBFE_FEC_5_6 | + DVBFE_FEC_7_8 | DVBFE_FEC_AUTO + }, + + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_step = 125, + .frequency_tolerance = 29500, + .symbol_rate_min = 1000000, + .symbol_rate_max = 45000000, +}; + +static int s5h1420_get_info(struct dvb_frontend *fe, struct dvbfe_info *fe_info) +{ + memcpy(fe_info, &dvbs_info, sizeof (dvbs_info)); + + return 0; +} + +static int s5h1420_get_delsys(struct dvb_frontend *fe, enum dvbfe_delsys *fe_delsys) +{ + *fe_delsys = DVBFE_DELSYS_DVBS; + + return 0; +} + static struct dvb_frontend_ops s5h1420_ops = { .info = { @@ -824,6 +1089,11 @@ static struct dvb_frontend_ops s5h1420_o .diseqc_send_burst = s5h1420_send_burst, .set_tone = s5h1420_set_tone, .set_voltage = s5h1420_set_voltage, + + .set_params = s5h1420_set_params, + .get_params = s5h1420_get_params, + .get_info = s5h1420_get_info, + .get_delsys = s5h1420_get_delsys, }; module_param(debug, int, 0644);
_______________________________________________ linux-dvb@xxxxxxxxxxx http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb