📄 dib3000mc.c
字号:
/* * Frontend driver for mobile DVB-T demodulator DiBcom 3000P/M-C * DiBcom (http://www.dibcom.fr/) * * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) * * based on GPL code from DiBCom, which has * * Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, version 2. * * Acknowledgements * * Amaury Demol (ademol@dibcom.fr) from DiBcom for providing specs and driver * sources, on which this driver (and the dvb-dibusb) are based. * * see Documentation/dvb/README.dibusb for more information * */#include <linux/config.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/init.h>#include <linux/delay.h>#include <linux/string.h>#include <linux/slab.h>#include "dib3000-common.h"#include "dib3000mc_priv.h"#include "dib3000.h"/* Version information */#define DRIVER_VERSION "0.1"#define DRIVER_DESC "DiBcom 3000M-C DVB-T demodulator"#define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@desy.de"#ifdef CONFIG_DVB_DIBCOM_DEBUGstatic int debug;module_param(debug, int, 0644);MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=setfe,8=getfe,16=stat (|-able)).");#endif#define deb_info(args...) dprintk(0x01,args)#define deb_xfer(args...) dprintk(0x02,args)#define deb_setf(args...) dprintk(0x04,args)#define deb_getf(args...) dprintk(0x08,args)#define deb_stat(args...) dprintk(0x10,args)static int dib3000mc_set_impulse_noise(struct dib3000_state * state, int mode, fe_transmit_mode_t transmission_mode, fe_bandwidth_t bandwidth){ switch (transmission_mode) { case TRANSMISSION_MODE_2K: wr_foreach(dib3000mc_reg_fft,dib3000mc_fft_modes[0]); break; case TRANSMISSION_MODE_8K: wr_foreach(dib3000mc_reg_fft,dib3000mc_fft_modes[1]); break; default: break; } switch (bandwidth) {/* case BANDWIDTH_5_MHZ: wr_foreach(dib3000mc_reg_impulse_noise,dib3000mc_impluse_noise[0]); break; */ case BANDWIDTH_6_MHZ: wr_foreach(dib3000mc_reg_impulse_noise,dib3000mc_impluse_noise[1]); break; case BANDWIDTH_7_MHZ: wr_foreach(dib3000mc_reg_impulse_noise,dib3000mc_impluse_noise[2]); break; case BANDWIDTH_8_MHZ: wr_foreach(dib3000mc_reg_impulse_noise,dib3000mc_impluse_noise[3]); break; default: break; } switch (mode) { case 0: /* no impulse */ /* fall through */ wr_foreach(dib3000mc_reg_imp_noise_ctl,dib3000mc_imp_noise_ctl[0]); break; case 1: /* new algo */ wr_foreach(dib3000mc_reg_imp_noise_ctl,dib3000mc_imp_noise_ctl[1]); set_or(DIB3000MC_REG_IMP_NOISE_55,DIB3000MC_IMP_NEW_ALGO(0)); /* gives 1<<10 */ break; default: /* old algo */ wr_foreach(dib3000mc_reg_imp_noise_ctl,dib3000mc_imp_noise_ctl[3]); break; } return 0;}static int dib3000mc_set_timing(struct dib3000_state *state, int upd_offset, fe_transmit_mode_t fft, fe_bandwidth_t bw){ u16 timf_msb,timf_lsb; s32 tim_offset,tim_sgn; u64 comp1,comp2,comp=0; switch (bw) { case BANDWIDTH_8_MHZ: comp = DIB3000MC_CLOCK_REF*8; break; case BANDWIDTH_7_MHZ: comp = DIB3000MC_CLOCK_REF*7; break; case BANDWIDTH_6_MHZ: comp = DIB3000MC_CLOCK_REF*6; break; default: err("unknown bandwidth (%d)",bw); break; } timf_msb = (comp >> 16) & 0xff; timf_lsb = (comp & 0xffff); // Update the timing offset ; if (upd_offset > 0) { if (!state->timing_offset_comp_done) { msleep(200); state->timing_offset_comp_done = 1; } tim_offset = rd(DIB3000MC_REG_TIMING_OFFS_MSB); if ((tim_offset & 0x2000) == 0x2000) tim_offset |= 0xC000; if (fft == TRANSMISSION_MODE_2K) tim_offset <<= 2; state->timing_offset += tim_offset; } tim_offset = state->timing_offset; if (tim_offset < 0) { tim_sgn = 1; tim_offset = -tim_offset; } else tim_sgn = 0; comp1 = (u32)tim_offset * (u32)timf_lsb ; comp2 = (u32)tim_offset * (u32)timf_msb ; comp = ((comp1 >> 16) + comp2) >> 7; if (tim_sgn == 0) comp = (u32)(timf_msb << 16) + (u32) timf_lsb + comp; else comp = (u32)(timf_msb << 16) + (u32) timf_lsb - comp ; timf_msb = (comp >> 16) & 0xff; timf_lsb = comp & 0xffff; wr(DIB3000MC_REG_TIMING_FREQ_MSB,timf_msb); wr(DIB3000MC_REG_TIMING_FREQ_LSB,timf_lsb); return 0;}static int dib3000mc_init_auto_scan(struct dib3000_state *state, fe_bandwidth_t bw, int boost){ if (boost) { wr(DIB3000MC_REG_SCAN_BOOST,DIB3000MC_SCAN_BOOST_ON); } else { wr(DIB3000MC_REG_SCAN_BOOST,DIB3000MC_SCAN_BOOST_OFF); } switch (bw) { case BANDWIDTH_8_MHZ: wr_foreach(dib3000mc_reg_bandwidth,dib3000mc_bandwidth_8mhz); break; case BANDWIDTH_7_MHZ: wr_foreach(dib3000mc_reg_bandwidth,dib3000mc_bandwidth_7mhz); break; case BANDWIDTH_6_MHZ: wr_foreach(dib3000mc_reg_bandwidth,dib3000mc_bandwidth_6mhz); break;/* case BANDWIDTH_5_MHZ: wr_foreach(dib3000mc_reg_bandwidth,dib3000mc_bandwidth_5mhz); break;*/ case BANDWIDTH_AUTO: return -EOPNOTSUPP; default: err("unknown bandwidth value (%d).",bw); return -EINVAL; } if (boost) { u32 timeout = (rd(DIB3000MC_REG_BW_TIMOUT_MSB) << 16) + rd(DIB3000MC_REG_BW_TIMOUT_LSB); timeout *= 85; timeout >>= 7; wr(DIB3000MC_REG_BW_TIMOUT_MSB,(timeout >> 16) & 0xffff); wr(DIB3000MC_REG_BW_TIMOUT_LSB,timeout & 0xffff); } return 0;}static int dib3000mc_set_adp_cfg(struct dib3000_state *state, fe_modulation_t con){ switch (con) { case QAM_64: wr_foreach(dib3000mc_reg_adp_cfg,dib3000mc_adp_cfg[2]); break; case QAM_16: wr_foreach(dib3000mc_reg_adp_cfg,dib3000mc_adp_cfg[1]); break; case QPSK: wr_foreach(dib3000mc_reg_adp_cfg,dib3000mc_adp_cfg[0]); break; case QAM_AUTO: break; default: warn("unkown constellation."); break; } return 0;}static int dib3000mc_set_general_cfg(struct dib3000_state *state, struct dvb_frontend_parameters *fep, int *auto_val){ struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm; fe_code_rate_t fe_cr = FEC_NONE; u8 fft=0, guard=0, qam=0, alpha=0, sel_hp=0, cr=0, hrch=0; int seq; switch (ofdm->transmission_mode) { case TRANSMISSION_MODE_2K: fft = DIB3000_TRANSMISSION_MODE_2K; break; case TRANSMISSION_MODE_8K: fft = DIB3000_TRANSMISSION_MODE_8K; break; case TRANSMISSION_MODE_AUTO: break; default: return -EINVAL; } switch (ofdm->guard_interval) { case GUARD_INTERVAL_1_32: guard = DIB3000_GUARD_TIME_1_32; break; case GUARD_INTERVAL_1_16: guard = DIB3000_GUARD_TIME_1_16; break; case GUARD_INTERVAL_1_8: guard = DIB3000_GUARD_TIME_1_8; break; case GUARD_INTERVAL_1_4: guard = DIB3000_GUARD_TIME_1_4; break; case GUARD_INTERVAL_AUTO: break; default: return -EINVAL; } switch (ofdm->constellation) { case QPSK: qam = DIB3000_CONSTELLATION_QPSK; break; case QAM_16: qam = DIB3000_CONSTELLATION_16QAM; break; case QAM_64: qam = DIB3000_CONSTELLATION_64QAM; break; case QAM_AUTO: break; default: return -EINVAL; } switch (ofdm->hierarchy_information) { case HIERARCHY_NONE: /* fall through */ case HIERARCHY_1: alpha = DIB3000_ALPHA_1; break; case HIERARCHY_2: alpha = DIB3000_ALPHA_2; break; case HIERARCHY_4: alpha = DIB3000_ALPHA_4; break; case HIERARCHY_AUTO: break; default: return -EINVAL; } if (ofdm->hierarchy_information == HIERARCHY_NONE) { hrch = DIB3000_HRCH_OFF; sel_hp = DIB3000_SELECT_HP; fe_cr = ofdm->code_rate_HP; } else if (ofdm->hierarchy_information != HIERARCHY_AUTO) { hrch = DIB3000_HRCH_ON; sel_hp = DIB3000_SELECT_LP; fe_cr = ofdm->code_rate_LP; } switch (fe_cr) { case FEC_1_2: cr = DIB3000_FEC_1_2; break; case FEC_2_3: cr = DIB3000_FEC_2_3; break; case FEC_3_4: cr = DIB3000_FEC_3_4; break; case FEC_5_6: cr = DIB3000_FEC_5_6; break; case FEC_7_8: cr = DIB3000_FEC_7_8; break; case FEC_NONE: break; case FEC_AUTO: break; default: return -EINVAL; } wr(DIB3000MC_REG_DEMOD_PARM,DIB3000MC_DEMOD_PARM(alpha,qam,guard,fft)); wr(DIB3000MC_REG_HRCH_PARM,DIB3000MC_HRCH_PARM(sel_hp,cr,hrch)); switch (fep->inversion) { case INVERSION_OFF: wr(DIB3000MC_REG_SET_DDS_FREQ_MSB,DIB3000MC_DDS_FREQ_MSB_INV_OFF); break; case INVERSION_AUTO: /* fall through */ case INVERSION_ON: wr(DIB3000MC_REG_SET_DDS_FREQ_MSB,DIB3000MC_DDS_FREQ_MSB_INV_ON); break; default: return -EINVAL; } seq = dib3000_seq [ofdm->transmission_mode == TRANSMISSION_MODE_AUTO] [ofdm->guard_interval == GUARD_INTERVAL_AUTO] [fep->inversion == INVERSION_AUTO]; deb_setf("seq? %d\n", seq); wr(DIB3000MC_REG_SEQ_TPS,DIB3000MC_SEQ_TPS(seq,1)); *auto_val = ofdm->constellation == QAM_AUTO || ofdm->hierarchy_information == HIERARCHY_AUTO || ofdm->guard_interval == GUARD_INTERVAL_AUTO || ofdm->transmission_mode == TRANSMISSION_MODE_AUTO || fe_cr == FEC_AUTO || fep->inversion == INVERSION_AUTO; return 0;}static int dib3000mc_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep){ struct dib3000_state* state = fe->demodulator_priv; struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm; fe_code_rate_t *cr; u16 tps_val,cr_val; int inv_test1,inv_test2; u32 dds_val, threshold = 0x1000000; if (!(rd(DIB3000MC_REG_LOCK_507) & DIB3000MC_LOCK_507)) return 0; dds_val = (rd(DIB3000MC_REG_DDS_FREQ_MSB) << 16) + rd(DIB3000MC_REG_DDS_FREQ_LSB); deb_getf("DDS_FREQ: %6x\n",dds_val); if (dds_val < threshold) inv_test1 = 0; else if (dds_val == threshold) inv_test1 = 1; else inv_test1 = 2; dds_val = (rd(DIB3000MC_REG_SET_DDS_FREQ_MSB) << 16) + rd(DIB3000MC_REG_SET_DDS_FREQ_LSB); deb_getf("DDS_SET_FREQ: %6x\n",dds_val); if (dds_val < threshold) inv_test2 = 0; else if (dds_val == threshold) inv_test2 = 1; else inv_test2 = 2; fep->inversion = ((inv_test2 == 2) && (inv_test1==1 || inv_test1==0)) || ((inv_test2 == 0) && (inv_test1==1 || inv_test1==2)) ? INVERSION_ON : INVERSION_OFF; deb_getf("inversion %d %d, %d\n", inv_test2, inv_test1, fep->inversion); fep->frequency = state->last_tuned_freq; fep->u.ofdm.bandwidth= state->last_tuned_bw; tps_val = rd(DIB3000MC_REG_TUNING_PARM); switch (DIB3000MC_TP_QAM(tps_val)) { case DIB3000_CONSTELLATION_QPSK: deb_getf("QPSK "); ofdm->constellation = QPSK; break; case DIB3000_CONSTELLATION_16QAM: deb_getf("QAM16 "); ofdm->constellation = QAM_16; break; case DIB3000_CONSTELLATION_64QAM: deb_getf("QAM64 "); ofdm->constellation = QAM_64; break; default: err("Unexpected constellation returned by TPS (%d)", tps_val); break; } if (DIB3000MC_TP_HRCH(tps_val)) { deb_getf("HRCH ON "); cr = &ofdm->code_rate_LP; ofdm->code_rate_HP = FEC_NONE; switch (DIB3000MC_TP_ALPHA(tps_val)) { case DIB3000_ALPHA_0: deb_getf("HIERARCHY_NONE "); ofdm->hierarchy_information = HIERARCHY_NONE; break; case DIB3000_ALPHA_1: deb_getf("HIERARCHY_1 "); ofdm->hierarchy_information = HIERARCHY_1; break; case DIB3000_ALPHA_2: deb_getf("HIERARCHY_2 "); ofdm->hierarchy_information = HIERARCHY_2; break; case DIB3000_ALPHA_4: deb_getf("HIERARCHY_4 "); ofdm->hierarchy_information = HIERARCHY_4; break; default: err("Unexpected ALPHA value returned by TPS (%d)", tps_val); break; } cr_val = DIB3000MC_TP_FEC_CR_LP(tps_val); } else { deb_getf("HRCH OFF "); cr = &ofdm->code_rate_HP; ofdm->code_rate_LP = FEC_NONE; ofdm->hierarchy_information = HIERARCHY_NONE; cr_val = DIB3000MC_TP_FEC_CR_HP(tps_val); } switch (cr_val) { case DIB3000_FEC_1_2: deb_getf("FEC_1_2 "); *cr = FEC_1_2; break; case DIB3000_FEC_2_3: deb_getf("FEC_2_3 "); *cr = FEC_2_3; break; case DIB3000_FEC_3_4: deb_getf("FEC_3_4 "); *cr = FEC_3_4; break; case DIB3000_FEC_5_6: deb_getf("FEC_5_6 "); *cr = FEC_4_5; break; case DIB3000_FEC_7_8: deb_getf("FEC_7_8 "); *cr = FEC_7_8; break; default: err("Unexpected FEC returned by TPS (%d)", tps_val); break; } switch (DIB3000MC_TP_GUARD(tps_val)) { case DIB3000_GUARD_TIME_1_32: deb_getf("GUARD_INTERVAL_1_32 "); ofdm->guard_interval = GUARD_INTERVAL_1_32; break; case DIB3000_GUARD_TIME_1_16: deb_getf("GUARD_INTERVAL_1_16 "); ofdm->guard_interval = GUARD_INTERVAL_1_16; break; case DIB3000_GUARD_TIME_1_8: deb_getf("GUARD_INTERVAL_1_8 "); ofdm->guard_interval = GUARD_INTERVAL_1_8; break; case DIB3000_GUARD_TIME_1_4: deb_getf("GUARD_INTERVAL_1_4 "); ofdm->guard_interval = GUARD_INTERVAL_1_4; break; default: err("Unexpected Guard Time returned by TPS (%d)", tps_val); break; } switch (DIB3000MC_TP_FFT(tps_val)) { case DIB3000_TRANSMISSION_MODE_2K: deb_getf("TRANSMISSION_MODE_2K "); ofdm->transmission_mode = TRANSMISSION_MODE_2K; break; case DIB3000_TRANSMISSION_MODE_8K: deb_getf("TRANSMISSION_MODE_8K "); ofdm->transmission_mode = TRANSMISSION_MODE_8K; break; default: err("unexpected transmission mode return by TPS (%d)", tps_val); break; } deb_getf("\n"); return 0;}static int dib3000mc_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep, int tuner){ struct dib3000_state* state = fe->demodulator_priv;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -