X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fmedia%2Fdvb%2Ffrontends%2Fdib3000mc.c;h=3b303dbb61565db54ed15b4bbab810be2c622860;hb=43bc926fffd92024b46cafaf7350d669ba9ca884;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..3b303dbb6 100644 --- a/drivers/media/dvb/frontends/dib3000mc.c +++ b/drivers/media/dvb/frontends/dib3000mc.c @@ -1,10 +1,10 @@ /* - * Frontend driver for mobile DVB-T demodulator DiBcom 3000-MC/P + * Frontend driver for mobile DVB-T demodulator DiBcom 3000P/M-C * 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) * @@ -22,32 +22,32 @@ */ #include #include -#include #include #include #include #include +#include +#include -#include "dvb_frontend.h" #include "dib3000-common.h" #include "dib3000mc_priv.h" #include "dib3000.h" /* Version information */ #define DRIVER_VERSION "0.1" -#define DRIVER_DESC "DiBcom 3000-MC DVB-T demodulator driver" +#define DRIVER_DESC "DiBcom 3000M-C DVB-T demodulator" #define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@desy.de" #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_set_impulse_noise(struct dib3000_state * state, int mode, fe_transmit_mode_t transmission_mode, fe_bandwidth_t bandwidth) @@ -185,46 +185,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; @@ -235,13 +222,13 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe, 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_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 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; @@ -256,13 +243,13 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe, default: return -EINVAL; } if (ofdm->hierarchy_information == HIERARCHY_NONE) { - hrch = DIB3000_HRCH_OFF; + hrch = DIB3000_HRCH_OFF; sel_hp = DIB3000_SELECT_HP; - fe_cr = ofdm->code_rate_HP; + fe_cr = ofdm->code_rate_HP; } else if (ofdm->hierarchy_information != HIERARCHY_AUTO) { - hrch = DIB3000_HRCH_ON; + hrch = DIB3000_HRCH_ON; sel_hp = DIB3000_SELECT_LP; - fe_cr = ofdm->code_rate_LP; + fe_cr = ofdm->code_rate_LP; } switch (fe_cr) { case FEC_1_2: cr = DIB3000_FEC_1_2; break; @@ -282,8 +269,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,175 +284,19 @@ 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 || - 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)); - }*/ + *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 = (struct dib3000_state*) fe->demodulator_priv; + 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; @@ -476,7 +306,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 +315,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 +331,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)) { @@ -517,7 +352,7 @@ static int dib3000mc_get_frontend(struct dvb_frontend* fe, default: err("Unexpected constellation returned by TPS (%d)", tps_val); break; - } + } if (DIB3000MC_TP_HRCH(tps_val)) { deb_getf("HRCH ON "); @@ -614,12 +449,208 @@ static int dib3000mc_get_frontend(struct dvb_frontend* fe, 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; + 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 = (struct dib3000_state*) fe->demodulator_priv; + struct dib3000_state* state = fe->demodulator_priv; u16 lock = rd(DIB3000MC_REG_LOCKING); *stat = 0; @@ -627,49 +658,48 @@ 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; } static int dib3000mc_read_ber(struct dvb_frontend* fe, u32 *ber) { - struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv; + 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 = (struct dib3000_state*) fe->demodulator_priv; + struct dib3000_state* state = fe->demodulator_priv; - *unc = rd(DIB3000MC_REG_PACKET_ERROR_COUNT); + *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 = (struct dib3000_state*) fe->demodulator_priv; + struct dib3000_state* state = fe->demodulator_priv; 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; } /* see dib3000mb.c for calculation comments */ 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); + 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); @@ -679,15 +709,15 @@ 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; } static int dib3000mc_sleep(struct dvb_frontend* fe) { - struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv; + 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); @@ -698,10 +728,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->step_size = 166667; - tune->max_drift = 166667 * 2; - + tune->min_delay_ms = 1000; return 0; } @@ -717,35 +744,31 @@ 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); + struct dib3000_state *state = fe->demodulator_priv; 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; - } + wr(index+DIB3000MC_REG_FIRST_PID,pid); return 0; } static int dib3000mc_fifo_control(struct dvb_frontend *fe, int onoff) { - struct dib3000_state *state = (struct dib3000_state*) fe->demodulator_priv; + struct dib3000_state *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,7 +778,9 @@ 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) { wr(DIB3000MC_REG_SMO_MODE,tmp | DIB3000MC_SMO_MODE_PID_PARSE); } else { @@ -764,16 +789,50 @@ static int dib3000mc_pid_parse(struct dvb_frontend *fe, int onoff) 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 dib3000_xfer_ops *xfer_ops) + 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 = (struct dib3000_state*) kmalloc(sizeof(struct dib3000_state), GFP_KERNEL); + state = kzalloc(sizeof(struct dib3000_state), GFP_KERNEL); if (state == NULL) goto error; @@ -790,19 +849,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 3000M-C, interesting..."); break; case DIB3000P_DEVICE_ID: - info("Found a DiBcom 3000-P."); + info("Found a DiBcom 3000P."); 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,22 +866,24 @@ 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; error: - if (state) - kfree(state); + kfree(state); return NULL; } static struct dvb_frontend_ops dib3000mc_ops = { .info = { - .name = "DiBcom 3000-MC/P DVB-T", - .type = FE_OFDM, - .frequency_min = 44250000, - .frequency_max = 867250000, + .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 | @@ -834,6 +891,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, },