📄 tda1004x.c
字号:
} else { dprintk("%s: setting up PLLs for a 16 MHz Xtal\n", __FUNCTION__); tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 3); // PLL P = 0, N = 3 } if(tda10046_clk53m) tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 0x67); else tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 0x72); /* Note clock frequency is handled implicitly */ switch (state->config->if_freq) { case TDA10046_FREQ_045: tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0c); tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x00); break; case TDA10046_FREQ_052: tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0d); tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xc7); break; case TDA10046_FREQ_3617: tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd7); tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x59); break; case TDA10046_FREQ_3613: tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd7); tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x3f); break; } tda10046h_set_bandwidth(state, BANDWIDTH_8_MHZ); // default bandwidth 8 MHz /* let the PLLs settle */ msleep(120);}static int tda10046_fwupload(struct dvb_frontend* fe){ struct tda1004x_state* state = fe->demodulator_priv; int ret; const struct firmware *fw; /* reset + wake up chip */ if (state->config->xtal_freq == TDA10046_XTAL_4M) { tda1004x_write_byteI(state, TDA1004X_CONFC4, 0); } else { dprintk("%s: 16MHz Xtal, reducing I2C speed\n", __FUNCTION__); tda1004x_write_byteI(state, TDA1004X_CONFC4, 0x80); } tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 1, 0); /* set GPIO 1 and 3 */ if (state->config->gpio_config != TDA10046_GPTRI) { tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE2, 0x33); tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0x0f, state->config->gpio_config &0x0f); } /* let the clocks recover from sleep */ msleep(10); /* The PLLs need to be reprogrammed after sleep */ tda10046_init_plls(fe); tda1004x_write_mask(state, TDA1004X_CONFADC2, 0xc0, 0); /* don't re-upload unless necessary */ if (tda1004x_check_upload_ok(state) == 0) return 0; printk(KERN_INFO "tda1004x: trying to boot from eeprom\n"); tda1004x_write_mask(state, TDA1004X_CONFC4, 4, 4); msleep(300); /* don't re-upload unless necessary */ if (tda1004x_check_upload_ok(state) == 0) return 0; if (state->config->request_firmware != NULL) { /* request the firmware, this will block until someone uploads it */ printk(KERN_INFO "tda1004x: waiting for firmware upload...\n"); ret = state->config->request_firmware(fe, &fw, TDA10046_DEFAULT_FIRMWARE); if (ret) { /* remain compatible to old bug: try to load with tda10045 image name */ ret = state->config->request_firmware(fe, &fw, TDA10045_DEFAULT_FIRMWARE); if (ret) { printk(KERN_ERR "tda1004x: no firmware upload (timeout or file not found?)\n"); return ret; } else { printk(KERN_INFO "tda1004x: please rename the firmware file to %s\n", TDA10046_DEFAULT_FIRMWARE); } } } else { printk(KERN_ERR "tda1004x: no request function defined, can't upload from file\n"); return -EIO; } tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8); // going to boot from HOST ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10046H_CODE_CPT, TDA10046H_CODE_IN); release_firmware(fw); return tda1004x_check_upload_ok(state);}static int tda1004x_encode_fec(int fec){ // convert known FEC values switch (fec) { case FEC_1_2: return 0; case FEC_2_3: return 1; case FEC_3_4: return 2; case FEC_5_6: return 3; case FEC_7_8: return 4; } // unsupported return -EINVAL;}static int tda1004x_decode_fec(int tdafec){ // convert known FEC values switch (tdafec) { case 0: return FEC_1_2; case 1: return FEC_2_3; case 2: return FEC_3_4; case 3: return FEC_5_6; case 4: return FEC_7_8; } // unsupported return -1;}static int tda1004x_write(struct dvb_frontend* fe, u8 *buf, int len){ struct tda1004x_state* state = fe->demodulator_priv; if (len != 2) return -EINVAL; return tda1004x_write_byteI(state, buf[0], buf[1]);}static int tda10045_init(struct dvb_frontend* fe){ struct tda1004x_state* state = fe->demodulator_priv; dprintk("%s\n", __FUNCTION__); if (tda10045_fwupload(fe)) { printk("tda1004x: firmware upload failed\n"); return -EIO; } tda1004x_write_mask(state, TDA1004X_CONFADC1, 0x10, 0); // wake up the ADC // tda setup tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer tda1004x_write_mask(state, TDA1004X_AUTO, 8, 0); // select HP stream tda1004x_write_mask(state, TDA1004X_CONFC1, 0x40, 0); // set polarity of VAGC signal tda1004x_write_mask(state, TDA1004X_CONFC1, 0x80, 0x80); // enable pulse killer tda1004x_write_mask(state, TDA1004X_AUTO, 0x10, 0x10); // enable auto offset tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0xC0, 0x0); // no frequency offset tda1004x_write_byteI(state, TDA1004X_CONF_TS1, 0); // setup MPEG2 TS interface tda1004x_write_byteI(state, TDA1004X_CONF_TS2, 0); // setup MPEG2 TS interface tda1004x_write_mask(state, TDA1004X_VBER_MSB, 0xe0, 0xa0); // 10^6 VBER measurement bits tda1004x_write_mask(state, TDA1004X_CONFC1, 0x10, 0); // VAGC polarity tda1004x_write_byteI(state, TDA1004X_CONFADC1, 0x2e); tda1004x_write_mask(state, 0x1f, 0x01, state->config->invert_oclk); return 0;}static int tda10046_init(struct dvb_frontend* fe){ struct tda1004x_state* state = fe->demodulator_priv; dprintk("%s\n", __FUNCTION__); if (tda10046_fwupload(fe)) { printk("tda1004x: firmware upload failed\n"); return -EIO; } // tda setup tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer tda1004x_write_byteI(state, TDA1004X_AUTO, 0x87); // 100 ppm crystal, select HP stream tda1004x_write_byteI(state, TDA1004X_CONFC1, 0x88); // enable pulse killer switch (state->config->agc_config) { case TDA10046_AGC_DEFAULT: tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x00); // AGC setup tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x60); // set AGC polarities break; case TDA10046_AGC_IFO_AUTO_NEG: tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x0a); // AGC setup tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x60); // set AGC polarities break; case TDA10046_AGC_IFO_AUTO_POS: tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x0a); // AGC setup tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x00); // set AGC polarities break; case TDA10046_AGC_TDA827X: tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x02); // AGC setup tda1004x_write_byteI(state, TDA10046H_AGC_THR, 0x70); // AGC Threshold tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x08); // Gain Renormalize tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x60); // set AGC polarities break; } if (state->config->ts_mode == 0) { tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 0xc0, 0x40); tda1004x_write_mask(state, 0x3a, 0x80, state->config->invert_oclk << 7); } else { tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 0xc0, 0x80); tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0x10, state->config->invert_oclk << 4); } tda1004x_write_byteI(state, TDA1004X_CONFADC2, 0x38); tda1004x_write_mask (state, TDA10046H_CONF_TRISTATE1, 0x3e, 0x38); // Turn IF AGC output on tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MIN, 0); // } tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MAX, 0xff); // } AGC min/max values tda1004x_write_byteI(state, TDA10046H_AGC_IF_MIN, 0); // } tda1004x_write_byteI(state, TDA10046H_AGC_IF_MAX, 0xff); // } tda1004x_write_byteI(state, TDA10046H_AGC_GAINS, 0x12); // IF gain 2, TUN gain 1 tda1004x_write_byteI(state, TDA10046H_CVBER_CTRL, 0x1a); // 10^6 VBER measurement bits tda1004x_write_byteI(state, TDA1004X_CONF_TS1, 7); // MPEG2 interface config tda1004x_write_byteI(state, TDA1004X_CONF_TS2, 0xc0); // MPEG2 interface config // tda1004x_write_mask(state, 0x50, 0x80, 0x80); // handle out of guard echoes return 0;}static int tda1004x_set_fe(struct dvb_frontend* fe, struct dvb_frontend_parameters *fe_params){ struct tda1004x_state* state = fe->demodulator_priv; int tmp; int inversion; dprintk("%s\n", __FUNCTION__); if (state->demod_type == TDA1004X_DEMOD_TDA10046) { // setup auto offset tda1004x_write_mask(state, TDA1004X_AUTO, 0x10, 0x10); tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x80, 0); tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0xC0, 0); // disable agc_conf[2] tda1004x_write_mask(state, TDA10046H_AGC_CONF, 4, 0); } // set frequency if (fe->ops.tuner_ops.set_params) { fe->ops.tuner_ops.set_params(fe, fe_params); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } // Hardcoded to use auto as much as possible on the TDA10045 as it // is very unreliable if AUTO mode is _not_ used. if (state->demod_type == TDA1004X_DEMOD_TDA10045) { fe_params->u.ofdm.code_rate_HP = FEC_AUTO; fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO; fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO; } // Set standard params.. or put them to auto if ((fe_params->u.ofdm.code_rate_HP == FEC_AUTO) || (fe_params->u.ofdm.code_rate_LP == FEC_AUTO) || (fe_params->u.ofdm.constellation == QAM_AUTO) || (fe_params->u.ofdm.hierarchy_information == HIERARCHY_AUTO)) { tda1004x_write_mask(state, TDA1004X_AUTO, 1, 1); // enable auto tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x03, 0); // turn off constellation bits tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 0); // turn off hierarchy bits tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0x3f, 0); // turn off FEC bits } else { tda1004x_write_mask(state, TDA1004X_AUTO, 1, 0); // disable auto // set HP FEC tmp = tda1004x_encode_fec(fe_params->u.ofdm.code_rate_HP); if (tmp < 0) return tmp; tda1004x_write_mask(state, TDA1004X_IN_CONF2, 7, tmp); // set LP FEC tmp = tda1004x_encode_fec(fe_params->u.ofdm.code_rate_LP); if (tmp < 0) return tmp; tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0x38, tmp << 3); // set constellation switch (fe_params->u.ofdm.constellation) { case QPSK: tda1004x_write_mask(state, TDA1004X_IN_CONF1, 3, 0); break; case QAM_16: tda1004x_write_mask(state, TDA1004X_IN_CONF1, 3, 1); break; case QAM_64: tda1004x_write_mask(state, TDA1004X_IN_CONF1, 3, 2); break; default: return -EINVAL; } // set hierarchy switch (fe_params->u.ofdm.hierarchy_information) { case HIERARCHY_NONE: tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 0 << 5); break; case HIERARCHY_1: tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 1 << 5); break; case HIERARCHY_2: tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 2 << 5); break; case HIERARCHY_4: tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 3 << 5); break; default: return -EINVAL; } } // set bandwidth switch (state->demod_type) { case TDA1004X_DEMOD_TDA10045: tda10045h_set_bandwidth(state, fe_params->u.ofdm.bandwidth); break; case TDA1004X_DEMOD_TDA10046: tda10046h_set_bandwidth(state, fe_params->u.ofdm.bandwidth); break; } // set inversion inversion = fe_params->inversion; if (state->config->invert) inversion = inversion ? INVERSION_OFF : INVERSION_ON; switch (inversion) { case INVERSION_OFF: tda1004x_write_mask(state, TDA1004X_CONFC1, 0x20, 0); break; case INVERSION_ON: tda1004x_write_mask(state, TDA1004X_CONFC1, 0x20, 0x20); break; default: return -EINVAL; } // set guard interval switch (fe_params->u.ofdm.guard_interval) { case GUARD_INTERVAL_1_32: tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0); tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 0 << 2); break; case GUARD_INTERVAL_1_16: tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0); tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 1 << 2); break; case GUARD_INTERVAL_1_8: tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0); tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 2 << 2); break; case GUARD_INTERVAL_1_4: tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0); tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 3 << 2); break; case GUARD_INTERVAL_AUTO: tda1004x_write_mask(state, TDA1004X_AUTO, 2, 2); tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 0 << 2); break; default: return -EINVAL; } // set transmission mode switch (fe_params->u.ofdm.transmission_mode) { case TRANSMISSION_MODE_2K: tda1004x_write_mask(state, TDA1004X_AUTO, 4, 0); tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x10, 0 << 4); break; case TRANSMISSION_MODE_8K: tda1004x_write_mask(state, TDA1004X_AUTO, 4, 0); tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x10, 1 << 4); break; case TRANSMISSION_MODE_AUTO: tda1004x_write_mask(state, TDA1004X_AUTO, 4, 4); tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x10, 0); break; default: return -EINVAL; } // start the lock switch (state->demod_type) { case TDA1004X_DEMOD_TDA10045: tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8); tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 0); break; case TDA1004X_DEMOD_TDA10046: tda1004x_write_mask(state, TDA1004X_AUTO, 0x40, 0x40); msleep(1); tda1004x_write_mask(state, TDA10046H_AGC_CONF, 4, 1); break; } msleep(10); return 0;}static int tda1004x_get_fe(struct dvb_frontend* fe, struct dvb_frontend_parameters *fe_params){ struct tda1004x_state* state = fe->demodulator_priv; dprintk("%s\n", __FUNCTION__); // inversion status fe_params->inversion = INVERSION_OFF; if (tda1004x_read_byte(state, TDA1004X_CONFC1) & 0x20) fe_params->inversion = INVERSION_ON; if (state->config->invert) fe_params->inversion = fe_params->inversion ? INVERSION_OFF : INVERSION_ON; // bandwidth switch (state->demod_type) { case TDA1004X_DEMOD_TDA10045: switch (tda1004x_read_byte(state, TDA10045H_WREF_LSB)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -