--- v4l-dvb/linux/drivers/media/dvb/frontends/sp887x.c 2006-06-30 19:59:10.000000000 +0400 +++ mp-bc1/linux/drivers/media/dvb/frontends/sp887x.c 2006-07-23 11:40:21.000000000 +0400 @@ -210,7 +210,7 @@ static int sp887x_initial_setup (struct return 0; }; -static int configure_reg0xc05 (struct dvb_frontend_parameters *p, u16 *reg0xc05) +static int configure_reg0xc05_compat(struct dvb_frontend_parameters *p, u16 *reg0xc05) { int known_parameters = 1; @@ -281,6 +281,82 @@ static int configure_reg0xc05 (struct dv return 0; } +static int configure_reg0xc05(struct dvbfe_params *p, u16 *reg0xc05) +{ + int known_parameters = 1; + + *reg0xc05 = 0x000; + + switch (p->delsys.dvbt.constellation) { + case DVBFE_MOD_QPSK: + break; + case DVBFE_MOD_QAM16: + *reg0xc05 |= (1 << 10); + break; + case DVBFE_MOD_QAM64: + *reg0xc05 |= (2 << 10); + break; + case DVBFE_MOD_QAMAUTO: + known_parameters = 0; + break; + default: + return -EINVAL; + }; + + switch (p->delsys.dvbt.hierarchy) { + case DVBFE_HIERARCHY_OFF: + break; + case DVBFE_HIERARCHY_ON: + break; + switch (p->delsys.dvbt.alpha) { + case DVBFE_ALPHA_1: + *reg0xc05 |= (1 << 7); + break; + case DVBFE_ALPHA_2: + *reg0xc05 |= (2 << 7); + break; + case DVBFE_ALPHA_4: + *reg0xc05 |= (3 << 7); + break; + } + break; + case DVBFE_HIERARCHY_AUTO: + known_parameters = 0; + break; + default: + return -EINVAL; + }; + + switch (p->delsys.dvbt.code_rate_HP) { + case DVBFE_FEC_1_2: + break; + case DVBFE_FEC_2_3: + *reg0xc05 |= (1 << 3); + break; + case DVBFE_FEC_3_4: + *reg0xc05 |= (2 << 3); + break; + case DVBFE_FEC_5_6: + *reg0xc05 |= (3 << 3); + break; + case DVBFE_FEC_7_8: + *reg0xc05 |= (4 << 3); + break; + case DVBFE_FEC_AUTO: + known_parameters = 0; + break; + default: + return -EINVAL; + }; + + if (known_parameters) + *reg0xc05 |= (2 << 1); /* use specified parameters */ + else + *reg0xc05 |= (1 << 1); /* enable autoprobing */ + + return 0; +} + /** * estimates division of two 24bit numbers, * derived from the ves1820/stv0299 driver code @@ -303,9 +379,9 @@ static void divide (int n, int d, int *q } } -static void sp887x_correct_offsets (struct sp887x_state* state, - struct dvb_frontend_parameters *p, - int actual_freq) +static void sp887x_correct_offsets_compat(struct sp887x_state* state, + struct dvb_frontend_parameters *p, + int actual_freq) { static const u32 srate_correction [] = { 1879617, 4544878, 8098561 }; int bw_index = p->u.ofdm.bandwidth - BANDWIDTH_8_MHZ; @@ -334,6 +410,38 @@ static void sp887x_correct_offsets (stru sp887x_writereg(state, 0x30a, frequency_shift & 0xfff); } +static void sp887x_correct_offsets(struct sp887x_state* state, + struct dvbfe_params *p, + int actual_freq) +{ + static const u32 srate_correction [] = { 1879617, 0, 4544878, 8098561, 0 }; + + int bw_index = p->delsys.dvbt.bandwidth - DVBFE_BANDWIDTH_8_MHZ; + int freq_offset = actual_freq - p->frequency; + int sysclock = 61003; //[kHz] + int ifreq = 36000000; + int freq; + int frequency_shift; + + if (p->inversion == INVERSION_ON) + freq = ifreq - freq_offset; + else + freq = ifreq + freq_offset; + + divide(freq / 333, sysclock, NULL, &frequency_shift); + + if (p->inversion == INVERSION_ON) + frequency_shift = -frequency_shift; + + /* sample rate correction */ + sp887x_writereg(state, 0x319, srate_correction[fls(bw_index)] >> 12); + sp887x_writereg(state, 0x31a, srate_correction[fls(bw_index)] & 0xfff); + + /* carrier offset correction */ + sp887x_writereg(state, 0x309, frequency_shift >> 12); + sp887x_writereg(state, 0x30a, frequency_shift & 0xfff); +} + static int sp887x_setup_frontend_parameters (struct dvb_frontend* fe, struct dvb_frontend_parameters *p) { @@ -346,15 +454,16 @@ static int sp887x_setup_frontend_paramet p->u.ofdm.bandwidth != BANDWIDTH_6_MHZ) return -EINVAL; - if ((err = configure_reg0xc05(p, ®0xc05))) + if ((err = configure_reg0xc05_compat(p, ®0xc05))) return err; sp887x_microcontroller_stop(state); /* setup the 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.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) { fe->ops.tuner_ops.get_frequency(fe, &actual_freq); @@ -366,7 +475,7 @@ static int sp887x_setup_frontend_paramet /* read status reg in order to clear <pending irqs */ sp887x_readreg(state, 0x200); - sp887x_correct_offsets(state, p, actual_freq); + sp887x_correct_offsets_compat(state, p, actual_freq); /* filter for 6/7/8 Mhz channel */ if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ) @@ -578,6 +687,105 @@ error: return NULL; } +static struct dvbfe_info dvbt_info = { + .name = "Spase SP887x DVB-T", + .delivery = DVBFE_DELSYS_DVBT, + .delsys = { + .dvbt.modulation = DVBFE_MOD_OFDM, + .dvbt.stream_priority = DVBFE_STREAM_PRIORITY_HP | + DVBFE_STREAM_PRIORITY_LP, + }, + + .frequency_min = 50500000, + .frequency_max = 858000000, + .frequency_step = 166666, +}; + +static int sp887x_set_params(struct dvb_frontend* fe, + struct dvbfe_params *p) +{ + struct sp887x_state* state = fe->demodulator_priv; + int actual_freq, err; + u16 val, reg0xc05; + + if (p->delsys.dvbt.bandwidth != DVBFE_BANDWIDTH_8_MHZ && + p->delsys.dvbt.bandwidth != DVBFE_BANDWIDTH_7_MHZ && + p->delsys.dvbt.bandwidth != DVBFE_BANDWIDTH_6_MHZ) + return -EINVAL; + + if ((err = configure_reg0xc05(p, ®0xc05))) + return err; + + sp887x_microcontroller_stop(state); + + /* setup the 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.tuner_ops.get_frequency) { + fe->ops.tuner_ops.get_frequency(fe, &actual_freq); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + } else { + actual_freq = p->frequency; + } + + /* read status reg in order to clear <pending irqs */ + sp887x_readreg(state, 0x200); + + sp887x_correct_offsets(state, p, actual_freq); + + /* filter for 6/7/8 Mhz channel */ + if (p->delsys.dvbt.bandwidth == DVBFE_BANDWIDTH_6_MHZ) + val = 2; + else if (p->delsys.dvbt.bandwidth == DVBFE_BANDWIDTH_7_MHZ) + val = 1; + else + val = 0; + + sp887x_writereg(state, 0x311, val); + + /* scan order: 2k first = 0, 8k first = 1 */ + if (p->delsys.dvbt.transmission_mode == DVBFE_TRANSMISSION_MODE_2K) + sp887x_writereg(state, 0x338, 0x000); + else + sp887x_writereg(state, 0x338, 0x001); + + sp887x_writereg(state, 0xc05, reg0xc05); + + if (p->delsys.dvbt.bandwidth == DVBFE_BANDWIDTH_6_MHZ) + val = 2 << 3; + else if (p->delsys.dvbt.bandwidth == DVBFE_BANDWIDTH_7_MHZ) + val = 3 << 3; + else + val = 0 << 3; + + /* enable OFDM and SAW bits as lock indicators in sync register 0xf17, + * optimize algorithm for given bandwidth... + */ + sp887x_writereg(state, 0xf14, 0x160 | val); + sp887x_writereg(state, 0xf15, 0x000); + + sp887x_microcontroller_start(state); + return 0; +} + +static int sp887x_get_info(struct dvb_frontend *fe, struct dvbfe_info *fe_info) +{ + memcpy(fe_info, &dvbt_info, sizeof (dvbt_info)); + + return 0; +} + +static int sp887x_get_delsys(struct dvb_frontend *fe, enum dvbfe_delsys *fe_delsys) +{ + *fe_delsys = DVBFE_DELSYS_DVBT; + + return 0; +} + static struct dvb_frontend_ops sp887x_ops = { .info = { @@ -606,6 +814,10 @@ static struct dvb_frontend_ops sp887x_op .read_signal_strength = sp887x_read_signal_strength, .read_snr = sp887x_read_snr, .read_ucblocks = sp887x_read_ucblocks, + + .set_params = sp887x_set_params, + .get_info = sp887x_get_info, + .get_delsys = sp887x_get_delsys, }; module_param(debug, int, 0644);
_______________________________________________ linux-dvb@xxxxxxxxxxx http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb