📄 au8522.c
字号:
{ 0x8260, 0xf5 }, { 0x8261, 0x06 }, { 0x821a, 0x00 }, { 0x8546, 0x40 }, { 0x8210, 0x26 }, { 0x8211, 0xf6 }, { 0x8212, 0x84 }, { 0x8213, 0x02 }, { 0x8502, 0x01 }, { 0x8121, 0x04 }, { 0x8122, 0x04 }, { 0x852e, 0x10 }, { 0x80a4, 0xca }, { 0x80a7, 0x40 }, { 0x8526, 0x01 },};static int au8522_enable_modulation(struct dvb_frontend *fe, fe_modulation_t m){ struct au8522_state *state = fe->demodulator_priv; int i; dprintk("%s(0x%08x)\n", __func__, m); switch (m) { case VSB_8: dprintk("%s() VSB_8\n", __func__); for (i = 0; i < ARRAY_SIZE(VSB_mod_tab); i++) au8522_writereg(state, VSB_mod_tab[i].reg, VSB_mod_tab[i].data); au8522_set_if(fe, state->config->vsb_if); break; case QAM_64: case QAM_256: dprintk("%s() QAM 64/256\n", __func__); for (i = 0; i < ARRAY_SIZE(QAM_mod_tab); i++) au8522_writereg(state, QAM_mod_tab[i].reg, QAM_mod_tab[i].data); au8522_set_if(fe, state->config->qam_if); break; default: dprintk("%s() Invalid modulation\n", __func__); return -EINVAL; } state->current_modulation = m; return 0;}/* Talk to the demod, set the FEC, GUARD, QAM settings etc */static int au8522_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p){ struct au8522_state *state = fe->demodulator_priv; int ret = -EINVAL; dprintk("%s(frequency=%d)\n", __func__, p->frequency); if ((state->current_frequency == p->frequency) && (state->current_modulation == p->u.vsb.modulation)) return 0; au8522_enable_modulation(fe, p->u.vsb.modulation); /* Allow the demod to settle */ msleep(100); if (fe->ops.tuner_ops.set_params) { if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); ret = fe->ops.tuner_ops.set_params(fe, p); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } if (ret < 0) return ret; state->current_frequency = p->frequency; return 0;}/* Reset the demod hardware and reset all of the configuration registers to a default state. */static int au8522_init(struct dvb_frontend *fe){ struct au8522_state *state = fe->demodulator_priv; dprintk("%s()\n", __func__); au8522_writereg(state, 0xa4, 1 << 5); au8522_i2c_gate_ctrl(fe, 1); return 0;}static int au8522_led_gpio_enable(struct au8522_state *state, int onoff){ struct au8522_led_config *led_config = state->config->led_cfg; u8 val; /* bail out if we cant control an LED */ if (!led_config || !led_config->gpio_output || !led_config->gpio_output_enable || !led_config->gpio_output_disable) return 0; val = au8522_readreg(state, 0x4000 | (led_config->gpio_output & ~0xc000)); if (onoff) { /* enable GPIO output */ val &= ~((led_config->gpio_output_enable >> 8) & 0xff); val |= (led_config->gpio_output_enable & 0xff); } else { /* disable GPIO output */ val &= ~((led_config->gpio_output_disable >> 8) & 0xff); val |= (led_config->gpio_output_disable & 0xff); } return au8522_writereg(state, 0x8000 | (led_config->gpio_output & ~0xc000), val);}/* led = 0 | off * led = 1 | signal ok * led = 2 | signal strong * led < 0 | only light led if leds are currently off */static int au8522_led_ctrl(struct au8522_state *state, int led){ struct au8522_led_config *led_config = state->config->led_cfg; int i, ret = 0; /* bail out if we cant control an LED */ if (!led_config || !led_config->gpio_leds || !led_config->num_led_states || !led_config->led_states) return 0; if (led < 0) { /* if LED is already lit, then leave it as-is */ if (state->led_state) return 0; else led *= -1; } /* toggle LED if changing state */ if (state->led_state != led) { u8 val; dprintk("%s: %d\n", __func__, led); au8522_led_gpio_enable(state, 1); val = au8522_readreg(state, 0x4000 | (led_config->gpio_leds & ~0xc000)); /* start with all leds off */ for (i = 0; i < led_config->num_led_states; i++) val &= ~led_config->led_states[i]; /* set selected LED state */ if (led < led_config->num_led_states) val |= led_config->led_states[led]; else if (led_config->num_led_states) val |= led_config->led_states[led_config->num_led_states - 1]; ret = au8522_writereg(state, 0x8000 | (led_config->gpio_leds & ~0xc000), val); if (ret < 0) return ret; state->led_state = led; if (led == 0) au8522_led_gpio_enable(state, 0); } return 0;}static int au8522_sleep(struct dvb_frontend *fe){ struct au8522_state *state = fe->demodulator_priv; dprintk("%s()\n", __func__); /* turn off led */ au8522_led_ctrl(state, 0); state->current_frequency = 0; return 0;}static int au8522_read_status(struct dvb_frontend *fe, fe_status_t *status){ struct au8522_state *state = fe->demodulator_priv; u8 reg; u32 tuner_status = 0; *status = 0; if (state->current_modulation == VSB_8) { dprintk("%s() Checking VSB_8\n", __func__); reg = au8522_readreg(state, 0x4088); if ((reg & 0x03) == 0x03) *status |= FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI; } else { dprintk("%s() Checking QAM\n", __func__); reg = au8522_readreg(state, 0x4541); if (reg & 0x80) *status |= FE_HAS_VITERBI; if (reg & 0x20) *status |= FE_HAS_LOCK | FE_HAS_SYNC; } switch (state->config->status_mode) { case AU8522_DEMODLOCKING: dprintk("%s() DEMODLOCKING\n", __func__); if (*status & FE_HAS_VITERBI) *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; break; case AU8522_TUNERLOCKING: /* Get the tuner status */ dprintk("%s() TUNERLOCKING\n", __func__); if (fe->ops.tuner_ops.get_status) { if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); fe->ops.tuner_ops.get_status(fe, &tuner_status); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } if (tuner_status) *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; break; } state->fe_status = *status; if (*status & FE_HAS_LOCK) /* turn on LED, if it isn't on already */ au8522_led_ctrl(state, -1); else /* turn off LED */ au8522_led_ctrl(state, 0); dprintk("%s() status 0x%08x\n", __func__, *status); return 0;}static int au8522_led_status(struct au8522_state *state, const u16 *snr){ struct au8522_led_config *led_config = state->config->led_cfg; int led; u16 strong; /* bail out if we cant control an LED */ if (!led_config) return 0; if (0 == (state->fe_status & FE_HAS_LOCK)) return au8522_led_ctrl(state, 0); else if (state->current_modulation == QAM_256) strong = led_config->qam256_strong; else if (state->current_modulation == QAM_64) strong = led_config->qam64_strong; else /* (state->current_modulation == VSB_8) */ strong = led_config->vsb8_strong; if (*snr >= strong) led = 2; else led = 1; if ((state->led_state) && (((strong < *snr) ? (*snr - strong) : (strong - *snr)) <= 10)) /* snr didn't change enough to bother * changing the color of the led */ return 0; return au8522_led_ctrl(state, led);}static int au8522_read_snr(struct dvb_frontend *fe, u16 *snr){ struct au8522_state *state = fe->demodulator_priv; int ret = -EINVAL; dprintk("%s()\n", __func__); if (state->current_modulation == QAM_256) ret = au8522_mse2snr_lookup(qam256_mse2snr_tab, ARRAY_SIZE(qam256_mse2snr_tab), au8522_readreg(state, 0x4522), snr); else if (state->current_modulation == QAM_64) ret = au8522_mse2snr_lookup(qam64_mse2snr_tab, ARRAY_SIZE(qam64_mse2snr_tab), au8522_readreg(state, 0x4522), snr); else /* VSB_8 */ ret = au8522_mse2snr_lookup(vsb_mse2snr_tab, ARRAY_SIZE(vsb_mse2snr_tab), au8522_readreg(state, 0x4311), snr); if (state->config->led_cfg) au8522_led_status(state, snr); return ret;}static int au8522_read_signal_strength(struct dvb_frontend *fe, u16 *signal_strength){ return au8522_read_snr(fe, signal_strength);}static int au8522_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks){ struct au8522_state *state = fe->demodulator_priv; if (state->current_modulation == VSB_8) *ucblocks = au8522_readreg(state, 0x4087); else *ucblocks = au8522_readreg(state, 0x4543); return 0;}static int au8522_read_ber(struct dvb_frontend *fe, u32 *ber){ return au8522_read_ucblocks(fe, ber);}static int au8522_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p){ struct au8522_state *state = fe->demodulator_priv; p->frequency = state->current_frequency; p->u.vsb.modulation = state->current_modulation; return 0;}static int au8522_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune){ tune->min_delay_ms = 1000; return 0;}static void au8522_release(struct dvb_frontend *fe){ struct au8522_state *state = fe->demodulator_priv; kfree(state);}static struct dvb_frontend_ops au8522_ops;struct dvb_frontend *au8522_attach(const struct au8522_config *config, struct i2c_adapter *i2c){ struct au8522_state *state = NULL; /* allocate memory for the internal state */ state = kmalloc(sizeof(struct au8522_state), GFP_KERNEL); if (state == NULL) goto error; /* setup the state */ state->config = config; state->i2c = i2c;#if 0 /* check if the demod exists */ reg = au8522_readreg(state, 0x04); if ((reg != 0x0066) && (reg != 0x007f)) goto error;#endif /* create dvb_frontend */ memcpy(&state->frontend.ops, &au8522_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; if (au8522_init(&state->frontend) != 0) { printk(KERN_ERR "%s: Failed to initialize correctly\n", __func__); goto error; } /* Note: Leaving the I2C gate open here. */ au8522_i2c_gate_ctrl(&state->frontend, 1); return &state->frontend;error: kfree(state); return NULL;}EXPORT_SYMBOL(au8522_attach);static struct dvb_frontend_ops au8522_ops = { .info = { .name = "Auvitek AU8522 QAM/8VSB Frontend", .type = FE_ATSC, .frequency_min = 54000000, .frequency_max = 858000000, .frequency_stepsize = 62500, .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB }, .init = au8522_init, .sleep = au8522_sleep, .i2c_gate_ctrl = au8522_i2c_gate_ctrl, .set_frontend = au8522_set_frontend, .get_frontend = au8522_get_frontend, .get_tune_settings = au8522_get_tune_settings, .read_status = au8522_read_status, .read_ber = au8522_read_ber, .read_signal_strength = au8522_read_signal_strength, .read_snr = au8522_read_snr, .read_ucblocks = au8522_read_ucblocks, .release = au8522_release,};module_param(debug, int, 0644);MODULE_PARM_DESC(debug, "Enable verbose debug messages");MODULE_DESCRIPTION("Auvitek AU8522 QAM-B/ATSC Demodulator driver");MODULE_AUTHOR("Steven Toth");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -