📄 tda10048.c
字号:
break; case 3: p->code_rate_LP = FEC_5_6; break; case 4: p->code_rate_LP = FEC_7_8; break; } val = tda10048_readreg(state, TDA10048_OUT_CONF1); switch ((val & 0x0c) >> 2) { case 0: p->guard_interval = GUARD_INTERVAL_1_32; break; case 1: p->guard_interval = GUARD_INTERVAL_1_16; break; case 2: p->guard_interval = GUARD_INTERVAL_1_8; break; case 3: p->guard_interval = GUARD_INTERVAL_1_4; break; } switch (val & 0x02) { case 0: p->transmission_mode = TRANSMISSION_MODE_2K; break; case 1: p->transmission_mode = TRANSMISSION_MODE_8K; break; } return 0;}static int tda10048_i2c_gate_ctrl(struct dvb_frontend *fe, int enable){ struct tda10048_state *state = fe->demodulator_priv; dprintk(1, "%s(%d)\n", __func__, enable); if (enable) return tda10048_writereg(state, TDA10048_CONF_C4_1, tda10048_readreg(state, TDA10048_CONF_C4_1) | 0x02); else return tda10048_writereg(state, TDA10048_CONF_C4_1, tda10048_readreg(state, TDA10048_CONF_C4_1) & 0xfd);}static int tda10048_output_mode(struct dvb_frontend *fe, int serial){ struct tda10048_state *state = fe->demodulator_priv; dprintk(1, "%s(%d)\n", __func__, serial); /* Ensure pins are out of tri-state */ tda10048_writereg(state, TDA10048_CONF_TRISTATE1, 0x21); tda10048_writereg(state, TDA10048_CONF_TRISTATE2, 0x00); if (serial) { tda10048_writereg(state, TDA10048_IC_MODE, 0x80 | 0x20); tda10048_writereg(state, TDA10048_CONF_TS2, 0xc0); } else { tda10048_writereg(state, TDA10048_IC_MODE, 0x00); tda10048_writereg(state, TDA10048_CONF_TS2, 0x01); } return 0;}/* Talk to the demod, set the FEC, GUARD, QAM settings etc *//* TODO: Support manual tuning with specific params */static int tda10048_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p){ struct tda10048_state *state = fe->demodulator_priv; dprintk(1, "%s(frequency=%d)\n", __func__, p->frequency); if (fe->ops.tuner_ops.set_params) { if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); fe->ops.tuner_ops.set_params(fe, p); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } /* Enable demod TPS auto detection and begin acquisition */ tda10048_writereg(state, TDA10048_AUTO, 0x57); return 0;}/* Establish sane defaults and load firmware. */static int tda10048_init(struct dvb_frontend *fe){ struct tda10048_state *state = fe->demodulator_priv; int ret = 0, i; dprintk(1, "%s()\n", __func__); /* Apply register defaults */ for (i = 0; i < ARRAY_SIZE(init_tab); i++) tda10048_writereg(state, init_tab[i].reg, init_tab[i].data); if (state->fwloaded == 0) ret = tda10048_firmware_upload(fe); /* Set either serial or parallel */ tda10048_output_mode(fe, state->config->output_mode); /* set inversion */ tda10048_set_inversion(fe, state->config->inversion); /* Ensure we leave the gate closed */ tda10048_i2c_gate_ctrl(fe, 0); return ret;}static int tda10048_read_status(struct dvb_frontend *fe, fe_status_t *status){ struct tda10048_state *state = fe->demodulator_priv; u8 reg; *status = 0; reg = tda10048_readreg(state, TDA10048_SYNC_STATUS); dprintk(1, "%s() status =0x%02x\n", __func__, reg); if (reg & 0x02) *status |= FE_HAS_CARRIER; if (reg & 0x04) *status |= FE_HAS_SIGNAL; if (reg & 0x08) { *status |= FE_HAS_LOCK; *status |= FE_HAS_VITERBI; *status |= FE_HAS_SYNC; } return 0;}static int tda10048_read_ber(struct dvb_frontend *fe, u32 *ber){ struct tda10048_state *state = fe->demodulator_priv; dprintk(1, "%s()\n", __func__); /* TODO: A reset may be required here */ *ber = tda10048_readreg(state, TDA10048_CBER_MSB) << 8 | tda10048_readreg(state, TDA10048_CBER_LSB); return 0;}static int tda10048_read_signal_strength(struct dvb_frontend *fe, u16 *signal_strength){ struct tda10048_state *state = fe->demodulator_priv; u8 v; dprintk(1, "%s()\n", __func__); *signal_strength = 65535; v = tda10048_readreg(state, TDA10048_NP_OUT); if (v > 0) *signal_strength -= (v << 8) | v; return 0;}/* SNR lookup table */static struct snr_tab { u8 val; u8 data;} snr_tab[] = { { 0, 0 }, { 1, 246 }, { 2, 215 }, { 3, 198 }, { 4, 185 }, { 5, 176 }, { 6, 168 }, { 7, 161 }, { 8, 155 }, { 9, 150 }, { 10, 146 }, { 11, 141 }, { 12, 138 }, { 13, 134 }, { 14, 131 }, { 15, 128 }, { 16, 125 }, { 17, 122 }, { 18, 120 }, { 19, 118 }, { 20, 115 }, { 21, 113 }, { 22, 111 }, { 23, 109 }, { 24, 107 }, { 25, 106 }, { 26, 104 }, { 27, 102 }, { 28, 101 }, { 29, 99 }, { 30, 98 }, { 31, 96 }, { 32, 95 }, { 33, 94 }, { 34, 92 }, { 35, 91 }, { 36, 90 }, { 37, 89 }, { 38, 88 }, { 39, 86 }, { 40, 85 }, { 41, 84 }, { 42, 83 }, { 43, 82 }, { 44, 81 }, { 45, 80 }, { 46, 79 }, { 47, 78 }, { 48, 77 }, { 49, 76 }, { 50, 76 }, { 51, 75 }, { 52, 74 }, { 53, 73 }, { 54, 72 }, { 56, 71 }, { 57, 70 }, { 58, 69 }, { 60, 68 }, { 61, 67 }, { 63, 66 }, { 64, 65 }, { 66, 64 }, { 67, 63 }, { 68, 62 }, { 69, 62 }, { 70, 61 }, { 72, 60 }, { 74, 59 }, { 75, 58 }, { 77, 57 }, { 79, 56 }, { 81, 55 }, { 83, 54 }, { 85, 53 }, { 87, 52 }, { 89, 51 }, { 91, 50 }, { 93, 49 }, { 95, 48 }, { 97, 47 }, { 100, 46 }, { 102, 45 }, { 104, 44 }, { 107, 43 }, { 109, 42 }, { 112, 41 }, { 114, 40 }, { 117, 39 }, { 120, 38 }, { 123, 37 }, { 125, 36 }, { 128, 35 }, { 131, 34 }, { 134, 33 }, { 138, 32 }, { 141, 31 }, { 144, 30 }, { 147, 29 }, { 151, 28 }, { 154, 27 }, { 158, 26 }, { 162, 25 }, { 165, 24 }, { 169, 23 }, { 173, 22 }, { 177, 21 }, { 181, 20 }, { 186, 19 }, { 190, 18 }, { 194, 17 }, { 199, 16 }, { 204, 15 }, { 208, 14 }, { 213, 13 }, { 218, 12 }, { 223, 11 }, { 229, 10 }, { 234, 9 }, { 239, 8 }, { 245, 7 }, { 251, 6 }, { 255, 5 },};static int tda10048_read_snr(struct dvb_frontend *fe, u16 *snr){ struct tda10048_state *state = fe->demodulator_priv; u8 v; int i, ret = -EINVAL; dprintk(1, "%s()\n", __func__); v = tda10048_readreg(state, TDA10048_NP_OUT); for (i = 0; i < ARRAY_SIZE(snr_tab); i++) { if (v <= snr_tab[i].val) { *snr = snr_tab[i].data; ret = 0; break; } } return ret;}static int tda10048_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks){ struct tda10048_state *state = fe->demodulator_priv; dprintk(1, "%s()\n", __func__);#if 0 /* Reset and begin counting */ tda10048_writereg(state, TDA10048_UNCOR_CTRL, 0x01); msleep(10);#endif *ucblocks = tda10048_readreg(state, TDA10048_UNCOR_CPT_MSB) << 8 | tda10048_readreg(state, TDA10048_UNCOR_CPT_LSB); return 0;}static int tda10048_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p){ struct tda10048_state *state = fe->demodulator_priv; dprintk(1, "%s()\n", __func__); p->inversion = tda10048_readreg(state, TDA10048_CONF_C1_1) & 0x20 ? INVERSION_ON : INVERSION_OFF; return tda10048_get_tps(state, &p->u.ofdm);}static int tda10048_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune){ tune->min_delay_ms = 1000; return 0;}static void tda10048_release(struct dvb_frontend *fe){ struct tda10048_state *state = fe->demodulator_priv; dprintk(1, "%s()\n", __func__); kfree(state);}static struct dvb_frontend_ops tda10048_ops;struct dvb_frontend *tda10048_attach(const struct tda10048_config *config, struct i2c_adapter *i2c){ struct tda10048_state *state = NULL; dprintk(1, "%s()\n", __func__); /* allocate memory for the internal state */ state = kmalloc(sizeof(struct tda10048_state), GFP_KERNEL); if (state == NULL) goto error; /* setup the state */ state->config = config; state->i2c = i2c; state->fwloaded = 0; /* check if the demod is present */ if (tda10048_readreg(state, TDA10048_IDENTITY) != 0x048) goto error; /* create dvb_frontend */ memcpy(&state->frontend.ops, &tda10048_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; /* Leave the gate closed */ tda10048_i2c_gate_ctrl(&state->frontend, 0); return &state->frontend;error: kfree(state); return NULL;}EXPORT_SYMBOL(tda10048_attach);static struct dvb_frontend_ops tda10048_ops = { .info = { .name = "NXP TDA10048HN DVB-T", .type = FE_OFDM, .frequency_min = 177000000, .frequency_max = 858000000, .frequency_stepsize = 166666, .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | FE_CAN_HIERARCHY_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER }, .release = tda10048_release, .init = tda10048_init, .i2c_gate_ctrl = tda10048_i2c_gate_ctrl, .set_frontend = tda10048_set_frontend, .get_frontend = tda10048_get_frontend, .get_tune_settings = tda10048_get_tune_settings, .read_status = tda10048_read_status, .read_ber = tda10048_read_ber, .read_signal_strength = tda10048_read_signal_strength, .read_snr = tda10048_read_snr, .read_ucblocks = tda10048_read_ucblocks,};module_param(debug, int, 0644);MODULE_PARM_DESC(debug, "Enable verbose debug messages");MODULE_DESCRIPTION("NXP TDA10048HN DVB-T Demodulator driver");MODULE_AUTHOR("Steven Toth");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -