--- v4l-dvb/linux/drivers/media/dvb/frontends/cx24123.c 2006-06-30 19:59:10.000000000 +0400 +++ mp-bc1/linux/drivers/media/dvb/frontends/cx24123.c 2006-07-23 11:37:39.000000000 +0400 @@ -325,7 +325,62 @@ static int cx24123_get_inversion(struct return 0; } -static int cx24123_set_fec(struct cx24123_state* state, fe_code_rate_t fec) +static int cx24123_set_fec(struct cx24123_state* state, enum dvbfe_fec fec) +{ + u8 nom_reg = cx24123_readreg(state, 0x0e) & ~0x07; + + if ( (fec < DVBFE_FEC_NONE) || (fec > DVBFE_FEC_AUTO) ) + fec = DVBFE_FEC_AUTO; + + switch (fec) { + case DVBFE_FEC_1_2: + dprintk("%s: set FEC to 1/2\n",__FUNCTION__); + cx24123_writereg(state, 0x0e, nom_reg | 0x01); + cx24123_writereg(state, 0x0f, 0x02); + break; + case DVBFE_FEC_2_3: + dprintk("%s: set FEC to 2/3\n",__FUNCTION__); + cx24123_writereg(state, 0x0e, nom_reg | 0x02); + cx24123_writereg(state, 0x0f, 0x04); + break; + case DVBFE_FEC_3_4: + dprintk("%s: set FEC to 3/4\n",__FUNCTION__); + cx24123_writereg(state, 0x0e, nom_reg | 0x03); + cx24123_writereg(state, 0x0f, 0x08); + break; + case DVBFE_FEC_4_5: + dprintk("%s: set FEC to 4/5\n",__FUNCTION__); + cx24123_writereg(state, 0x0e, nom_reg | 0x04); + cx24123_writereg(state, 0x0f, 0x10); + break; + case DVBFE_FEC_5_6: + dprintk("%s: set FEC to 5/6\n",__FUNCTION__); + cx24123_writereg(state, 0x0e, nom_reg | 0x05); + cx24123_writereg(state, 0x0f, 0x20); + break; + case DVBFE_FEC_6_7: + dprintk("%s: set FEC to 6/7\n",__FUNCTION__); + cx24123_writereg(state, 0x0e, nom_reg | 0x06); + cx24123_writereg(state, 0x0f, 0x40); + break; + case DVBFE_FEC_7_8: + dprintk("%s: set FEC to 7/8\n",__FUNCTION__); + cx24123_writereg(state, 0x0e, nom_reg | 0x07); + cx24123_writereg(state, 0x0f, 0x80); + break; + case DVBFE_FEC_AUTO: + dprintk("%s: set FEC to auto\n",__FUNCTION__); + cx24123_writereg(state, 0x0f, 0xfe); + break; + default: + return -EOPNOTSUPP; + } + + return 0; +} + +static int cx24123_set_fec_compat(struct cx24123_state* state, + fe_code_rate_t fec) { u8 nom_reg = cx24123_readreg(state, 0x0e) & ~0x07; @@ -379,7 +434,7 @@ static int cx24123_set_fec(struct cx2412 return 0; } -static int cx24123_get_fec(struct cx24123_state* state, fe_code_rate_t *fec) +static int cx24123_get_fec_compat(struct cx24123_state* state, fe_code_rate_t *fec) { int ret; @@ -418,6 +473,46 @@ static int cx24123_get_fec(struct cx2412 return 0; } +static int cx24123_get_fec(struct cx24123_state* state, + enum dvbfe_fec *fec) +{ + int ret; + + ret = cx24123_readreg (state, 0x1b); + if (ret < 0) + return ret; + ret = ret & 0x07; + + switch (ret) { + case 1: + *fec = DVBFE_FEC_1_2; + break; + case 2: + *fec = DVBFE_FEC_2_3; + break; + case 3: + *fec = DVBFE_FEC_3_4; + break; + case 4: + *fec = DVBFE_FEC_4_5; + break; + case 5: + *fec = DVBFE_FEC_5_6; + break; + case 6: + *fec = DVBFE_FEC_6_7; + break; + case 7: + *fec = DVBFE_FEC_7_8; + break; + default: + /* this can happen when there's no lock */ + *fec = DVBFE_FEC_NONE; + } + + return 0; +} + /* Approximation of closest integer of log2(a/b). It actually gives the lowest integer i such that 2^i >= round(a/b) */ static u32 cx24123_int_log2(u32 a, u32 b) @@ -507,7 +602,8 @@ static int cx24123_set_symbolrate(struct * Based on the required frequency and symbolrate, the tuner AGC has to be configured * and the correct band selected. Calculate those values */ -static int cx24123_pll_calculate(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int cx24123_pll_calculate_compat(struct dvb_frontend* fe, + struct dvb_frontend_parameters *p) { struct cx24123_state *state = fe->demodulator_priv; u32 ndiv = 0, adiv = 0, vco_div = 0; @@ -569,11 +665,76 @@ static int cx24123_pll_calculate(struct return 0; } +static int cx24123_pll_calculate(struct dvb_frontend* fe, + struct dvbfe_params *p) +{ + struct cx24123_state *state = fe->demodulator_priv; + u32 ndiv = 0, adiv = 0, vco_div = 0; + int i = 0; + int pump = 2; + int band = 0; + int num_bands = sizeof (cx24123_bandselect_vals) / + sizeof(cx24123_bandselect_vals[0]); + + /* Defaults for low freq, low rate */ + state->VCAarg = cx24123_AGC_vals[0].VCAprogdata; + state->VGAarg = cx24123_AGC_vals[0].VGAprogdata; + state->bandselectarg = cx24123_bandselect_vals[0].progdata; + vco_div = cx24123_bandselect_vals[0].VCOdivider; + + /* For the given symbol rate, determine the VCA, VGA and FILTUNE programming bits */ + for (i = 0; i < sizeof(cx24123_AGC_vals) / sizeof(cx24123_AGC_vals[0]); i++) + { + if ((cx24123_AGC_vals[i].symbolrate_low <= p->delsys.dvbs.symbol_rate) && + (cx24123_AGC_vals[i].symbolrate_high >= p->delsys.dvbs.symbol_rate) ) { + state->VCAarg = cx24123_AGC_vals[i].VCAprogdata; + state->VGAarg = cx24123_AGC_vals[i].VGAprogdata; + state->FILTune = cx24123_AGC_vals[i].FILTune; + } + } + + /* determine the band to use */ + if(force_band < 1 || force_band > num_bands) + { + for (i = 0; i < num_bands; i++) + { + if ((cx24123_bandselect_vals[i].freq_low <= p->frequency) && + (cx24123_bandselect_vals[i].freq_high >= p->frequency) ) + band = i; + } + } + else + band = force_band - 1; + + state->bandselectarg = cx24123_bandselect_vals[band].progdata; + vco_div = cx24123_bandselect_vals[band].VCOdivider; + + /* determine the charge pump current */ + if ( p->frequency < (cx24123_bandselect_vals[band].freq_low + cx24123_bandselect_vals[band].freq_high)/2 ) + pump = 0x01; + else + pump = 0x02; + + /* Determine the N/A dividers for the requested lband freq (in kHz). */ + /* Note: the reference divider R=10, frequency is in KHz, XTAL is in Hz */ + ndiv = ( ((p->frequency * vco_div * 10) / (2 * XTAL / 1000)) / 32) & 0x1ff; + adiv = ( ((p->frequency * vco_div * 10) / (2 * XTAL / 1000)) % 32) & 0x1f; + + if (adiv == 0) + ndiv++; + + /* control bits 11, refdiv 11, charge pump polarity 1, charge pump current, ndiv, adiv */ + state->pllarg = (3 << 19) | (3 << 17) | (1 << 16) | (pump << 14) | (ndiv << 5) | adiv; + + return 0; +} + /* * Tuner data is 21 bits long, must be left-aligned in data. * Tuner cx24109 is written through a dedicated 3wire interface on the demod chip. */ -static int cx24123_pll_writereg(struct dvb_frontend* fe, struct dvb_frontend_parameters *p, u32 data) +//static int cx24123_pll_writereg(struct dvb_frontend* fe, struct dvb_frontend_parameters *p, u32 data) +static int cx24123_pll_writereg(struct dvb_frontend* fe, u32 data) { struct cx24123_state *state = fe->demodulator_priv; unsigned long timeout; @@ -626,7 +787,40 @@ static int cx24123_pll_writereg(struct d return 0; } -static int cx24123_pll_tune(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int cx24123_pll_tune_compat(struct dvb_frontend* fe, + struct dvb_frontend_parameters *p) +{ + struct cx24123_state *state = fe->demodulator_priv; + u8 val; + + dprintk("frequency=%i\n", p->frequency); + + if (cx24123_pll_calculate_compat(fe, p) != 0) { + printk("%s: cx24123_pll_calcutate failed\n",__FUNCTION__); + return -EINVAL; + } + + /* Write the new VCO/VGA */ + cx24123_pll_writereg(fe, state->VCAarg); + cx24123_pll_writereg(fe, state->VGAarg); + + /* Write the new bandselect and pll args */ + cx24123_pll_writereg(fe, state->bandselectarg); + cx24123_pll_writereg(fe, state->pllarg); + + /* set the FILTUNE voltage */ + val = cx24123_readreg(state, 0x28) & ~0x3; + cx24123_writereg(state, 0x27, state->FILTune >> 2); + cx24123_writereg(state, 0x28, val | (state->FILTune & 0x3)); + + dprintk("%s: pll tune VCA=%d, band=%d, pll=%d\n",__FUNCTION__,state->VCAarg, + state->bandselectarg,state->pllarg); + + return 0; +} + +static int cx24123_pll_tune(struct dvb_frontend* fe, + struct dvbfe_params *p) { struct cx24123_state *state = fe->demodulator_priv; u8 val; @@ -639,12 +833,12 @@ static int cx24123_pll_tune(struct dvb_f } /* Write the new VCO/VGA */ - cx24123_pll_writereg(fe, p, state->VCAarg); - cx24123_pll_writereg(fe, p, state->VGAarg); + cx24123_pll_writereg(fe, state->VCAarg); + cx24123_pll_writereg(fe, state->VGAarg); /* Write the new bandselect and pll args */ - cx24123_pll_writereg(fe, p, state->bandselectarg); - cx24123_pll_writereg(fe, p, state->pllarg); + cx24123_pll_writereg(fe, state->bandselectarg); + cx24123_pll_writereg(fe, state->pllarg); /* set the FILTUNE voltage */ val = cx24123_readreg(state, 0x28) & ~0x3; @@ -876,9 +1070,9 @@ static int cx24123_set_frontend(struct d state->currentsymbolrate = p->u.qpsk.symbol_rate; cx24123_set_inversion(state, p->inversion); - cx24123_set_fec(state, p->u.qpsk.fec_inner); + cx24123_set_fec_compat(state, p->u.qpsk.fec_inner); cx24123_set_symbolrate(state, p->u.qpsk.symbol_rate); - cx24123_pll_tune(fe, p); + cx24123_pll_tune_compat(fe, p); /* Enable automatic aquisition and reset cycle */ cx24123_writereg(state, 0x03, (cx24123_readreg(state, 0x03) | 0x07)); @@ -898,7 +1092,7 @@ static int cx24123_get_frontend(struct d printk("%s: Failed to get inversion status\n",__FUNCTION__); return -EREMOTEIO; } - if (cx24123_get_fec(state, &p->u.qpsk.fec_inner) != 0) { + if (cx24123_get_fec_compat(state, &p->u.qpsk.fec_inner) != 0) { printk("%s: Failed to get fec status\n",__FUNCTION__); return -EREMOTEIO; } @@ -987,6 +1181,93 @@ error: return NULL; } +static struct dvbfe_info dvbs_info = { + .name = "Conexant CX24123 DVB-S", + .delivery = DVBFE_DELSYS_DVBS, + .delsys = { + .dvbs.modulation = DVBFE_MOD_QPSK, + .dvbs.fec = DVBFE_FEC_1_2 | DVBFE_FEC_2_3 | + DVBFE_FEC_3_4 | DVBFE_FEC_4_5 | + DVBFE_FEC_5_6 | DVBFE_FEC_6_7 | + DVBFE_FEC_7_8 | DVBFE_FEC_AUTO + }, + + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_step = 1011, + .frequency_tolerance = 5000, + .symbol_rate_min = 1000000, + .symbol_rate_max = 45000000 +}; + +static int cx24123_set_params(struct dvb_frontend* fe, + struct dvbfe_params *p) +{ + struct cx24123_state *state = fe->demodulator_priv; + + dprintk("%s: set_frontend\n",__FUNCTION__); + + if (state->config->set_ts_params) + state->config->set_ts_params(fe, 0); + + state->currentfreq = p->frequency; + state->currentsymbolrate = p->delsys.dvbs.symbol_rate; + + cx24123_set_inversion(state, p->inversion); + cx24123_set_fec(state, p->delsys.dvbs.fec); + cx24123_set_symbolrate(state, p->delsys.dvbs.symbol_rate); + cx24123_pll_tune(fe, p); + + /* Enable automatic aquisition and reset cycle */ + cx24123_writereg(state, 0x03, (cx24123_readreg(state, 0x03) | 0x07)); + cx24123_writereg(state, 0x00, 0x10); + cx24123_writereg(state, 0x00, 0); + + return 0; +} + +static int cx24123_get_params(struct dvb_frontend* fe, + struct dvbfe_params *p) +{ + struct cx24123_state *state = fe->demodulator_priv; + + dprintk("%s: get_frontend\n",__FUNCTION__); + + if (cx24123_get_inversion(state, &p->inversion) != 0) { + printk("%s: Failed to get inversion status\n",__FUNCTION__); + return -EREMOTEIO; + } + if (cx24123_get_fec(state, &p->delsys.dvbs.fec) != 0) { + printk("%s: Failed to get fec status\n",__FUNCTION__); + return -EREMOTEIO; + } + p->frequency = state->currentfreq; + p->delsys.dvbs.symbol_rate = state->currentsymbolrate; + + return 0; +} + +static int cx24123_get_info(struct dvb_frontend *fe, + struct dvbfe_info *fe_info) +{ + memcpy(fe_info, &dvbs_info, sizeof (dvbs_info)); + + return 0; +} + +static int cx24123_get_delsys(struct dvb_frontend *fe, + enum dvbfe_delsys *fe_delsys) +{ + *fe_delsys = DVBFE_DELSYS_DVBS; + + return 0; +} + +static enum dvbfe_algo cx24123_get_algo(struct dvb_frontend *fe) +{ + return DVBFE_ALGO_RECOVERY; +} + static struct dvb_frontend_ops cx24123_ops = { .info = { @@ -1019,6 +1300,12 @@ static struct dvb_frontend_ops cx24123_o .diseqc_send_burst = cx24123_diseqc_send_burst, .set_tone = cx24123_set_tone, .set_voltage = cx24123_set_voltage, + + .set_params = cx24123_set_params, + .get_params = cx24123_get_params, + .get_info = cx24123_get_info, + .get_delsys = cx24123_get_delsys, + .get_frontend_algo = cx24123_get_algo, }; module_param(debug, int, 0644);
_______________________________________________ linux-dvb@xxxxxxxxxxx http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb