?? dib7000m.c
字號:
schan.u.ofdm.code_rate_HP = FEC_2_3; schan.u.ofdm.code_rate_LP = FEC_3_4; schan.u.ofdm.hierarchy_information = 0; dib7000m_set_channel(state, &schan, 7); factor = BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth); if (factor >= 5000) factor = 1; else factor = 6; // always use the setting for 8MHz here lock_time for 7,6 MHz are longer value = 30 * state->internal_clk * factor; ret |= dib7000m_write_word(state, 6, (u16) ((value >> 16) & 0xffff)); // lock0 wait time ret |= dib7000m_write_word(state, 7, (u16) (value & 0xffff)); // lock0 wait time value = 100 * state->internal_clk * factor; ret |= dib7000m_write_word(state, 8, (u16) ((value >> 16) & 0xffff)); // lock1 wait time ret |= dib7000m_write_word(state, 9, (u16) (value & 0xffff)); // lock1 wait time value = 500 * state->internal_clk * factor; ret |= dib7000m_write_word(state, 10, (u16) ((value >> 16) & 0xffff)); // lock2 wait time ret |= dib7000m_write_word(state, 11, (u16) (value & 0xffff)); // lock2 wait time // start search value = dib7000m_read_word(state, 0); ret |= dib7000m_write_word(state, 0, (u16) (value | (1 << 9))); /* clear n_irq_pending */ if (state->revision == 0x4000) dib7000m_write_word(state, 1793, 0); else dib7000m_read_word(state, 537); ret |= dib7000m_write_word(state, 0, (u16) value); return ret;}static int dib7000m_autosearch_irq(struct dib7000m_state *state, u16 reg){ u16 irq_pending = dib7000m_read_word(state, reg); if (irq_pending & 0x1) { // failed dprintk( "autosearch failed"); return 1; } if (irq_pending & 0x2) { // succeeded dprintk( "autosearch succeeded"); return 2; } return 0; // still pending}static int dib7000m_autosearch_is_irq(struct dvb_frontend *demod){ struct dib7000m_state *state = demod->demodulator_priv; if (state->revision == 0x4000) return dib7000m_autosearch_irq(state, 1793); else return dib7000m_autosearch_irq(state, 537);}static int dib7000m_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch){ struct dib7000m_state *state = demod->demodulator_priv; int ret = 0; u16 value; // we are already tuned - just resuming from suspend if (ch != NULL) dib7000m_set_channel(state, ch, 0); else return -EINVAL; // restart demod ret |= dib7000m_write_word(state, 898, 0x4000); ret |= dib7000m_write_word(state, 898, 0x0000); msleep(45); dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_CRY_ESRAM_MOUT_NUD); /* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=0, P_ctrl_alpha_isi=3, P_ctrl_inh_cor4=1, P_ctrl_alpha_cor4=3 */ ret |= dib7000m_write_word(state, 29, (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3)); // never achieved a lock before - wait for timfreq to update if (state->timf == 0) msleep(200); //dump_reg(state); /* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */ value = (6 << 8) | 0x80; switch (ch->u.ofdm.transmission_mode) { case TRANSMISSION_MODE_2K: value |= (7 << 12); break; case /* 4K MODE */ 255: value |= (8 << 12); break; default: case TRANSMISSION_MODE_8K: value |= (9 << 12); break; } ret |= dib7000m_write_word(state, 26, value); /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */ value = (0 << 4); switch (ch->u.ofdm.transmission_mode) { case TRANSMISSION_MODE_2K: value |= 0x6; break; case /* 4K MODE */ 255: value |= 0x7; break; default: case TRANSMISSION_MODE_8K: value |= 0x8; break; } ret |= dib7000m_write_word(state, 32, value); /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */ value = (0 << 4); switch (ch->u.ofdm.transmission_mode) { case TRANSMISSION_MODE_2K: value |= 0x6; break; case /* 4K MODE */ 255: value |= 0x7; break; default: case TRANSMISSION_MODE_8K: value |= 0x8; break; } ret |= dib7000m_write_word(state, 33, value); // we achieved a lock - it's time to update the timf freq if ((dib7000m_read_word(state, 535) >> 6) & 0x1) dib7000m_update_timf(state); dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); return ret;}static int dib7000m_wakeup(struct dvb_frontend *demod){ struct dib7000m_state *state = demod->demodulator_priv; dib7000m_set_power_mode(state, DIB7000M_POWER_ALL); if (dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0) dprintk( "could not start Slow ADC"); return 0;}static int dib7000m_sleep(struct dvb_frontend *demod){ struct dib7000m_state *st = demod->demodulator_priv; dib7000m_set_output_mode(st, OUTMODE_HIGH_Z); dib7000m_set_power_mode(st, DIB7000M_POWER_INTERFACE_ONLY); return dib7000m_set_adc_state(st, DIBX000_SLOW_ADC_OFF) | dib7000m_set_adc_state(st, DIBX000_ADC_OFF);}static int dib7000m_identify(struct dib7000m_state *state){ u16 value; if ((value = dib7000m_read_word(state, 896)) != 0x01b3) { dprintk( "wrong Vendor ID (0x%x)",value); return -EREMOTEIO; } state->revision = dib7000m_read_word(state, 897); if (state->revision != 0x4000 && state->revision != 0x4001 && state->revision != 0x4002 && state->revision != 0x4003) { dprintk( "wrong Device ID (0x%x)",value); return -EREMOTEIO; } /* protect this driver to be used with 7000PC */ if (state->revision == 0x4000 && dib7000m_read_word(state, 769) == 0x4000) { dprintk( "this driver does not work with DiB7000PC"); return -EREMOTEIO; } switch (state->revision) { case 0x4000: dprintk( "found DiB7000MA/PA/MB/PB"); break; case 0x4001: state->reg_offs = 1; dprintk( "found DiB7000HC"); break; case 0x4002: state->reg_offs = 1; dprintk( "found DiB7000MC"); break; case 0x4003: state->reg_offs = 1; dprintk( "found DiB9000"); break; } return 0;}static int dib7000m_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep){ struct dib7000m_state *state = fe->demodulator_priv; u16 tps = dib7000m_read_word(state,480); fep->inversion = INVERSION_AUTO; fep->u.ofdm.bandwidth = state->current_bandwidth; switch ((tps >> 8) & 0x3) { case 0: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; break; case 1: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; break; /* case 2: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_4K; break; */ } switch (tps & 0x3) { case 0: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; break; case 1: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; break; case 2: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; break; case 3: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; break; } switch ((tps >> 14) & 0x3) { case 0: fep->u.ofdm.constellation = QPSK; break; case 1: fep->u.ofdm.constellation = QAM_16; break; case 2: default: fep->u.ofdm.constellation = QAM_64; break; } /* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */ /* (tps >> 13) & 0x1 == hrch is used, (tps >> 10) & 0x7 == alpha */ fep->u.ofdm.hierarchy_information = HIERARCHY_NONE; switch ((tps >> 5) & 0x7) { case 1: fep->u.ofdm.code_rate_HP = FEC_1_2; break; case 2: fep->u.ofdm.code_rate_HP = FEC_2_3; break; case 3: fep->u.ofdm.code_rate_HP = FEC_3_4; break; case 5: fep->u.ofdm.code_rate_HP = FEC_5_6; break; case 7: default: fep->u.ofdm.code_rate_HP = FEC_7_8; break; } switch ((tps >> 2) & 0x7) { case 1: fep->u.ofdm.code_rate_LP = FEC_1_2; break; case 2: fep->u.ofdm.code_rate_LP = FEC_2_3; break; case 3: fep->u.ofdm.code_rate_LP = FEC_3_4; break; case 5: fep->u.ofdm.code_rate_LP = FEC_5_6; break; case 7: default: fep->u.ofdm.code_rate_LP = FEC_7_8; break; } /* native interleaver: (dib7000m_read_word(state, 481) >> 5) & 0x1 */ return 0;}static int dib7000m_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep){ struct dib7000m_state *state = fe->demodulator_priv; int time, ret; dib7000m_set_output_mode(state, OUTMODE_HIGH_Z); state->current_bandwidth = fep->u.ofdm.bandwidth; dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth)); if (fe->ops.tuner_ops.set_params) fe->ops.tuner_ops.set_params(fe, fep); /* start up the AGC */ state->agc_state = 0; do { time = dib7000m_agc_startup(fe, fep); if (time != -1) msleep(time); } while (time != -1); if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO || fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO || fep->u.ofdm.constellation == QAM_AUTO || fep->u.ofdm.code_rate_HP == FEC_AUTO) { int i = 800, found; dib7000m_autosearch_start(fe, fep); do { msleep(1); found = dib7000m_autosearch_is_irq(fe); } while (found == 0 && i--); dprintk("autosearch returns: %d",found); if (found == 0 || found == 1) return 0; // no channel found dib7000m_get_frontend(fe, fep); } ret = dib7000m_tune(fe, fep); /* make this a config parameter */ dib7000m_set_output_mode(state, OUTMODE_MPEG2_FIFO); return ret;}static int dib7000m_read_status(struct dvb_frontend *fe, fe_status_t *stat){ struct dib7000m_state *state = fe->demodulator_priv; u16 lock = dib7000m_read_word(state, 535); *stat = 0; if (lock & 0x8000) *stat |= FE_HAS_SIGNAL; if (lock & 0x3000) *stat |= FE_HAS_CARRIER; if (lock & 0x0100) *stat |= FE_HAS_VITERBI; if (lock & 0x0010) *stat |= FE_HAS_SYNC; if (lock & 0x0008) *stat |= FE_HAS_LOCK; return 0;}static int dib7000m_read_ber(struct dvb_frontend *fe, u32 *ber){ struct dib7000m_state *state = fe->demodulator_priv; *ber = (dib7000m_read_word(state, 526) << 16) | dib7000m_read_word(state, 527); return 0;}static int dib7000m_read_unc_blocks(struct dvb_frontend *fe, u32 *unc){ struct dib7000m_state *state = fe->demodulator_priv; *unc = dib7000m_read_word(state, 534); return 0;}static int dib7000m_read_signal_strength(struct dvb_frontend *fe, u16 *strength){ struct dib7000m_state *state = fe->demodulator_priv; u16 val = dib7000m_read_word(state, 390); *strength = 65535 - val; return 0;}static int dib7000m_read_snr(struct dvb_frontend* fe, u16 *snr){ *snr = 0x0000; return 0;}static int dib7000m_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune){ tune->min_delay_ms = 1000; return 0;}static void dib7000m_release(struct dvb_frontend *demod){ struct dib7000m_state *st = demod->demodulator_priv; dibx000_exit_i2c_master(&st->i2c_master); kfree(st);}struct i2c_adapter * dib7000m_get_i2c_master(struct dvb_frontend *demod, enum dibx000_i2c_interface intf, int gating){ struct dib7000m_state *st = demod->demodulator_priv; return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);}EXPORT_SYMBOL(dib7000m_get_i2c_master);#if 0 /* keep *//* used with some prototype boards */int dib7000m_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000m_config cfg[]){ struct dib7000m_state st = { .i2c_adap = i2c }; int k = 0; u8 new_addr = 0; for (k = no_of_demods-1; k >= 0; k--) { st.cfg = cfg[k]; /* designated i2c address */ new_addr = (0x40 + k) << 1; st.i2c_addr = new_addr; if (dib7000m_identify(&st) != 0) { st.i2c_addr = default_addr; if (dib7000m_identify(&st) != 0) { dprintk("DiB7000M #%d: not identified", k); return -EIO; } } /* start diversity to pull_down div_str - just for i2c-enumeration */ dib7000m_set_output_mode(&st, OUTMODE_DIVERSITY); dib7000m_write_word(&st, 1796, 0x0); // select DVB-T output /* set new i2c address and force divstart */ dib7000m_write_word(&st, 1794, (new_addr << 2) | 0x2); dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr); } for (k = 0; k < no_of_demods; k++) { st.cfg = cfg[k]; st.i2c_addr = (0x40 + k) << 1; // unforce divstr dib7000m_write_word(&st,1794, st.i2c_addr << 2); /* deactivate div - it was just for i2c-enumeration */ dib7000m_set_output_mode(&st, OUTMODE_HIGH_Z); } return 0;}EXPORT_SYMBOL(dib7000m_i2c_enumeration);#endifstatic struct dvb_frontend_ops dib7000m_ops;struct dvb_frontend * dib7000m_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000m_config *cfg){ struct dvb_frontend *demod; struct dib7000m_state *st; st = kzalloc(sizeof(struct dib7000m_state), GFP_KERNEL); if (st == NULL) return NULL; memcpy(&st->cfg, cfg, sizeof(struct dib7000m_config)); st->i2c_adap = i2c_adap; st->i2c_addr = i2c_addr; demod = &st->demod; demod->demodulator_priv = st; memcpy(&st->demod.ops, &dib7000m_ops, sizeof(struct dvb_frontend_ops)); st->timf_default = cfg->bw->timf; if (dib7000m_identify(st) != 0) goto error; if (st->revision == 0x4000) dibx000_init_i2c_master(&st->i2c_master, DIB7000, st->i2c_adap, st->i2c_addr); else dibx000_init_i2c_master(&st->i2c_master, DIB7000MC, st->i2c_adap, st->i2c_addr); dib7000m_demod_reset(st); return demod;error: kfree(st); return NULL;}EXPORT_SYMBOL(dib7000m_attach);static struct dvb_frontend_ops dib7000m_ops = { .info = { .name = "DiBcom 7000MA/MB/PA/PB/MC", .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 = dib7000m_release, .init = dib7000m_wakeup, .sleep = dib7000m_sleep, .set_frontend = dib7000m_set_frontend, .get_tune_settings = dib7000m_fe_get_tune_settings, .get_frontend = dib7000m_get_frontend, .read_status = dib7000m_read_status, .read_ber = dib7000m_read_ber, .read_signal_strength = dib7000m_read_signal_strength, .read_snr = dib7000m_read_snr, .read_ucblocks = dib7000m_read_unc_blocks,};MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");MODULE_DESCRIPTION("Driver for the DiBcom 7000MA/MB/PA/PB/MC COFDM demodulator");MODULE_LICENSE("GPL");
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -