drx397xd.c
来自「trident tm5600的linux驱动」· C语言 代码 · 共 1,600 行 · 第 1/3 页
C
1,600 行
(u64)ebx) - 0x800000; EXIT_RC(WR16(s, 0x0c50010, ebx & 0xffff)); EXIT_RC(WR16(s, 0x0c50011, ebx >> 16)); /* drx397xD oscillator calibration */ ebx = div64_u64(((u64) (s->config.f_if + df_tuner) << 28) + (s->f_osc >> 1), (u64)s->f_osc); } ebx &= 0xfffffff; if (fep->inversion == INVERSION_ON) ebx = 0x10000000 - ebx; EXIT_RC(WR16(s, 0x0c30010, ebx & 0xffff)); EXIT_RC(WR16(s, 0x0c30011, ebx >> 16)); EXIT_RC(WR16(s, 0x0800000, 1)); EXIT_RC(RD16(s, 0x0800000));#if 0 rc = WR16(s, 0x0810000, 1); if (rc < 0) goto exit_rc;#endif EXIT_RC(SC_WaitForReady(s)); EXIT_RC(WR16(s, 0x0820042, 0)); EXIT_RC(WR16(s, 0x0820041, v22)); EXIT_RC(WR16(s, 0x0820040, edi)); EXIT_RC(SC_SendCommand(s, 3)); rc = RD16(s, 0x0800000); SC_WaitForReady(s); WR16(s, 0x0820042, 0); WR16(s, 0x0820041, 1); WR16(s, 0x0820040, 1); SC_SendCommand(s, 1);#if 0 rc = WR16(s, 0x2150000, 1); if (rc < 0) goto exit_rc;#endif rc = WR16(s, 0x2150000, 2); rc = WR16(s, 0x2150016, a); rc = WR16(s, 0x2150010, 4); rc = WR16(s, 0x2150036, 0); rc = WR16(s, 0x2150000, 1); s->config.d60 = 2;exit_rc: return rc;}/******************************************************************************* * DVB interface ******************************************************************************/static int drx397x_init(struct dvb_frontend *fe){ struct drx397xD_state *s = fe->demodulator_priv; int rc; pr_debug("%s\n", __func__); s->config.rfagc.d00 = 2; /* 0x7c */ s->config.rfagc.w04 = 0; s->config.rfagc.w06 = 0x3ff; s->config.ifagc.d00 = 0; /* 0x68 */ s->config.ifagc.w04 = 0; s->config.ifagc.w06 = 140; s->config.ifagc.w08 = 0; s->config.ifagc.w0A = 0x3ff; s->config.ifagc.w0C = 0x388; /* for signal strenght calculations */ s->config.ss76 = 820; s->config.ss78 = 2200; s->config.ss7A = 150; /* HI_CfgCommand */ s->config.w50 = 4; s->config.w52 = 9; s->config.f_if = 42800000; /* d14: intermediate frequency [Hz] */ s->config.f_osc = 48000; /* s66 : oscillator frequency [kHz] */ s->config.w92 = 12000; s->config.w9C = 0x000e; s->config.w9E = 0x0000; /* ConfigureMPEGOutput params */ s->config.wA0 = 4; s->config.w98 = 1; s->config.w9A = 1; /* get chip revision */ rc = RD16(s, 0x2410019); if (rc < 0) return -ENODEV; if (rc == 0) { printk(KERN_INFO "%s: chip revision A2\n", mod_name); rc = drx_load_fw(s, DRXD_FW_A2); } else { rc = (rc >> 12) - 3; switch (rc) { case 1: s->flags |= F_SET_0D4h; case 0: case 4: s->flags |= F_SET_0D0h; break; case 2: case 5: break; case 3: s->flags |= F_SET_0D4h; break; default: return -ENODEV; }; printk(KERN_INFO "%s: chip revision B1.%d\n", mod_name, rc); rc = drx_load_fw(s, DRXD_FW_B1); } if (rc < 0) goto error; rc = WR16(s, 0x0420033, 0x3973); if (rc < 0) goto error; rc = HI_Command(s, 2); msleep(1); if (s->chip_rev == DRXD_FW_A2) { rc = WR16(s, 0x043012d, 0x47F); if (rc < 0) goto error; } rc = WR16_E0(s, 0x0400000, 0); if (rc < 0) goto error; if (s->config.w92 > 20000 || s->config.w92 % 4000) { printk(KERN_ERR "%s: invalid osc frequency\n", mod_name); rc = -1; goto error; } rc = WR16(s, 0x2410010, 1); if (rc < 0) goto error; rc = WR16(s, 0x2410011, 0x15); if (rc < 0) goto error; rc = WR16(s, 0x2410012, s->config.w92 / 4000); if (rc < 0) goto error;#ifdef ORIG_FW rc = WR16(s, 0x2410015, 2); if (rc < 0) goto error;#endif rc = WR16(s, 0x2410017, 0x3973); if (rc < 0) goto error; s->f_osc = s->config.f_osc * 1000; /* initial estimator */#if 0 { int deviation, val, edi; /* osc_deviation(struct state *x, int deviation, int io) * * io == 0 : read_deviation from eeprom * io != 0 : write deviation to eeprom */ s->config.w64 = x->osc_deviation(x, 0, 0); val = s->config.w64 * s->config.w66; deviation = val / 1000000; edi = 2; if (val <= 0) edi = -2; val = val % 1000000; if (edi * val > 1000000) deviation += edi >> 1; s->clk_if_corrected += deviation; }#endif s->config.w56 = 1; rc = HI_CfgCommand(s); if (rc < 0) goto error; rc = write_fw(s, DRXD_InitAtomicRead); if (rc < 0) goto error; if (s->chip_rev == DRXD_FW_A2) { rc = WR16(s, 0x2150013, 0); if (rc < 0) goto error; } rc = WR16_E0(s, 0x0400002, 0); if (rc < 0) goto error; rc = WR16(s, 0x0400002, 0); if (rc < 0) goto error; if (s->chip_rev == DRXD_FW_A2) { rc = write_fw(s, DRXD_ResetCEFR); if (rc < 0) goto error; } rc = write_fw(s, DRXD_microcode); if (rc < 0) goto error; s->config.w9C = 0x0e; if (s->flags & F_SET_0D0h) { s->config.w9C = 0; rc = RD16(s, 0x0c20010); if (rc < 0) goto write_DRXD_InitFE_1; rc &= ~0x1000; rc = WR16(s, 0x0c20010, rc); if (rc < 0) goto write_DRXD_InitFE_1; rc = RD16(s, 0x0c20011); if (rc < 0) goto write_DRXD_InitFE_1; rc &= ~0x8; rc = WR16(s, 0x0c20011, rc); if (rc < 0) goto write_DRXD_InitFE_1; rc = WR16(s, 0x0c20012, 1); }write_DRXD_InitFE_1: rc = write_fw(s, DRXD_InitFE_1); if (rc < 0) goto error; rc = 1; if (s->chip_rev == DRXD_FW_B1) { if (s->flags & F_SET_0D0h) rc = 0; } else { if (s->flags & F_SET_0D0h) rc = 4; } rc = WR16(s, 0x0C20012, rc); if (rc < 0) goto error; rc = WR16(s, 0x0C20013, s->config.w9E); if (rc < 0) goto error; rc = WR16(s, 0x0C20015, s->config.w9C); if (rc < 0) goto error; rc = write_fw(s, DRXD_InitFE_2); if (rc < 0) goto error; rc = write_fw(s, DRXD_InitFT); if (rc < 0) goto error; rc = write_fw(s, DRXD_InitCP); if (rc < 0) goto error; rc = write_fw(s, DRXD_InitCE); if (rc < 0) goto error; rc = write_fw(s, DRXD_InitEQ); if (rc < 0) goto error; rc = write_fw(s, DRXD_InitEC); if (rc < 0) goto error; rc = write_fw(s, DRXD_InitSC); if (rc < 0) goto error; rc = SetCfgIfAgc(s, &s->config.ifagc); if (rc < 0) goto error; rc = SetCfgRfAgc(s, &s->config.rfagc); if (rc < 0) goto error;#if 1 rc = ConfigureMPEGOutput(s, 1); rc = WR16(s, 0x08201fe, 0x0017); rc = WR16(s, 0x08201ff, 0x0101); s->config.d5C = 0;#else s->config.d5C = 0; rc = CorrectSysClockDeviation(s); if (rc < 0) goto error;// rc = ConfigureWR16(s, 0x0420033, 0x200); rc = WR16(s, 0x0800000, 0); if (rc < 0) goto error; rc = WR16(s, 0x2800000, 0);#endif s->config.d60 = 1; s->config.d48 = 1;error: return rc;}static int drx397x_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *params){ return 0;}static int drx397x_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *params){ struct drx397xD_state *s = fe->demodulator_priv; s->config.s20d24 = 1; return drx_tune(s, params);}static int drx397x_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *fe_tune_settings){ fe_tune_settings->min_delay_ms = 10000; fe_tune_settings->step_size = 0; fe_tune_settings->max_drift = 0; return 0;}static int drx397x_read_status(struct dvb_frontend *fe, fe_status_t *status){ struct drx397xD_state *s = fe->demodulator_priv; int lockstat; GetLockStatus(s, &lockstat);#if 0 /* TODO */ if (lockstat & 1) CorrectSysClockDeviation(s);#endif *status = 0; if (lockstat & 2) { CorrectSysClockDeviation(s); ConfigureMPEGOutput(s, 1); *status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI; } if (lockstat & 4) *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; return 0;}static int drx397x_read_ber(struct dvb_frontend *fe, unsigned int *ber){ *ber = 0; return 0;}static int drx397x_read_snr(struct dvb_frontend *fe, u16 *snr){ *snr = 0; return 0;}static int drx397x_read_signal_strength(struct dvb_frontend *fe, u16 *strength){ struct drx397xD_state *s = fe->demodulator_priv; int rc; if (s->config.ifagc.d00 == 2) { *strength = 0xffff; return 0; } rc = RD16(s, 0x0c20035); if (rc < 0) { *strength = 0; return 0; } rc &= 0x3ff; /* Signal strength is calculated using the following formula: * * a = 2200 * 150 / (2200 + 150); * a = a * 3300 / (a + 820); * b = 2200 * 3300 / (2200 + 820); * c = (((b-a) * rc) >> 10 + a) << 4; * strength = ~c & 0xffff; * * The following does the same but with less rounding errors: */ *strength = ~(7720 + (rc * 30744 >> 10)); return 0;}static int drx397x_read_ucblocks(struct dvb_frontend *fe, unsigned int *ucblocks){ *ucblocks = 0; return 0;}static int drx397x_sleep(struct dvb_frontend *fe){ return 0;}static void drx397x_release(struct dvb_frontend *fe){ struct drx397xD_state *s = fe->demodulator_priv; printk(KERN_INFO "%s: release demodulator\n", mod_name); if (s) { drx_release_fw(s); kfree(s); }}static struct dvb_frontend_ops drx397x_ops = { .info = { .name = "Micronas DRX397xD DVB-T Frontend", .type = FE_OFDM, .frequency_min = 47125000, .frequency_max = 855250000, .frequency_stepsize = 166667, .frequency_tolerance = 0, .caps = /* 0x0C01B2EAE */ FE_CAN_FEC_1_2 | /* = 0x2, */ FE_CAN_FEC_2_3 | /* = 0x4, */ FE_CAN_FEC_3_4 | /* = 0x8, */ FE_CAN_FEC_5_6 | /* = 0x20, */ FE_CAN_FEC_7_8 | /* = 0x80, */ FE_CAN_FEC_AUTO | /* = 0x200, */ FE_CAN_QPSK | /* = 0x400, */ FE_CAN_QAM_16 | /* = 0x800, */ FE_CAN_QAM_64 | /* = 0x2000, */ FE_CAN_QAM_AUTO | /* = 0x10000, */ FE_CAN_TRANSMISSION_MODE_AUTO | /* = 0x20000, */ FE_CAN_GUARD_INTERVAL_AUTO | /* = 0x80000, */ FE_CAN_HIERARCHY_AUTO | /* = 0x100000, */ FE_CAN_RECOVER | /* = 0x40000000, */ FE_CAN_MUTE_TS /* = 0x80000000 */ }, .release = drx397x_release, .init = drx397x_init, .sleep = drx397x_sleep, .set_frontend = drx397x_set_frontend, .get_tune_settings = drx397x_get_tune_settings, .get_frontend = drx397x_get_frontend, .read_status = drx397x_read_status, .read_snr = drx397x_read_snr, .read_signal_strength = drx397x_read_signal_strength, .read_ber = drx397x_read_ber, .read_ucblocks = drx397x_read_ucblocks,};struct dvb_frontend *drx397xD_attach(const struct drx397xD_config *config, struct i2c_adapter *i2c){ struct drx397xD_state *state; /* allocate memory for the internal state */ state = kzalloc(sizeof(struct drx397xD_state), GFP_KERNEL); if (!state) goto error; /* setup the state */ state->i2c = i2c; memcpy(&state->config, config, sizeof(struct drx397xD_config)); /* check if the demod is there */ if (RD16(state, 0x2410019) < 0) goto error; /* create dvb_frontend */ memcpy(&state->frontend.ops, &drx397x_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; return &state->frontend;error: kfree(state); return NULL;}EXPORT_SYMBOL(drx397xD_attach);MODULE_DESCRIPTION("Micronas DRX397xD DVB-T Frontend");MODULE_AUTHOR("Henk Vergonet");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?