X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fmedia%2Fdvb%2Ffrontends%2Fdib3000mc.c;h=26e640cd43c303fbad83c9ded5b8545c1ad00849;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=8015c214072c10190a6f88a718d37f5b1c1c8dd5;hpb=87fc8d1bb10cd459024a742c6a10961fefcef18f;p=linux-2.6.git diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c index 8015c2140..26e640cd4 100644 --- a/drivers/media/dvb/frontends/dib3000mc.c +++ b/drivers/media/dvb/frontends/dib3000mc.c @@ -2,9 +2,9 @@ * Frontend driver for mobile DVB-T demodulator DiBcom 3000-MC/P * DiBcom (http://www.dibcom.fr/) * - * Copyright (C) 2004 Patrick Boettcher (patrick.boettcher@desy.de) + * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) * - * based on GPL code from DibCom, which has + * based on GPL code from DiBCom, which has * * Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr) * @@ -28,7 +28,6 @@ #include #include -#include "dvb_frontend.h" #include "dib3000-common.h" #include "dib3000mc_priv.h" #include "dib3000.h" @@ -40,14 +39,16 @@ #ifdef CONFIG_DVB_DIBCOM_DEBUG static int debug; -module_param(debug, int, 0x644); -MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=setfe,8=getfe (|-able))."); +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_tuner_pass_ctrl(struct dvb_frontend *fe, int onoff, u8 pll_addr); static int dib3000mc_set_impulse_noise(struct dib3000_state * state, int mode, fe_transmit_mode_t transmission_mode, fe_bandwidth_t bandwidth) @@ -185,46 +186,33 @@ static int dib3000mc_init_auto_scan(struct dib3000_state *state, fe_bandwidth_t return 0; } -static int dib3000mc_get_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fep); +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_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fep, int tuner) +static int dib3000mc_set_general_cfg(struct dib3000_state *state, struct dvb_frontend_parameters *fep, int *auto_val) { - struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv; struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm; fe_code_rate_t fe_cr = FEC_NONE; - int search_state, seq; - u16 val; u8 fft=0, guard=0, qam=0, alpha=0, sel_hp=0, cr=0, hrch=0; - - if (tuner) { - wr(DIB3000MC_REG_TUNER, - DIB3000_TUNER_WRITE_ENABLE(state->config.pll_addr)); - state->config.pll_set(fe, fep); - wr(DIB3000MC_REG_TUNER, - DIB3000_TUNER_WRITE_DISABLE(state->config.pll_addr)); - } - - dib3000mc_set_timing(state,0,ofdm->transmission_mode,ofdm->bandwidth); - dib3000mc_init_auto_scan(state, ofdm->bandwidth, 0); - - 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); - wr_foreach(dib3000mc_reg_adp_cfg,dib3000mc_adp_cfg[1]); - wr(DIB3000MC_REG_UNK_133,DIB3000MC_UNK_133); - - wr_foreach(dib3000mc_reg_bandwidth_general,dib3000mc_bandwidth_general); - if (ofdm->bandwidth == BANDWIDTH_8_MHZ) { - wr_foreach(dib3000mc_reg_bw,dib3000mc_bw[3]); - } else { - wr_foreach(dib3000mc_reg_bw,dib3000mc_bw[0]); - } + int seq; switch (ofdm->transmission_mode) { case TRANSMISSION_MODE_2K: fft = DIB3000_TRANSMISSION_MODE_2K; break; @@ -282,8 +270,7 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe, case INVERSION_OFF: wr(DIB3000MC_REG_SET_DDS_FREQ_MSB,DIB3000MC_DDS_FREQ_MSB_INV_OFF); break; - case INVERSION_AUTO: - break; + case INVERSION_AUTO: /* fall through */ case INVERSION_ON: wr(DIB3000MC_REG_SET_DDS_FREQ_MSB,DIB3000MC_DDS_FREQ_MSB_INV_ON); break; @@ -298,168 +285,12 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe, deb_setf("seq? %d\n", seq); wr(DIB3000MC_REG_SEQ_TPS,DIB3000MC_SEQ_TPS(seq,1)); - - 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); - - wr_foreach(dib3000mc_reg_agc_bandwidth, dib3000mc_agc_bandwidth); - - /* something has to be auto searched */ - if (ofdm->constellation == QAM_AUTO || + *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 - ) { - 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; - feps.u.ofdm.bandwidth = ofdm->bandwidth; /* bw is not auto searched */; - if (dib3000mc_get_frontend(fe, &feps) == 0) { - deb_setf("reading tuning data from frontend succeeded.\n"); - return dib3000mc_set_frontend(fe, &feps, 0); - } - } - } else { - wr(DIB3000MC_REG_ISI,DIB3000MC_ISI_DEFAULT|DIB3000MC_ISI_ACTIVATE); - wr_foreach(dib3000mc_reg_adp_cfg,dib3000mc_adp_cfg[qam]); - /* set_offset_cfg */ - wr_foreach(dib3000mc_reg_offset, - dib3000mc_offset[(ofdm->transmission_mode == TRANSMISSION_MODE_8K)+1]); - -// dib3000mc_set_timing(1,ofdm->transmission_mode,ofdm->bandwidth); - -// wr(DIB3000MC_REG_LOCK_MASK,DIB3000MC_ACTIVATE_LOCK_MASK); /* activates some locks if needed */ - -/* set_or(DIB3000MC_REG_DEMOD_PARM,DIB3000MC_DEMOD_RST_AUTO_SRCH_ON); - set_or(DIB3000MC_REG_DEMOD_PARM,DIB3000MC_DEMOD_RST_AUTO_SRCH_OFF); - wr(DIB3000MC_REG_RESTART_VIT,DIB3000MC_RESTART_VIT_ON); - wr(DIB3000MC_REG_RESTART_VIT,DIB3000MC_RESTART_VIT_OFF);*/ - } - - return 0; -} - - -static int dib3000mc_fe_init(struct dvb_frontend* fe, int mobile_mode) -{ - struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv; - - state->timing_offset = 0; - state->timing_offset_comp_done = 0; - - 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(state->config.demod_address) | - DIB3000MC_DEMOD_ADDR_ON); - - wr(DIB3000MC_REG_RST_I2C_ADDR, - DIB3000MC_DEMOD_ADDR(state->config.demod_address)); - - 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_general,dib3000mc_bandwidth_general); - wr_foreach(dib3000mc_reg_bandwidth,dib3000mc_bandwidth_8mhz); - - 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_2K,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); - - 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_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); - - wr(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) { - wr(DIB3000MC_REG_TUNER, - DIB3000_TUNER_WRITE_ENABLE(state->config->pll_addr)); - state->config->pll_init(fe); - wr(DIB3000MC_REG_TUNER, - DIB3000_TUNER_WRITE_DISABLE(state->config->pll_addr)); - }*/ + fep->inversion == INVERSION_AUTO; return 0; } @@ -476,7 +307,8 @@ static int dib3000mc_get_frontend(struct dvb_frontend* fe, if (!(rd(DIB3000MC_REG_LOCK_507) & DIB3000MC_LOCK_507)) return 0; - dds_val = ((rd(DIB3000MC_REG_DDS_FREQ_MSB) & 0xff) << 16) + rd(DIB3000MC_REG_DDS_FREQ_LSB); + 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) @@ -484,7 +316,8 @@ static int dib3000mc_get_frontend(struct dvb_frontend* fe, else inv_test1 = 2; - dds_val = ((rd(DIB3000MC_REG_SET_DDS_FREQ_MSB) & 0xff) << 16) + rd(DIB3000MC_REG_SET_DDS_FREQ_LSB); + 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) @@ -499,6 +332,9 @@ static int dib3000mc_get_frontend(struct dvb_frontend* fe, 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)) { @@ -613,10 +449,214 @@ static int dib3000mc_get_frontend(struct dvb_frontend* fe, 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 = (struct dib3000_state*) fe->demodulator_priv; + struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm; + int search_state,auto_val; + u16 val; + + if (tuner) { /* initial call from dvb */ + dib3000mc_tuner_pass_ctrl(fe,1,state->config.pll_addr(fe)); + state->config.pll_set(fe,fep,NULL); + dib3000mc_tuner_pass_ctrl(fe,0,state->config.pll_addr(fe)); + + 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; + + deb_info("init start\n"); + + state = fe->demodulator_priv; + 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) { + dib3000mc_tuner_pass_ctrl(fe,1,state->config.pll_addr(fe)); + state->config->pll_init(fe,NULL); + dib3000mc_tuner_pass_ctrl(fe,0,state->config.pll_addr(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 = (struct dib3000_state*) fe->demodulator_priv; @@ -627,12 +667,12 @@ static int dib3000mc_read_status(struct dvb_frontend* fe, fe_status_t *stat) *stat |= FE_HAS_SIGNAL; if (DIB3000MC_CARRIER_LOCK(lock)) *stat |= FE_HAS_CARRIER; - if (DIB3000MC_TPS_LOCK(lock)) /* VIT_LOCK ? */ + if (DIB3000MC_TPS_LOCK(lock)) *stat |= FE_HAS_VITERBI; if (DIB3000MC_MPEG_SYNC_LOCK(lock)) *stat |= (FE_HAS_SYNC | FE_HAS_LOCK); - deb_info("actual status is %2x\n",*stat); + 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; } @@ -659,7 +699,7 @@ static int dib3000mc_read_signal_strength(struct dvb_frontend* fe, u16 *strength u16 val = rd(DIB3000MC_REG_SIGNAL_NOISE_LSB); *strength = (((val >> 6) & 0xff) << 8) + (val & 0x3f); - deb_info("signal: mantisse = %d, exponent = %d\n",(*strength >> 8) & 0xff, *strength & 0xff); + deb_stat("signal: mantisse = %d, exponent = %d\n",(*strength >> 8) & 0xff, *strength & 0xff); return 0; } @@ -667,9 +707,8 @@ static int dib3000mc_read_signal_strength(struct dvb_frontend* fe, u16 *strength static int dib3000mc_read_snr(struct dvb_frontend* fe, u16 *snr) { struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv; - - u16 val = rd(DIB3000MC_REG_SIGNAL_NOISE_MSB), - val2 = rd(DIB3000MC_REG_SIGNAL_NOISE_LSB); + 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); @@ -679,9 +718,9 @@ static int dib3000mc_read_snr(struct dvb_frontend* fe, u16 *snr) else *snr = (u16) sig/noise; - deb_info("signal: mantisse = %d, exponent = %d\n",(sig >> 8) & 0xff, sig & 0xff); - deb_info("noise: mantisse = %d, exponent = %d\n",(noise >> 8) & 0xff, noise & 0xff); - deb_info("snr: %d\n",*snr); + 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; } @@ -698,7 +737,7 @@ static int dib3000mc_sleep(struct dvb_frontend* fe) static int dib3000mc_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) { - tune->min_delay_ms = 800; + tune->min_delay_ms = 2000; tune->step_size = 166667; tune->max_drift = 166667 * 2; @@ -718,23 +757,15 @@ static int dib3000mc_set_frontend_and_tuner(struct dvb_frontend* fe, struct dvb_ static void dib3000mc_release(struct dvb_frontend* fe) { struct dib3000_state *state = (struct dib3000_state*) fe->demodulator_priv; - dib3000_dealloc_pid_list(state); kfree(state); } /* pid filter and transfer stuff */ -static int dib3000mc_pid_control(struct dvb_frontend *fe,int pid,int onoff) +static int dib3000mc_pid_control(struct dvb_frontend *fe,int index, int pid,int onoff) { struct dib3000_state *state = fe->demodulator_priv; - int index = dib3000_get_pid_index(state->pid_list, DIB3000MC_NUM_PIDS, pid, &state->pid_list_lock,onoff); pid = (onoff ? pid | DIB3000_ACTIVATE_PID_FILTERING : 0); - - if (index >= 0) { wr(index+DIB3000MC_REG_FIRST_PID,pid); - } else { - err("no more pids for filtering."); - return -ENOMEM; - } return 0; } @@ -742,10 +773,14 @@ static int dib3000mc_fifo_control(struct dvb_frontend *fe, int onoff) { struct dib3000_state *state = (struct dib3000_state*) fe->demodulator_priv; u16 tmp = rd(DIB3000MC_REG_SMO_MODE); - deb_xfer("%s fifo",onoff ? "enabling" : "disabling"); + + 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; @@ -755,19 +790,57 @@ 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",onoff ? "enabling" : "disabling"); + + deb_xfer("%s pid parsing\n",onoff ? "enabling" : "disabling"); + if (onoff) { + deb_xfer("%d %x\n",tmp | DIB3000MC_SMO_MODE_PID_PARSE,tmp | DIB3000MC_SMO_MODE_PID_PARSE); wr(DIB3000MC_REG_SMO_MODE,tmp | DIB3000MC_SMO_MODE_PID_PARSE); } else { + deb_xfer("%d %x\n",tmp & DIB3000MC_SMO_MODE_NO_PID_PARSE,tmp & DIB3000MC_SMO_MODE_NO_PID_PARSE); 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 = (struct dib3000_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 dib3000_xfer_ops *xfer_ops) + struct i2c_adapter* i2c, struct dib_fe_xfer_ops *xfer_ops) { struct dib3000_state* state = NULL; u16 devid; @@ -790,19 +863,15 @@ struct dvb_frontend* dib3000mc_attach(const struct dib3000_config* config, if (devid != DIB3000MC_DEVICE_ID && devid != DIB3000P_DEVICE_ID) goto error; - switch (devid) { case DIB3000MC_DEVICE_ID: - info("Found a DiBcom 3000-MC."); + info("Found a DiBcom 3000-MC, interesting..."); break; case DIB3000P_DEVICE_ID: info("Found a DiBcom 3000-P."); break; } - if (dib3000_init_pid_list(state,DIB3000MC_NUM_PIDS)) - goto error; - /* create dvb_frontend */ state->frontend.ops = &state->ops; state->frontend.demodulator_priv = state; @@ -811,6 +880,9 @@ struct dvb_frontend* dib3000mc_attach(const struct dib3000_config* config, 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; @@ -834,6 +906,7 @@ static struct dvb_frontend_ops dib3000mc_ops = { 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, },