📄 tda80xx.c
字号:
state->code_rate = fec_tab[val & 0x07]; if (state->status & (FE_HAS_SYNC | FE_HAS_LOCK)) state->spectral_inversion = inv_tab[(val >> 7) & 0x01]; else state->spectral_inversion = INVERSION_AUTO; } else { state->code_rate = FEC_AUTO; }}static void tda80xx_worklet(void *priv){ struct tda80xx_state *state = priv; tda80xx_writereg(state, 0x00, 0x04); enable_irq(state->config->irq); tda80xx_read_status_int(state);}static void tda80xx_wait_diseqc_fifo(struct tda80xx_state* state){ size_t i; for (i = 0; i < 100; i++) { if (tda80xx_readreg(state, 0x02) & 0x80) break; msleep(10); }}static int tda8044_init(struct dvb_frontend* fe){ struct tda80xx_state* state = fe->demodulator_priv; int ret; /* * this function is a mess... */ if ((ret = tda80xx_write(state, 0x00, tda8044_inittab_pre, sizeof(tda8044_inittab_pre)))) return ret; tda80xx_writereg(state, 0x0f, 0x50);#if 1 tda80xx_writereg(state, 0x20, 0x8F); /* FIXME */ tda80xx_writereg(state, 0x20, state->config->volt18setting); /* FIXME */ //tda80xx_writereg(state, 0x00, 0x04); tda80xx_writereg(state, 0x00, 0x0C);#endif //tda80xx_writereg(state, 0x00, 0x08); /* Reset AFC1 loop filter */ tda80xx_write(state, 0x00, tda8044_inittab_post, sizeof(tda8044_inittab_post)); if (state->config->pll_init) { tda80xx_writereg(state, 0x1c, 0x80); state->config->pll_init(fe); tda80xx_writereg(state, 0x1c, 0x00); } return 0;}static int tda8083_init(struct dvb_frontend* fe){ struct tda80xx_state* state = fe->demodulator_priv; tda80xx_write(state, 0x00, tda8083_inittab, sizeof(tda8083_inittab)); if (state->config->pll_init) { tda80xx_writereg(state, 0x1c, 0x80); state->config->pll_init(fe); tda80xx_writereg(state, 0x1c, 0x00); } return 0;}static int tda80xx_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage){ struct tda80xx_state* state = fe->demodulator_priv; switch (voltage) { case SEC_VOLTAGE_13: return tda80xx_writereg(state, 0x20, state->config->volt13setting); case SEC_VOLTAGE_18: return tda80xx_writereg(state, 0x20, state->config->volt18setting); case SEC_VOLTAGE_OFF: return tda80xx_writereg(state, 0x20, 0); default: return -EINVAL; }}static int tda80xx_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone){ struct tda80xx_state* state = fe->demodulator_priv; switch (tone) { case SEC_TONE_OFF: return tda80xx_writereg(state, 0x29, 0x00); case SEC_TONE_ON: return tda80xx_writereg(state, 0x29, 0x80); default: return -EINVAL; }}static int tda80xx_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *cmd){ struct tda80xx_state* state = fe->demodulator_priv; if (cmd->msg_len > 6) return -EINVAL; tda80xx_writereg(state, 0x29, 0x08 | (cmd->msg_len - 3)); tda80xx_write(state, 0x23, cmd->msg, cmd->msg_len); tda80xx_writereg(state, 0x29, 0x0c | (cmd->msg_len - 3)); tda80xx_wait_diseqc_fifo(state); return 0;}static int tda80xx_send_diseqc_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t cmd){ struct tda80xx_state* state = fe->demodulator_priv; switch (cmd) { case SEC_MINI_A: tda80xx_writereg(state, 0x29, 0x14); break; case SEC_MINI_B: tda80xx_writereg(state, 0x29, 0x1c); break; default: return -EINVAL; } tda80xx_wait_diseqc_fifo(state); return 0;}static int tda80xx_sleep(struct dvb_frontend* fe){ struct tda80xx_state* state = fe->demodulator_priv; tda80xx_writereg(state, 0x00, 0x02); /* enter standby */ return 0;}static int tda80xx_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p){ struct tda80xx_state* state = fe->demodulator_priv; tda80xx_writereg(state, 0x1c, 0x80); state->config->pll_set(fe, p); tda80xx_writereg(state, 0x1c, 0x00); tda80xx_set_parameters(state, p->inversion, p->u.qpsk.symbol_rate, p->u.qpsk.fec_inner); tda80xx_set_clk(state); //tda80xx_set_scpc_freq_offset(state); state->afc_loop = 1; return 0;}static int tda80xx_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p){ struct tda80xx_state* state = fe->demodulator_priv; if (!state->config->irq) tda80xx_read_status_int(state); p->inversion = state->spectral_inversion; p->u.qpsk.fec_inner = state->code_rate; return 0;}static int tda80xx_read_status(struct dvb_frontend* fe, fe_status_t* status){ struct tda80xx_state* state = fe->demodulator_priv; if (!state->config->irq) tda80xx_read_status_int(state); *status = state->status; return 0;}static int tda80xx_read_ber(struct dvb_frontend* fe, u32* ber){ struct tda80xx_state* state = fe->demodulator_priv; int ret; u8 buf[3]; if ((ret = tda80xx_read(state, 0x0b, buf, sizeof(buf)))) return ret; *ber = ((buf[0] & 0x1f) << 16) | (buf[1] << 8) | buf[2]; return 0;}static int tda80xx_read_signal_strength(struct dvb_frontend* fe, u16* strength){ struct tda80xx_state* state = fe->demodulator_priv; u8 gain = ~tda80xx_readreg(state, 0x01); *strength = (gain << 8) | gain; return 0;}static int tda80xx_read_snr(struct dvb_frontend* fe, u16* snr){ struct tda80xx_state* state = fe->demodulator_priv; u8 quality = tda80xx_readreg(state, 0x08); *snr = (quality << 8) | quality; return 0;}static int tda80xx_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks){ struct tda80xx_state* state = fe->demodulator_priv; *ucblocks = tda80xx_readreg(state, 0x0f); if (*ucblocks == 0xff) *ucblocks = 0xffffffff; return 0;}static int tda80xx_init(struct dvb_frontend* fe){ struct tda80xx_state* state = fe->demodulator_priv; switch(state->id) { case ID_TDA8044: return tda8044_init(fe); case ID_TDA8083: return tda8083_init(fe); } return 0;}static void tda80xx_release(struct dvb_frontend* fe){ struct tda80xx_state* state = fe->demodulator_priv; if (state->config->irq) free_irq(state->config->irq, &state->worklet); kfree(state);}static struct dvb_frontend_ops tda80xx_ops;struct dvb_frontend* tda80xx_attach(const struct tda80xx_config* config, struct i2c_adapter* i2c){ struct tda80xx_state* state = NULL; int ret; /* allocate memory for the internal state */ state = kmalloc(sizeof(struct tda80xx_state), GFP_KERNEL); if (state == NULL) goto error; /* setup the state */ state->config = config; state->i2c = i2c; memcpy(&state->ops, &tda80xx_ops, sizeof(struct dvb_frontend_ops)); state->spectral_inversion = INVERSION_AUTO; state->code_rate = FEC_AUTO; state->status = 0; state->afc_loop = 0; /* check if the demod is there */ if (tda80xx_writereg(state, 0x89, 0x00) < 0) goto error; state->id = tda80xx_readreg(state, 0x00); switch (state->id) { case ID_TDA8044: state->clk = 96000000; printk("tda80xx: Detected tda8044\n"); break; case ID_TDA8083: state->clk = 64000000; printk("tda80xx: Detected tda8083\n"); break; default: goto error; } /* setup IRQ */ if (state->config->irq) { INIT_WORK(&state->worklet, tda80xx_worklet, state); if ((ret = request_irq(state->config->irq, tda80xx_irq, SA_ONESHOT, "tda80xx", &state->worklet)) < 0) { printk(KERN_ERR "tda80xx: request_irq failed (%d)\n", ret); goto error; } } /* create dvb_frontend */ state->frontend.ops = &state->ops; state->frontend.demodulator_priv = state; return &state->frontend;error: kfree(state); return NULL;}static struct dvb_frontend_ops tda80xx_ops = { .info = { .name = "Philips TDA80xx DVB-S", .type = FE_QPSK, .frequency_min = 500000, .frequency_max = 2700000, .frequency_stepsize = 125, .symbol_rate_min = 4500000, .symbol_rate_max = 45000000, .caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO | FE_CAN_QPSK | FE_CAN_MUTE_TS }, .release = tda80xx_release, .init = tda80xx_init, .sleep = tda80xx_sleep, .set_frontend = tda80xx_set_frontend, .get_frontend = tda80xx_get_frontend, .read_status = tda80xx_read_status, .read_ber = tda80xx_read_ber, .read_signal_strength = tda80xx_read_signal_strength, .read_snr = tda80xx_read_snr, .read_ucblocks = tda80xx_read_ucblocks, .diseqc_send_master_cmd = tda80xx_send_diseqc_msg, .diseqc_send_burst = tda80xx_send_diseqc_burst, .set_tone = tda80xx_set_tone, .set_voltage = tda80xx_set_voltage,};module_param(debug, int, 0644);MODULE_DESCRIPTION("Philips TDA8044 / TDA8083 DVB-S Demodulator driver");MODULE_AUTHOR("Felix Domke, Andreas Oberritter");MODULE_LICENSE("GPL");EXPORT_SYMBOL(tda80xx_attach);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -