📄 tda10023.c
字号:
if (state->config->deltaf) { tda10023_inittab[80] = (state->config->deltaf & 0xff); tda10023_inittab[83] = (state->config->deltaf >> 8); } if (state->config->output_mode) tda10023_inittab[95] = state->config->output_mode; tda10023_writetab(state, tda10023_inittab); return 0;}static int tda10023_set_parameters (struct dvb_frontend *fe, struct dvb_frontend_parameters *p){ struct tda10023_state* state = fe->demodulator_priv; static int qamvals[6][6] = { // QAM LOCKTHR MSETH AREF AGCREFNYQ ERAGCNYQ_THD { (5<<2), 0x78, 0x8c, 0x96, 0x78, 0x4c }, // 4 QAM { (0<<2), 0x87, 0xa2, 0x91, 0x8c, 0x57 }, // 16 QAM { (1<<2), 0x64, 0x74, 0x96, 0x8c, 0x57 }, // 32 QAM { (2<<2), 0x46, 0x43, 0x6a, 0x6a, 0x44 }, // 64 QAM { (3<<2), 0x36, 0x34, 0x7e, 0x78, 0x4c }, // 128 QAM { (4<<2), 0x26, 0x23, 0x6c, 0x5c, 0x3c }, // 256 QAM }; int qam = p->u.qam.modulation; if (qam < 0 || qam > 5) return -EINVAL; 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); } tda10023_set_symbolrate (state, p->u.qam.symbol_rate); tda10023_writereg (state, 0x05, qamvals[qam][1]); tda10023_writereg (state, 0x08, qamvals[qam][2]); tda10023_writereg (state, 0x09, qamvals[qam][3]); tda10023_writereg (state, 0xb4, qamvals[qam][4]); tda10023_writereg (state, 0xb6, qamvals[qam][5]);// tda10023_writereg (state, 0x04, (p->inversion?0x12:0x32));// tda10023_writebit (state, 0x04, 0x60, (p->inversion?0:0x20)); tda10023_writebit (state, 0x04, 0x40, 0x40); tda10023_setup_reg0 (state, qamvals[qam][0]); return 0;}static int tda10023_read_status(struct dvb_frontend* fe, fe_status_t* status){ struct tda10023_state* state = fe->demodulator_priv; int sync; *status = 0; //0x11[1] == CARLOCK -> Carrier locked //0x11[2] == FSYNC -> Frame synchronisation //0x11[3] == FEL -> Front End locked //0x11[6] == NODVB -> DVB Mode Information sync = tda10023_readreg (state, 0x11); if (sync & 2) *status |= FE_HAS_SIGNAL|FE_HAS_CARRIER; if (sync & 4) *status |= FE_HAS_SYNC|FE_HAS_VITERBI; if (sync & 8) *status |= FE_HAS_LOCK; return 0;}static int tda10023_read_ber(struct dvb_frontend* fe, u32* ber){ struct tda10023_state* state = fe->demodulator_priv; u8 a,b,c; a=tda10023_readreg(state, 0x14); b=tda10023_readreg(state, 0x15); c=tda10023_readreg(state, 0x16)&0xf; tda10023_writebit (state, 0x10, 0xc0, 0x00); *ber = a | (b<<8)| (c<<16); return 0;}static int tda10023_read_signal_strength(struct dvb_frontend* fe, u16* strength){ struct tda10023_state* state = fe->demodulator_priv; u8 ifgain=tda10023_readreg(state, 0x2f); u16 gain = ((255-tda10023_readreg(state, 0x17))) + (255-ifgain)/16; // Max raw value is about 0xb0 -> Normalize to >0xf0 after 0x90 if (gain>0x90) gain=gain+2*(gain-0x90); if (gain>255) gain=255; *strength = (gain<<8)|gain; return 0;}static int tda10023_read_snr(struct dvb_frontend* fe, u16* snr){ struct tda10023_state* state = fe->demodulator_priv; u8 quality = ~tda10023_readreg(state, 0x18); *snr = (quality << 8) | quality; return 0;}static int tda10023_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks){ struct tda10023_state* state = fe->demodulator_priv; u8 a,b,c,d; a= tda10023_readreg (state, 0x74); b= tda10023_readreg (state, 0x75); c= tda10023_readreg (state, 0x76); d= tda10023_readreg (state, 0x77); *ucblocks = a | (b<<8)|(c<<16)|(d<<24); tda10023_writebit (state, 0x10, 0x20,0x00); tda10023_writebit (state, 0x10, 0x20,0x20); tda10023_writebit (state, 0x13, 0x01, 0x00); return 0;}static int tda10023_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p){ struct tda10023_state* state = fe->demodulator_priv; int sync,inv; s8 afc = 0; sync = tda10023_readreg(state, 0x11); afc = tda10023_readreg(state, 0x19); inv = tda10023_readreg(state, 0x04); if (verbose) { /* AFC only valid when carrier has been recovered */ printk(sync & 2 ? "DVB: TDA10023(%d): AFC (%d) %dHz\n" : "DVB: TDA10023(%d): [AFC (%d) %dHz]\n", state->frontend.dvb->num, afc, -((s32)p->u.qam.symbol_rate * afc) >> 10); } p->inversion = (inv&0x20?0:1); p->u.qam.modulation = ((state->reg0 >> 2) & 7) + QAM_16; p->u.qam.fec_inner = FEC_NONE; p->frequency = ((p->frequency + 31250) / 62500) * 62500; if (sync & 2) p->frequency -= ((s32)p->u.qam.symbol_rate * afc) >> 10; return 0;}static int tda10023_sleep(struct dvb_frontend* fe){ struct tda10023_state* state = fe->demodulator_priv; tda10023_writereg (state, 0x1b, 0x02); /* pdown ADC */ tda10023_writereg (state, 0x00, 0x80); /* standby */ return 0;}static int tda10023_i2c_gate_ctrl(struct dvb_frontend* fe, int enable){ struct tda10023_state* state = fe->demodulator_priv; if (enable) { lock_tuner(state); } else { unlock_tuner(state); } return 0;}static void tda10023_release(struct dvb_frontend* fe){ struct tda10023_state* state = fe->demodulator_priv; kfree(state);}static struct dvb_frontend_ops tda10023_ops;struct dvb_frontend *tda10023_attach(const struct tda10023_config *config, struct i2c_adapter *i2c, u8 pwm){ struct tda10023_state* state = NULL; /* allocate memory for the internal state */ state = kzalloc(sizeof(struct tda10023_state), GFP_KERNEL); if (state == NULL) goto error; /* setup the state */ state->config = config; state->i2c = i2c; /* wakeup if in standby */ tda10023_writereg (state, 0x00, 0x33); /* check if the demod is there */ if ((tda10023_readreg(state, 0x1a) & 0xf0) != 0x70) goto error; /* create dvb_frontend */ memcpy(&state->frontend.ops, &tda10023_ops, sizeof(struct dvb_frontend_ops)); state->pwm = pwm; state->reg0 = REG0_INIT_VAL; if (state->config->xtal) { state->xtal = state->config->xtal; state->pll_m = state->config->pll_m; state->pll_p = state->config->pll_p; state->pll_n = state->config->pll_n; } else { /* set default values if not defined in config */ state->xtal = 28920000; state->pll_m = 8; state->pll_p = 4; state->pll_n = 1; } /* calc sysclk */ state->sysclk = (state->xtal * state->pll_m / \ (state->pll_n * state->pll_p)); state->frontend.ops.info.symbol_rate_min = (state->sysclk/2)/64; state->frontend.ops.info.symbol_rate_max = (state->sysclk/2)/4; dprintk("DVB: TDA10023 %s: xtal:%d pll_m:%d pll_p:%d pll_n:%d\n", __func__, state->xtal, state->pll_m, state->pll_p, state->pll_n); state->frontend.demodulator_priv = state; return &state->frontend;error: kfree(state); return NULL;}static struct dvb_frontend_ops tda10023_ops = { .info = { .name = "Philips TDA10023 DVB-C", .type = FE_QAM, .frequency_stepsize = 62500, .frequency_min = 47000000, .frequency_max = 862000000, .symbol_rate_min = 0, /* set in tda10023_attach */ .symbol_rate_max = 0, /* set in tda10023_attach */ #if 0 .frequency_tolerance = ???, .symbol_rate_tolerance = ???, /* ppm */ /* == 8% (spec p. 5) */ #endif .caps = 0x400 | //FE_CAN_QAM_4 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 = tda10023_release, .init = tda10023_init, .sleep = tda10023_sleep, .i2c_gate_ctrl = tda10023_i2c_gate_ctrl, .set_frontend = tda10023_set_parameters, .get_frontend = tda10023_get_frontend, .read_status = tda10023_read_status, .read_ber = tda10023_read_ber, .read_signal_strength = tda10023_read_signal_strength, .read_snr = tda10023_read_snr, .read_ucblocks = tda10023_read_ucblocks,};MODULE_DESCRIPTION("Philips TDA10023 DVB-C demodulator driver");MODULE_AUTHOR("Georg Acher, Hartmut Birr");MODULE_LICENSE("GPL");EXPORT_SYMBOL(tda10023_attach);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -