📄 stv0297_cs2.c
字号:
state->lastber = 0; if (state->config->pll_init) state->config->pll_init(fe); return 0;}static void stv0297_set_initdemod(struct stv0297_state *state, s32 offset){ u16 initdemod = div64( (s64) (state->config->demodfreq - offset) << 16 , state->config->fclk); u8 initdem[6]; deb_calc("demodfreq: %d, offset: %d, fclk: %d, initdemod: %d (%x)\n", state->config->demodfreq, offset, state->config->fclk, initdemod, initdemod); initdem[0] = initdemod & 0xff; initdem[1] = (initdemod >> 8) & 0xff; initdem[2] = 0x00; initdem[3] = 0x00; initdem[4] = 0x40; initdem[5] = 0x88; stv0297_writeregsI(state,INITDEM_0, initdem,6);}#define try(expr,num,sleep) \ for (i = 0; i < (num) && !(expr); i++) msleep(sleep);static int stv0297_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p){ struct stv0297_state *state = fe->demodulator_priv; int i; u8 equ_save[2]; fe_spectral_inversion_t inversion; switch (p->inversion) { case INVERSION_AUTO: /* fall through wanted */ case INVERSION_OFF: inversion = state->invert ? INVERSION_ON : INVERSION_OFF; break; case INVERSION_ON: inversion = state->invert ? INVERSION_OFF : INVERSION_ON; break; default: return -EINVAL; } deb_info("spectrum inversion: %s\n",inversion == INVERSION_ON ? "on" : "off"); stv0297_reset(fe); state->config->pll_set(fe, p);/* clear software interrupts */ stv0297_writeregI(state, CTRL_2, 0x00);/* set initial demodulation frequency */ stv0297_set_initdemod(state, 0);/* setup AGC */ stv0297_writeregI(state, WBAGC_3, 0x00);/* Wide Band AGC agc2sd initialisation: mid-range */ stv0297_writeregI(state, WBAGC_1, 0x00);// stv0297_writereg_maskI(state, WBAGC_2, 0x03, 0x01);/* Wide Band AGC1&AGC2 nofreeze */ stv0297_writereg_maskI(state, DELAGC_6, 0x7f, 0x00);/* PMF AGC accumulator reset */ stv0297_writereg_maskI(state, PMFAGC_1, 0x80, 0x80); stv0297_writeregI(state, PMFAGC_2, 0x00); stv0297_writeregI(state, PMFAGC_3, 0x00); stv0297_writereg_maskI(state, PMFAGC_4, 0x7f, 0x00);/* Force AGC ACQ low */ stv0297_writereg_maskI(state, WBAGC_3, 0x08, 0x00);/* Disable unlock forcing. */ stv0297_writereg_maskI(state, PMFAGC_1, 0x80, 0x00);/* setup STL * Phase clear */ stv0297_writereg_maskI(state, ST_LOOP10, 0x20, 0x20);/* STL integral path clear */ stv0297_writereg_maskI(state, ST_LOOP11, 0x02, 0x02);/* STL integral path clear release */ stv0297_writereg_maskI(state, ST_LOOP11, 0x02, 0x00);/* integral path enabled only */ stv0297_writereg_maskI(state, ST_LOOP11, 0x01, 0x00);/* direct path immediatly enabled */ stv0297_writereg_maskI(state, ST_LOOP10, 0x40, 0x40);/* disable frequency sweep */ stv0297_writereg_maskI(state, CRL_10, 0x01, 0x00);/* reset deinterleaver */ stv0297_writereg_maskI(state, CTRL_1, 0x01, 0x01); stv0297_writereg_maskI(state, CTRL_1, 0x01, 0x00);/* ??? */ stv0297_writereg_maskI(state, CTRL_3, 0x20, 0x20); stv0297_writereg_maskI(state, CTRL_3, 0x20, 0x00);/* Reed-Salomon clear */ stv0297_writereg_maskI(state, CTRL_3, 0x10, 0x10); stv0297_writereg_maskI(state, CTRL_3, 0x10, 0x00);/* Equalizer values capture */ stv0297_readregsI(state, EQU_0, equ_save, 2);/* reset equalizer */ stv0297_writereg_maskI(state, CTRL_4, 0x01, 0x01); stv0297_writereg_maskI(state, CTRL_4, 0x01, 0x00);/* Equalizer values restore */ stv0297_writeregsI(state, EQU_0, equ_save, 2);/* data comes from internal A/D */ stv0297_writereg_maskI(state, CTRL_7, 0x80, 0x00);/* set parameters */ stv0297_set_modulation(state, p->u.qam.modulation); stv0297_set_symbolrate(state, p->u.qam.symbol_rate); stv0297_set_crl(state, p, -130000); stv0297_set_inversion(state, inversion); stv0297_writereg_maskI(state, EQU_0, 0x0f, 0x09); stv0297_writeregI(state, EQU_1, 0x69);/* only disable corner detection for QAM256 and QAM128, otherwise, enable it */ if (p->u.qam.modulation == QAM_256 || p->u.qam.modulation == QAM_128) stv0297_writereg_maskI(state, CTRL_8, 0x08, 0x00); else stv0297_writereg_maskI(state, CTRL_8, 0x08, 0x08);/* Phase clear release */ stv0297_writereg_maskI(state, ST_LOOP10, 0x20, 0x00);/* Sweep Enable */ stv0297_writereg_maskI(state, CRL_10, 0x01, 0x01); msleep(10);/* Clear wide band AGC */ stv0297_writereg_maskI(state, WBAGC_3, 0x40, 0x40);/* enable wide band AGC */ stv0297_writereg_maskI(state, WBAGC_3, 0x10, WAGC_EN); deb_info("initialized - waiting for the locks now\n"); /* wait for WBAGC lock */ deb_info("waiting for WBAGC lock\n"); try(stv0297_readregI(state, WBAGC_3) & 0x08, 200, 10); if (i == 200) goto timeout; deb_info("WBAGC has lock\n"); msleep(20); /* wait for equalizer 1 lock */ deb_info("waiting for equalizer 1 lock\n"); try(stv0297_readregI(state, CTRL_2) & 0x04, 400, 10); if (i == 400) goto timeout; deb_info("equalizer 1 has lock\n"); /* wait for equalizer 2 lock and if it's stable */ deb_info("waiting for equalizer 2 lock\n"); try(stv0297_readregI(state, CTRL_2) & 0x08, 200, 10); if (i == 200) goto timeout; deb_info("equalizer 2 has lock\n"); msleep(20); if (!(stv0297_readregI(state, CTRL_2) & 0x08)) goto timeout; deb_info("equalizer 2 is stable\n"); /* we have modulation, do we have data */ deb_info("waiting for data lock\n"); try(stv0297_readregI(state,RS_DESC_15) & 0x80,5,10); if (i == 5) { /* try to invert the inversion during the next run */ deb_info("no data lock achieved, trying to invert the spectrum in the next run.\n"); state->invert = !state->invert; goto timeout; } deb_info("we have data lock\n");/* Turn off corner detection */ stv0297_writereg_maskI(state, CTRL_8,0x08, 0x00); /* success!! */ state->base_freq = p->frequency; return 0;timeout: deb_info("timed out\n"); stv0297_writereg_maskI(state, CRL_10, 0x01, 0x00); return 0;}static int stv0297_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p){ struct stv0297_state *state = fe->demodulator_priv; int reg_00, reg_83; reg_00 = stv0297_readregI(state, EQU_0); reg_83 = stv0297_readregI(state, CTRL_3); p->frequency = state->base_freq; if (reg_83 & 0x08) p->inversion = INVERSION_ON; else p->inversion = INVERSION_OFF; p->u.qam.symbol_rate = stv0297_get_symbolrate(state); p->u.qam.fec_inner = FEC_NONE; switch (reg_00 & 0x70) { case STV0297_QAM16: p->u.qam.modulation = QAM_16; break; case STV0297_QAM32: p->u.qam.modulation = QAM_32; break; case STV0297_QAM128: p->u.qam.modulation = QAM_128; break; case STV0297_QAM256: p->u.qam.modulation = QAM_256; break; case STV0297_QAM64: p->u.qam.modulation = QAM_64; break; } return 0;}static int stv0297_sleep(struct dvb_frontend *fe){ struct stv0297_state *state = fe->demodulator_priv; deb_info("stv0297 is going to bed.\n"); stv0297_writereg_maskI(state, CTRL_0, 1, 1); return 0;}static int stv0297_read_status(struct dvb_frontend *fe, fe_status_t * status){ struct stv0297_state *state = fe->demodulator_priv; u8 ctrl_2 = stv0297_readregI(state, CTRL_2); *status = 0;/* The following status assignments are only guesses, but we wanted to have a * kind of grade here */ if (stv0297_readregI(state, WBAGC_3) & 0x08) *status |= FE_HAS_SIGNAL; if (ctrl_2 & 0x04) *status |= FE_HAS_CARRIER; if (ctrl_2 & 0x08) *status |= FE_HAS_VITERBI; if (stv0297_readregI(state, RS_DESC_15) & 0x80) *status |= FE_HAS_SYNC | FE_HAS_LOCK; return 0;}static int stv0297_read_signal_strength(struct dvb_frontend *fe, u16 * strength){ struct stv0297_state *state = (struct stv0297_state *) fe->demodulator_priv; u8 STRENGTH[2]; stv0297_readregsI(state, WBAGC_1, STRENGTH, 2); *strength = (STRENGTH[1] & 0x03) << 8 | STRENGTH[0]; return 0;}static int stv0297_read_snr(struct dvb_frontend *fe, u16 * snr){ struct stv0297_state *state = (struct stv0297_state *) fe->demodulator_priv; u8 SNR[2]; stv0297_readregsI(state, EQU_7, SNR, 2); *snr = SNR[1] << 8 | SNR[0]; return 0;}static int stv0297_read_ber(struct dvb_frontend *fe, u32 * ber){ struct stv0297_state *state = (struct stv0297_state *) fe->demodulator_priv; u8 BER[3]; *ber = 0; stv0297_readregsI(state, BERT_0, BER, 3); if (!(BER[0] & 0x80)) { state->lastber = (BER[0] & 0x07 << 16) | (BER[2] << 8) | BER[1]; /* reset the BER counter */ BER[0] |= 0x80; BER[1] = BER[2] = 0x00; stv0297_writeregsI(state, BERT_0, BER, 3); } *ber = state->lastber; return 0;}static int stv0297_read_ucblocks(struct dvb_frontend *fe, u32 * ucblocks){ struct stv0297_state *state = fe->demodulator_priv; u8 block_count[6]; stv0297_writeregI(state,RS_DESC_15,0x03); /* freeze the counters */ stv0297_readregsI(state,RS_DESC_0,block_count,6); stv0297_writeregI(state,RS_DESC_15,0x02); /* clear the counters */ stv0297_writeregI(state,RS_DESC_15,0x01); /* re-enable the counters *//* LastBlockCount = (block_count[1] << 8) | block_count[0]; *//* LastCorrectedBlockCount = (block_count[3] << 8) | block_count[2]; */ *ucblocks = (block_count[5] << 8) | block_count[4]; return 0;}static void stv0297_release(struct dvb_frontend *fe){ struct stv0297_state *state = fe->demodulator_priv; kfree(state);}static struct dvb_frontend_ops stv0297_ops;struct dvb_frontend *stv0297_cs2_attach(const struct stv0297_config *config, struct i2c_adapter *i2c){ struct stv0297_state *state = NULL; /* allocate memory for the internal state */ state = kmalloc(sizeof(struct stv0297_state), GFP_KERNEL); if (state == NULL) goto error; /* setup the state */ state->config = config; state->i2c = i2c; memcpy(&state->ops, &stv0297_ops, sizeof(struct dvb_frontend_ops)); state->base_freq = 0; /* check if the demod is there */ if ((stv0297_readregI(state, CTRL_0) & 0x70) != 0x20) goto error; /* create dvb_frontend */ state->frontend.ops = &state->ops; state->frontend.demodulator_priv = state; return &state->frontend;error: kfree(state); return NULL;}static struct dvb_frontend_ops stv0297_ops = { .info = { .name = "ST STV0297 DVB-C", .type = FE_QAM, .frequency_min = 64000000, .frequency_max = 1300000000, .frequency_stepsize = 62500, .symbol_rate_min = 870000, .symbol_rate_max = 11700000, .caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | FE_CAN_QAM_128 | FE_CAN_QAM_256 | FE_CAN_FEC_AUTO}, .release = stv0297_release, .init = stv0297_init, .sleep = stv0297_sleep, .set_frontend = stv0297_set_frontend, .get_frontend = stv0297_get_frontend, .read_status = stv0297_read_status, .read_ber = stv0297_read_ber, .read_signal_strength = stv0297_read_signal_strength, .read_snr = stv0297_read_snr, .read_ucblocks = stv0297_read_ucblocks,};MODULE_DESCRIPTION("ST STV0297 DVB-C Demodulator driver");MODULE_AUTHOR("Dennis Noermann, Andrew de Quincey and Patrick Boettcher");MODULE_LICENSE("GPL");MODULE_VERSION("1.0");EXPORT_SYMBOL(stv0297_cs2_attach);EXPORT_SYMBOL(stv0297_cs2_enable_plli2c);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -