📄 tda1004x.c
字号:
fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ; break; case 0x6e: fe_params->u.ofdm.bandwidth = BANDWIDTH_7_MHZ; break; case 0x80: fe_params->u.ofdm.bandwidth = BANDWIDTH_6_MHZ; break; } break; } // FEC fe_params->u.ofdm.code_rate_HP = tda1004x_decode_fec(tda1004x_read_byte(state, TDA1004X_OUT_CONF2) & 7); fe_params->u.ofdm.code_rate_LP = tda1004x_decode_fec((tda1004x_read_byte(state, TDA1004X_OUT_CONF2) >> 3) & 7); // constellation switch (tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 3) { case 0: fe_params->u.ofdm.constellation = QPSK; break; case 1: fe_params->u.ofdm.constellation = QAM_16; break; case 2: fe_params->u.ofdm.constellation = QAM_64; break; } // transmission mode fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; if (tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x10) { fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; } // guard interval switch ((tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x0c) >> 2) { case 0: fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; break; case 1: fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; break; case 2: fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; break; case 3: fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; break; } // hierarchy switch ((tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x60) >> 5) { case 0: fe_params->u.ofdm.hierarchy_information = HIERARCHY_NONE; break; case 1: fe_params->u.ofdm.hierarchy_information = HIERARCHY_1; break; case 2: fe_params->u.ofdm.hierarchy_information = HIERARCHY_2; break; case 3: fe_params->u.ofdm.hierarchy_information = HIERARCHY_4; break; } return 0;}static int tda1004x_read_status(struct dvb_frontend* fe, fe_status_t * fe_status){ struct tda1004x_state* state = fe->demodulator_priv; int status; int cber; int vber; dprintk("%s\n", __FUNCTION__); // read status status = tda1004x_read_byte(state, TDA1004X_STATUS_CD); if (status == -1) { return -EIO; } // decode *fe_status = 0; if (status & 4) *fe_status |= FE_HAS_SIGNAL; if (status & 2) *fe_status |= FE_HAS_CARRIER; if (status & 8) *fe_status |= FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; // if we don't already have VITERBI (i.e. not LOCKED), see if the viterbi // is getting anything valid if (!(*fe_status & FE_HAS_VITERBI)) { // read the CBER cber = tda1004x_read_byte(state, TDA1004X_CBER_LSB); if (cber == -1) return -EIO; status = tda1004x_read_byte(state, TDA1004X_CBER_MSB); if (status == -1) return -EIO; cber |= (status << 8); tda1004x_read_byte(state, TDA1004X_CBER_RESET); if (cber != 65535) { *fe_status |= FE_HAS_VITERBI; } } // if we DO have some valid VITERBI output, but don't already have SYNC // bytes (i.e. not LOCKED), see if the RS decoder is getting anything valid. if ((*fe_status & FE_HAS_VITERBI) && (!(*fe_status & FE_HAS_SYNC))) { // read the VBER vber = tda1004x_read_byte(state, TDA1004X_VBER_LSB); if (vber == -1) return -EIO; status = tda1004x_read_byte(state, TDA1004X_VBER_MID); if (status == -1) return -EIO; vber |= (status << 8); status = tda1004x_read_byte(state, TDA1004X_VBER_MSB); if (status == -1) return -EIO; vber |= ((status << 16) & 0x0f); tda1004x_read_byte(state, TDA1004X_CVBER_LUT); // if RS has passed some valid TS packets, then we must be // getting some SYNC bytes if (vber < 16632) { *fe_status |= FE_HAS_SYNC; } } // success dprintk("%s: fe_status=0x%x\n", __FUNCTION__, *fe_status); return 0;}static int tda1004x_read_signal_strength(struct dvb_frontend* fe, u16 * signal){ struct tda1004x_state* state = fe->demodulator_priv; int tmp; int reg = 0; dprintk("%s\n", __FUNCTION__); // determine the register to use switch(state->demod_type) { case TDA1004X_DEMOD_TDA10045: reg = TDA10045H_S_AGC; break; case TDA1004X_DEMOD_TDA10046: reg = TDA10046H_AGC_IF_LEVEL; break; } // read it tmp = tda1004x_read_byte(state, reg); if (tmp < 0) return -EIO; *signal = (tmp << 8) | tmp; dprintk("%s: signal=0x%x\n", __FUNCTION__, *signal); return 0;}static int tda1004x_read_snr(struct dvb_frontend* fe, u16 * snr){ struct tda1004x_state* state = fe->demodulator_priv; int tmp; dprintk("%s\n", __FUNCTION__); // read it tmp = tda1004x_read_byte(state, TDA1004X_SNR); if (tmp < 0) return -EIO; if (tmp) { tmp = 255 - tmp; } *snr = ((tmp << 8) | tmp); dprintk("%s: snr=0x%x\n", __FUNCTION__, *snr); return 0;}static int tda1004x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks){ struct tda1004x_state* state = fe->demodulator_priv; int tmp; int tmp2; int counter; dprintk("%s\n", __FUNCTION__); // read the UCBLOCKS and reset counter = 0; tmp = tda1004x_read_byte(state, TDA1004X_UNCOR); if (tmp < 0) return -EIO; tmp &= 0x7f; while (counter++ < 5) { tda1004x_write_mask(state, TDA1004X_UNCOR, 0x80, 0); tda1004x_write_mask(state, TDA1004X_UNCOR, 0x80, 0); tda1004x_write_mask(state, TDA1004X_UNCOR, 0x80, 0); tmp2 = tda1004x_read_byte(state, TDA1004X_UNCOR); if (tmp2 < 0) return -EIO; tmp2 &= 0x7f; if ((tmp2 < tmp) || (tmp2 == 0)) break; } if (tmp != 0x7f) { *ucblocks = tmp; } else { *ucblocks = 0xffffffff; } dprintk("%s: ucblocks=0x%x\n", __FUNCTION__, *ucblocks); return 0;}static int tda1004x_read_ber(struct dvb_frontend* fe, u32* ber){ struct tda1004x_state* state = fe->demodulator_priv; int tmp; dprintk("%s\n", __FUNCTION__); // read it in tmp = tda1004x_read_byte(state, TDA1004X_CBER_LSB); if (tmp < 0) return -EIO; *ber = tmp << 1; tmp = tda1004x_read_byte(state, TDA1004X_CBER_MSB); if (tmp < 0) return -EIO; *ber |= (tmp << 9); tda1004x_read_byte(state, TDA1004X_CBER_RESET); dprintk("%s: ber=0x%x\n", __FUNCTION__, *ber); return 0;}static int tda1004x_sleep(struct dvb_frontend* fe){ struct tda1004x_state* state = fe->demodulator_priv; switch(state->demod_type) { case TDA1004X_DEMOD_TDA10045: tda1004x_write_mask(state, TDA1004X_CONFADC1, 0x10, 0x10); break; case TDA1004X_DEMOD_TDA10046: tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 1); break; } state->initialised = 0; return 0; }static int tda1004x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) { fesettings->min_delay_ms = 800; fesettings->step_size = 166667; fesettings->max_drift = 166667*2; return 0; }static void tda1004x_release(struct dvb_frontend* fe){ struct tda1004x_state* state = (struct tda1004x_state*) fe->demodulator_priv; kfree(state); }static struct dvb_frontend_ops tda10045_ops;struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config, struct i2c_adapter* i2c){ struct tda1004x_state* state = NULL; /* allocate memory for the internal state */ state = (struct tda1004x_state*) kmalloc(sizeof(struct tda1004x_state), GFP_KERNEL); if (state == NULL) goto error; /* setup the state */ state->config = config; state->i2c = i2c; memcpy(&state->ops, &tda10045_ops, sizeof(struct dvb_frontend_ops)); state->initialised = 0; state->demod_type = TDA1004X_DEMOD_TDA10045; /* check if the demod is there */ if (tda1004x_read_byte(state, TDA1004X_CHIPID) != 0x25) goto error; /* create dvb_frontend */ state->frontend.ops = &state->ops; state->frontend.demodulator_priv = state; return &state->frontend;error: if (state) kfree(state); return NULL; }static struct dvb_frontend_ops tda10046_ops;struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config, struct i2c_adapter* i2c){ struct tda1004x_state* state = NULL; /* allocate memory for the internal state */ state = (struct tda1004x_state*) kmalloc(sizeof(struct tda1004x_state), GFP_KERNEL); if (state == NULL) goto error; /* setup the state */ state->config = config; state->i2c = i2c; memcpy(&state->ops, &tda10046_ops, sizeof(struct dvb_frontend_ops)); state->initialised = 0; state->demod_type = TDA1004X_DEMOD_TDA10046; /* check if the demod is there */ if (tda1004x_read_byte(state, TDA1004X_CHIPID) != 0x46) goto error; /* create dvb_frontend */ state->frontend.ops = &state->ops; state->frontend.demodulator_priv = state; return &state->frontend;error: if (state) kfree(state); return NULL; }static struct dvb_frontend_ops tda10045_ops = { .info = { .name = "Philips TDA10045H DVB-T", .type = FE_OFDM, .frequency_min = 51000000, .frequency_max = 858000000, .frequency_stepsize = 166667, .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_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO }, .release = tda1004x_release, .init = tda10045_init, .sleep = tda1004x_sleep, .set_frontend = tda1004x_set_fe, .get_frontend = tda1004x_get_fe, .get_tune_settings = tda1004x_get_tune_settings, .read_status = tda1004x_read_status, .read_ber = tda1004x_read_ber, .read_signal_strength = tda1004x_read_signal_strength, .read_snr = tda1004x_read_snr, .read_ucblocks = tda1004x_read_ucblocks,};static struct dvb_frontend_ops tda10046_ops = { .info = { .name = "Philips TDA10046H DVB-T", .type = FE_OFDM, .frequency_min = 51000000, .frequency_max = 858000000, .frequency_stepsize = 166667, .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_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO }, .release = tda1004x_release, .init = tda10046_init, .sleep = tda1004x_sleep, .set_frontend = tda1004x_set_fe, .get_frontend = tda1004x_get_fe, .get_tune_settings = tda1004x_get_tune_settings, .read_status = tda1004x_read_status, .read_ber = tda1004x_read_ber, .read_signal_strength = tda1004x_read_signal_strength, .read_snr = tda1004x_read_snr, .read_ucblocks = tda1004x_read_ucblocks,};module_param(debug, int, 0644);MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");MODULE_DESCRIPTION("Philips TDA10045H & TDA10046H DVB-T Demodulator");MODULE_AUTHOR("Andrew de Quincey & Robert Schlabbach");MODULE_LICENSE("GPL");EXPORT_SYMBOL(tda10045_attach);EXPORT_SYMBOL(tda10046_attach);EXPORT_SYMBOL(tda1004x_write_byte);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -