📄 dib3000mc.c
字号:
struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm; int search_state,auto_val; u16 val; if (tuner && state->config.pll_set) { /* initial call from dvb */ state->config.pll_set(fe,fep); state->last_tuned_freq = fep->frequency; // if (!scanboost) { dib3000mc_set_timing(state,0,ofdm->transmission_mode,ofdm->bandwidth); dib3000mc_init_auto_scan(state, ofdm->bandwidth, 0); state->last_tuned_bw = ofdm->bandwidth; wr_foreach(dib3000mc_reg_agc_bandwidth,dib3000mc_agc_bandwidth); wr(DIB3000MC_REG_RESTART,DIB3000MC_RESTART_AGC); wr(DIB3000MC_REG_RESTART,DIB3000MC_RESTART_OFF); /* Default cfg isi offset adp */ wr_foreach(dib3000mc_reg_offset,dib3000mc_offset[0]); wr(DIB3000MC_REG_ISI,DIB3000MC_ISI_DEFAULT | DIB3000MC_ISI_INHIBIT); dib3000mc_set_adp_cfg(state,ofdm->constellation); wr(DIB3000MC_REG_UNK_133,DIB3000MC_UNK_133); wr_foreach(dib3000mc_reg_bandwidth_general,dib3000mc_bandwidth_general); /* power smoothing */ if (ofdm->bandwidth != BANDWIDTH_8_MHZ) { wr_foreach(dib3000mc_reg_bw,dib3000mc_bw[0]); } else { wr_foreach(dib3000mc_reg_bw,dib3000mc_bw[3]); } auto_val = 0; dib3000mc_set_general_cfg(state,fep,&auto_val); dib3000mc_set_impulse_noise(state,0,ofdm->constellation,ofdm->bandwidth); val = rd(DIB3000MC_REG_DEMOD_PARM); wr(DIB3000MC_REG_DEMOD_PARM,val|DIB3000MC_DEMOD_RST_DEMOD_ON); wr(DIB3000MC_REG_DEMOD_PARM,val); // } msleep(70); /* something has to be auto searched */ if (auto_val) { int as_count=0; deb_setf("autosearch enabled.\n"); val = rd(DIB3000MC_REG_DEMOD_PARM); wr(DIB3000MC_REG_DEMOD_PARM,val | DIB3000MC_DEMOD_RST_AUTO_SRCH_ON); wr(DIB3000MC_REG_DEMOD_PARM,val); while ((search_state = dib3000_search_status( rd(DIB3000MC_REG_AS_IRQ),1)) < 0 && as_count++ < 100) msleep(10); deb_info("search_state after autosearch %d after %d checks\n",search_state,as_count); if (search_state == 1) { struct dvb_frontend_parameters feps; if (dib3000mc_get_frontend(fe, &feps) == 0) { deb_setf("reading tuning data from frontend succeeded.\n"); return dib3000mc_set_frontend(fe, &feps, 0); } } } else { dib3000mc_set_impulse_noise(state,0,ofdm->transmission_mode,ofdm->bandwidth); wr(DIB3000MC_REG_ISI,DIB3000MC_ISI_DEFAULT|DIB3000MC_ISI_ACTIVATE); dib3000mc_set_adp_cfg(state,ofdm->constellation); /* set_offset_cfg */ wr_foreach(dib3000mc_reg_offset, dib3000mc_offset[(ofdm->transmission_mode == TRANSMISSION_MODE_8K)+1]); } } else { /* second call, after autosearch (fka: set_WithKnownParams) */// dib3000mc_set_timing(state,1,ofdm->transmission_mode,ofdm->bandwidth); auto_val = 0; dib3000mc_set_general_cfg(state,fep,&auto_val); if (auto_val) deb_info("auto_val is true, even though an auto search was already performed.\n"); dib3000mc_set_impulse_noise(state,0,ofdm->constellation,ofdm->bandwidth); val = rd(DIB3000MC_REG_DEMOD_PARM); wr(DIB3000MC_REG_DEMOD_PARM,val | DIB3000MC_DEMOD_RST_AUTO_SRCH_ON); wr(DIB3000MC_REG_DEMOD_PARM,val); msleep(30); wr(DIB3000MC_REG_ISI,DIB3000MC_ISI_DEFAULT|DIB3000MC_ISI_ACTIVATE); dib3000mc_set_adp_cfg(state,ofdm->constellation); wr_foreach(dib3000mc_reg_offset, dib3000mc_offset[(ofdm->transmission_mode == TRANSMISSION_MODE_8K)+1]); } return 0;}static int dib3000mc_fe_init(struct dvb_frontend* fe, int mobile_mode){ struct dib3000_state *state = fe->demodulator_priv; deb_info("init start\n"); state->timing_offset = 0; state->timing_offset_comp_done = 0; wr(DIB3000MC_REG_RESTART,DIB3000MC_RESTART_CONFIG); wr(DIB3000MC_REG_RESTART,DIB3000MC_RESTART_OFF); wr(DIB3000MC_REG_CLK_CFG_1,DIB3000MC_CLK_CFG_1_POWER_UP); wr(DIB3000MC_REG_CLK_CFG_2,DIB3000MC_CLK_CFG_2_PUP_MOBILE); wr(DIB3000MC_REG_CLK_CFG_3,DIB3000MC_CLK_CFG_3_POWER_UP); wr(DIB3000MC_REG_CLK_CFG_7,DIB3000MC_CLK_CFG_7_INIT); wr(DIB3000MC_REG_RST_UNC,DIB3000MC_RST_UNC_OFF); wr(DIB3000MC_REG_UNK_19,DIB3000MC_UNK_19); wr(33,5); wr(36,81); wr(DIB3000MC_REG_UNK_88,DIB3000MC_UNK_88); wr(DIB3000MC_REG_UNK_99,DIB3000MC_UNK_99); wr(DIB3000MC_REG_UNK_111,DIB3000MC_UNK_111_PH_N_MODE_0); /* phase noise algo off */ /* mobile mode - portable reception */ wr_foreach(dib3000mc_reg_mobile_mode,dib3000mc_mobile_mode[1]);/* TUNER_PANASONIC_ENV57H12D5: */ wr_foreach(dib3000mc_reg_agc_bandwidth,dib3000mc_agc_bandwidth); wr_foreach(dib3000mc_reg_agc_bandwidth_general,dib3000mc_agc_bandwidth_general); wr_foreach(dib3000mc_reg_agc,dib3000mc_agc_tuner[1]); wr(DIB3000MC_REG_UNK_110,DIB3000MC_UNK_110); wr(26,0x6680); wr(DIB3000MC_REG_UNK_1,DIB3000MC_UNK_1); wr(DIB3000MC_REG_UNK_2,DIB3000MC_UNK_2); wr(DIB3000MC_REG_UNK_3,DIB3000MC_UNK_3); wr(DIB3000MC_REG_SEQ_TPS,DIB3000MC_SEQ_TPS_DEFAULT); wr_foreach(dib3000mc_reg_bandwidth,dib3000mc_bandwidth_8mhz); wr_foreach(dib3000mc_reg_bandwidth_general,dib3000mc_bandwidth_general); wr(DIB3000MC_REG_UNK_4,DIB3000MC_UNK_4); wr(DIB3000MC_REG_SET_DDS_FREQ_MSB,DIB3000MC_DDS_FREQ_MSB_INV_OFF); wr(DIB3000MC_REG_SET_DDS_FREQ_LSB,DIB3000MC_DDS_FREQ_LSB); dib3000mc_set_timing(state,0,TRANSMISSION_MODE_8K,BANDWIDTH_8_MHZ);// wr_foreach(dib3000mc_reg_timing_freq,dib3000mc_timing_freq[3]); wr(DIB3000MC_REG_UNK_120,DIB3000MC_UNK_120); wr(DIB3000MC_REG_UNK_134,DIB3000MC_UNK_134); wr(DIB3000MC_REG_FEC_CFG,DIB3000MC_FEC_CFG); wr(DIB3000MC_REG_DIVERSITY3,DIB3000MC_DIVERSITY3_IN_OFF); dib3000mc_set_impulse_noise(state,0,TRANSMISSION_MODE_8K,BANDWIDTH_8_MHZ);/* output mode control, just the MPEG2_SLAVE */// set_or(DIB3000MC_REG_OUTMODE,DIB3000MC_OM_SLAVE); wr(DIB3000MC_REG_OUTMODE,DIB3000MC_OM_SLAVE); wr(DIB3000MC_REG_SMO_MODE,DIB3000MC_SMO_MODE_SLAVE); wr(DIB3000MC_REG_FIFO_THRESHOLD,DIB3000MC_FIFO_THRESHOLD_SLAVE); wr(DIB3000MC_REG_ELEC_OUT,DIB3000MC_ELEC_OUT_SLAVE);/* MPEG2_PARALLEL_CONTINUOUS_CLOCK wr(DIB3000MC_REG_OUTMODE, DIB3000MC_SET_OUTMODE(DIB3000MC_OM_PAR_CONT_CLK, rd(DIB3000MC_REG_OUTMODE))); wr(DIB3000MC_REG_SMO_MODE, DIB3000MC_SMO_MODE_DEFAULT | DIB3000MC_SMO_MODE_188); wr(DIB3000MC_REG_FIFO_THRESHOLD,DIB3000MC_FIFO_THRESHOLD_DEFAULT); wr(DIB3000MC_REG_ELEC_OUT,DIB3000MC_ELEC_OUT_DIV_OUT_ON);*//* diversity */ wr(DIB3000MC_REG_DIVERSITY1,DIB3000MC_DIVERSITY1_DEFAULT); wr(DIB3000MC_REG_DIVERSITY2,DIB3000MC_DIVERSITY2_DEFAULT); set_and(DIB3000MC_REG_DIVERSITY3,DIB3000MC_DIVERSITY3_IN_OFF); set_or(DIB3000MC_REG_CLK_CFG_7,DIB3000MC_CLK_CFG_7_DIV_IN_OFF); if (state->config.pll_init) state->config.pll_init(fe); deb_info("init end\n"); return 0;}static int dib3000mc_read_status(struct dvb_frontend* fe, fe_status_t *stat){ struct dib3000_state* state = fe->demodulator_priv; u16 lock = rd(DIB3000MC_REG_LOCKING); *stat = 0; if (DIB3000MC_AGC_LOCK(lock)) *stat |= FE_HAS_SIGNAL; if (DIB3000MC_CARRIER_LOCK(lock)) *stat |= FE_HAS_CARRIER; if (DIB3000MC_TPS_LOCK(lock)) *stat |= FE_HAS_VITERBI; if (DIB3000MC_MPEG_SYNC_LOCK(lock)) *stat |= (FE_HAS_SYNC | FE_HAS_LOCK); deb_stat("actual status is %2x fifo_level: %x,244: %x, 206: %x, 207: %x, 1040: %x\n",*stat,rd(510),rd(244),rd(206),rd(207),rd(1040)); return 0;}static int dib3000mc_read_ber(struct dvb_frontend* fe, u32 *ber){ struct dib3000_state* state = fe->demodulator_priv; *ber = ((rd(DIB3000MC_REG_BER_MSB) << 16) | rd(DIB3000MC_REG_BER_LSB)); return 0;}static int dib3000mc_read_unc_blocks(struct dvb_frontend* fe, u32 *unc){ struct dib3000_state* state = fe->demodulator_priv; *unc = rd(DIB3000MC_REG_PACKET_ERRORS); return 0;}/* see dib3000mb.c for calculation comments */static int dib3000mc_read_signal_strength(struct dvb_frontend* fe, u16 *strength){ struct dib3000_state* state = fe->demodulator_priv; u16 val = rd(DIB3000MC_REG_SIGNAL_NOISE_LSB); *strength = (((val >> 6) & 0xff) << 8) + (val & 0x3f); deb_stat("signal: mantisse = %d, exponent = %d\n",(*strength >> 8) & 0xff, *strength & 0xff); return 0;}/* see dib3000mb.c for calculation comments */static int dib3000mc_read_snr(struct dvb_frontend* fe, u16 *snr){ struct dib3000_state* state = fe->demodulator_priv; u16 val = rd(DIB3000MC_REG_SIGNAL_NOISE_LSB), val2 = rd(DIB3000MC_REG_SIGNAL_NOISE_MSB); u16 sig,noise; sig = (((val >> 6) & 0xff) << 8) + (val & 0x3f); noise = (((val >> 4) & 0xff) << 8) + ((val & 0xf) << 2) + ((val2 >> 14) & 0x3); if (noise == 0) *snr = 0xffff; else *snr = (u16) sig/noise; deb_stat("signal: mantisse = %d, exponent = %d\n",(sig >> 8) & 0xff, sig & 0xff); deb_stat("noise: mantisse = %d, exponent = %d\n",(noise >> 8) & 0xff, noise & 0xff); deb_stat("snr: %d\n",*snr); return 0;}static int dib3000mc_sleep(struct dvb_frontend* fe){ struct dib3000_state* state = fe->demodulator_priv; set_or(DIB3000MC_REG_CLK_CFG_7,DIB3000MC_CLK_CFG_7_PWR_DOWN); wr(DIB3000MC_REG_CLK_CFG_1,DIB3000MC_CLK_CFG_1_POWER_DOWN); wr(DIB3000MC_REG_CLK_CFG_2,DIB3000MC_CLK_CFG_2_POWER_DOWN); wr(DIB3000MC_REG_CLK_CFG_3,DIB3000MC_CLK_CFG_3_POWER_DOWN); return 0;}static int dib3000mc_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune){ tune->min_delay_ms = 1000; return 0;}static int dib3000mc_fe_init_nonmobile(struct dvb_frontend* fe){ return dib3000mc_fe_init(fe, 0);}static int dib3000mc_set_frontend_and_tuner(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep){ return dib3000mc_set_frontend(fe, fep, 1);}static void dib3000mc_release(struct dvb_frontend* fe){ struct dib3000_state *state = fe->demodulator_priv; kfree(state);}/* pid filter and transfer stuff */static int dib3000mc_pid_control(struct dvb_frontend *fe,int index, int pid,int onoff){ struct dib3000_state *state = fe->demodulator_priv; pid = (onoff ? pid | DIB3000_ACTIVATE_PID_FILTERING : 0); wr(index+DIB3000MC_REG_FIRST_PID,pid); return 0;}static int dib3000mc_fifo_control(struct dvb_frontend *fe, int onoff){ struct dib3000_state *state = fe->demodulator_priv; u16 tmp = rd(DIB3000MC_REG_SMO_MODE); deb_xfer("%s fifo\n",onoff ? "enabling" : "disabling"); if (onoff) { deb_xfer("%d %x\n",tmp & DIB3000MC_SMO_MODE_FIFO_UNFLUSH,tmp & DIB3000MC_SMO_MODE_FIFO_UNFLUSH); wr(DIB3000MC_REG_SMO_MODE,tmp & DIB3000MC_SMO_MODE_FIFO_UNFLUSH); } else { deb_xfer("%d %x\n",tmp | DIB3000MC_SMO_MODE_FIFO_FLUSH,tmp | DIB3000MC_SMO_MODE_FIFO_FLUSH); wr(DIB3000MC_REG_SMO_MODE,tmp | DIB3000MC_SMO_MODE_FIFO_FLUSH); } return 0;}static int dib3000mc_pid_parse(struct dvb_frontend *fe, int onoff){ struct dib3000_state *state = fe->demodulator_priv; u16 tmp = rd(DIB3000MC_REG_SMO_MODE); deb_xfer("%s pid parsing\n",onoff ? "enabling" : "disabling"); if (onoff) { wr(DIB3000MC_REG_SMO_MODE,tmp | DIB3000MC_SMO_MODE_PID_PARSE); } else { wr(DIB3000MC_REG_SMO_MODE,tmp & DIB3000MC_SMO_MODE_NO_PID_PARSE); } return 0;}static int dib3000mc_tuner_pass_ctrl(struct dvb_frontend *fe, int onoff, u8 pll_addr){ struct dib3000_state *state = fe->demodulator_priv; if (onoff) { wr(DIB3000MC_REG_TUNER, DIB3000_TUNER_WRITE_ENABLE(pll_addr)); } else { wr(DIB3000MC_REG_TUNER, DIB3000_TUNER_WRITE_DISABLE(pll_addr)); } return 0;}static int dib3000mc_demod_init(struct dib3000_state *state){ u16 default_addr = 0x0a; /* first init */ if (state->config.demod_address != default_addr) { deb_info("initializing the demod the first time. Setting demod addr to 0x%x\n",default_addr); wr(DIB3000MC_REG_ELEC_OUT,DIB3000MC_ELEC_OUT_DIV_OUT_ON); wr(DIB3000MC_REG_OUTMODE,DIB3000MC_OM_PAR_CONT_CLK); wr(DIB3000MC_REG_RST_I2C_ADDR, DIB3000MC_DEMOD_ADDR(default_addr) | DIB3000MC_DEMOD_ADDR_ON); state->config.demod_address = default_addr; wr(DIB3000MC_REG_RST_I2C_ADDR, DIB3000MC_DEMOD_ADDR(default_addr)); } else deb_info("demod is already initialized. Demod addr: 0x%x\n",state->config.demod_address); return 0;}static struct dvb_frontend_ops dib3000mc_ops;struct dvb_frontend* dib3000mc_attach(const struct dib3000_config* config, struct i2c_adapter* i2c, struct dib_fe_xfer_ops *xfer_ops){ struct dib3000_state* state = NULL; u16 devid; /* allocate memory for the internal state */ state = kmalloc(sizeof(struct dib3000_state), GFP_KERNEL); if (state == NULL) goto error; memset(state,0,sizeof(struct dib3000_state)); /* setup the state */ state->i2c = i2c; memcpy(&state->config,config,sizeof(struct dib3000_config)); memcpy(&state->ops, &dib3000mc_ops, sizeof(struct dvb_frontend_ops)); /* check for the correct demod */ if (rd(DIB3000_REG_MANUFACTOR_ID) != DIB3000_I2C_ID_DIBCOM) goto error; devid = rd(DIB3000_REG_DEVICE_ID); if (devid != DIB3000MC_DEVICE_ID && devid != DIB3000P_DEVICE_ID) goto error; switch (devid) { case DIB3000MC_DEVICE_ID: info("Found a DiBcom 3000M-C, interesting..."); break; case DIB3000P_DEVICE_ID: info("Found a DiBcom 3000P."); break; } /* create dvb_frontend */ state->frontend.ops = &state->ops; state->frontend.demodulator_priv = state; /* set the xfer operations */ xfer_ops->pid_parse = dib3000mc_pid_parse; xfer_ops->fifo_ctrl = dib3000mc_fifo_control; xfer_ops->pid_ctrl = dib3000mc_pid_control; xfer_ops->tuner_pass_ctrl = dib3000mc_tuner_pass_ctrl; dib3000mc_demod_init(state); return &state->frontend;error: kfree(state); return NULL;}static struct dvb_frontend_ops dib3000mc_ops = { .info = { .name = "DiBcom 3000P/M-C DVB-T", .type = FE_OFDM, .frequency_min = 44250000, .frequency_max = 867250000, .frequency_stepsize = 62500, .caps = FE_CAN_INVERSION_AUTO | 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 | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO, }, .release = dib3000mc_release, .init = dib3000mc_fe_init_nonmobile, .sleep = dib3000mc_sleep, .set_frontend = dib3000mc_set_frontend_and_tuner, .get_frontend = dib3000mc_get_frontend, .get_tune_settings = dib3000mc_fe_get_tune_settings, .read_status = dib3000mc_read_status, .read_ber = dib3000mc_read_ber, .read_signal_strength = dib3000mc_read_signal_strength, .read_snr = dib3000mc_read_snr, .read_ucblocks = dib3000mc_read_unc_blocks,};MODULE_AUTHOR(DRIVER_AUTHOR);MODULE_DESCRIPTION(DRIVER_DESC);MODULE_LICENSE("GPL");EXPORT_SYMBOL(dib3000mc_attach);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -