2 Auvitek AU8522 QAM/8VSB demodulator driver
4 Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include <linux/kernel.h>
23 #include <linux/init.h>
24 #include <linux/module.h>
25 #include <linux/string.h>
26 #include <linux/delay.h>
27 #include "dvb_frontend.h"
29 #include "au8522_priv.h"
33 /* Despite the name "hybrid_tuner", the framework works just as well for
34 hybrid demodulators as well... */
35 static LIST_HEAD(hybrid_tuner_instance_list);
36 static DEFINE_MUTEX(au8522_list_mutex);
38 #define dprintk(arg...)\
43 /* 16 bit registers, 8 bit values */
44 int au8522_writereg(struct au8522_state *state, u16 reg, u8 data)
47 u8 buf[] = { (reg >> 8) | 0x80, reg & 0xff, data };
49 struct i2c_msg msg = { .addr = state->config->demod_address,
50 .flags = 0, .buf = buf, .len = 3 };
52 ret = i2c_transfer(state->i2c, &msg, 1);
55 printk("%s: writereg error (reg == 0x%02x, val == 0x%04x, "
56 "ret == %i)\n", __func__, reg, data, ret);
58 return (ret != 1) ? -1 : 0;
61 u8 au8522_readreg(struct au8522_state *state, u16 reg)
64 u8 b0[] = { (reg >> 8) | 0x40, reg & 0xff };
67 struct i2c_msg msg[] = {
68 { .addr = state->config->demod_address, .flags = 0,
69 .buf = b0, .len = 2 },
70 { .addr = state->config->demod_address, .flags = I2C_M_RD,
71 .buf = b1, .len = 1 } };
73 ret = i2c_transfer(state->i2c, msg, 2);
76 printk(KERN_ERR "%s: readreg error (ret == %i)\n",
81 static int au8522_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
83 struct au8522_state *state = fe->demodulator_priv;
85 dprintk("%s(%d)\n", __func__, enable);
88 return au8522_writereg(state, 0x106, 1);
90 return au8522_writereg(state, 0x106, 0);
98 /* VSB SNR lookup table */
99 static struct mse2snr_tab vsb_mse2snr_tab[] = {
132 /* QAM64 SNR lookup table */
133 static struct mse2snr_tab qam64_mse2snr_tab[] = {
213 /* QAM256 SNR lookup table */
214 static struct mse2snr_tab qam256_mse2snr_tab[] = {
281 static int au8522_mse2snr_lookup(struct mse2snr_tab *tab, int sz, int mse,
284 int i, ret = -EINVAL;
285 dprintk("%s()\n", __func__);
287 for (i = 0; i < sz; i++) {
288 if (mse < tab[i].val) {
294 dprintk("%s() snr=%d\n", __func__, *snr);
298 static int au8522_set_if(struct dvb_frontend *fe, enum au8522_if_freq if_freq)
300 struct au8522_state *state = fe->demodulator_priv;
305 case AU8522_IF_3_25MHZ:
324 dprintk("%s() IF Frequency not supported\n", __func__);
327 dprintk("%s() %s MHz\n", __func__, ifmhz);
328 au8522_writereg(state, 0x80b5, r0b5);
329 au8522_writereg(state, 0x80b6, r0b6);
330 au8522_writereg(state, 0x80b7, r0b7);
335 /* VSB Modulation table */
369 /* QAM64 Modulation table */
373 } QAM64_mod_tab[] = {
448 /* QAM256 Modulation table */
452 } QAM256_mod_tab[] = {
527 static int au8522_enable_modulation(struct dvb_frontend *fe,
530 struct au8522_state *state = fe->demodulator_priv;
533 dprintk("%s(0x%08x)\n", __func__, m);
537 dprintk("%s() VSB_8\n", __func__);
538 for (i = 0; i < ARRAY_SIZE(VSB_mod_tab); i++)
539 au8522_writereg(state,
541 VSB_mod_tab[i].data);
542 au8522_set_if(fe, state->config->vsb_if);
545 dprintk("%s() QAM 64\n", __func__);
546 for (i = 0; i < ARRAY_SIZE(QAM64_mod_tab); i++)
547 au8522_writereg(state,
548 QAM64_mod_tab[i].reg,
549 QAM64_mod_tab[i].data);
550 au8522_set_if(fe, state->config->qam_if);
553 dprintk("%s() QAM 256\n", __func__);
554 for (i = 0; i < ARRAY_SIZE(QAM256_mod_tab); i++)
555 au8522_writereg(state,
556 QAM256_mod_tab[i].reg,
557 QAM256_mod_tab[i].data);
558 au8522_set_if(fe, state->config->qam_if);
561 dprintk("%s() Invalid modulation\n", __func__);
565 state->current_modulation = m;
570 /* Talk to the demod, set the FEC, GUARD, QAM settings etc */
571 static int au8522_set_frontend(struct dvb_frontend *fe,
572 struct dvb_frontend_parameters *p)
574 struct au8522_state *state = fe->demodulator_priv;
577 dprintk("%s(frequency=%d)\n", __func__, p->frequency);
579 if ((state->current_frequency == p->frequency) &&
580 (state->current_modulation == p->u.vsb.modulation))
583 au8522_enable_modulation(fe, p->u.vsb.modulation);
585 /* Allow the demod to settle */
588 if (fe->ops.tuner_ops.set_params) {
589 if (fe->ops.i2c_gate_ctrl)
590 fe->ops.i2c_gate_ctrl(fe, 1);
591 ret = fe->ops.tuner_ops.set_params(fe, p);
592 if (fe->ops.i2c_gate_ctrl)
593 fe->ops.i2c_gate_ctrl(fe, 0);
599 state->current_frequency = p->frequency;
604 /* Reset the demod hardware and reset all of the configuration registers
605 to a default state. */
606 int au8522_init(struct dvb_frontend *fe)
608 struct au8522_state *state = fe->demodulator_priv;
609 dprintk("%s()\n", __func__);
611 au8522_writereg(state, 0xa4, 1 << 5);
613 au8522_i2c_gate_ctrl(fe, 1);
618 static int au8522_led_gpio_enable(struct au8522_state *state, int onoff)
620 struct au8522_led_config *led_config = state->config->led_cfg;
623 /* bail out if we cant control an LED */
624 if (!led_config || !led_config->gpio_output ||
625 !led_config->gpio_output_enable || !led_config->gpio_output_disable)
628 val = au8522_readreg(state, 0x4000 |
629 (led_config->gpio_output & ~0xc000));
631 /* enable GPIO output */
632 val &= ~((led_config->gpio_output_enable >> 8) & 0xff);
633 val |= (led_config->gpio_output_enable & 0xff);
635 /* disable GPIO output */
636 val &= ~((led_config->gpio_output_disable >> 8) & 0xff);
637 val |= (led_config->gpio_output_disable & 0xff);
639 return au8522_writereg(state, 0x8000 |
640 (led_config->gpio_output & ~0xc000), val);
644 * led = 1 | signal ok
645 * led = 2 | signal strong
646 * led < 0 | only light led if leds are currently off
648 static int au8522_led_ctrl(struct au8522_state *state, int led)
650 struct au8522_led_config *led_config = state->config->led_cfg;
653 /* bail out if we cant control an LED */
654 if (!led_config || !led_config->gpio_leds ||
655 !led_config->num_led_states || !led_config->led_states)
659 /* if LED is already lit, then leave it as-is */
660 if (state->led_state)
666 /* toggle LED if changing state */
667 if (state->led_state != led) {
670 dprintk("%s: %d\n", __func__, led);
672 au8522_led_gpio_enable(state, 1);
674 val = au8522_readreg(state, 0x4000 |
675 (led_config->gpio_leds & ~0xc000));
677 /* start with all leds off */
678 for (i = 0; i < led_config->num_led_states; i++)
679 val &= ~led_config->led_states[i];
681 /* set selected LED state */
682 if (led < led_config->num_led_states)
683 val |= led_config->led_states[led];
684 else if (led_config->num_led_states)
686 led_config->led_states[led_config->num_led_states - 1];
688 ret = au8522_writereg(state, 0x8000 |
689 (led_config->gpio_leds & ~0xc000), val);
693 state->led_state = led;
696 au8522_led_gpio_enable(state, 0);
702 int au8522_sleep(struct dvb_frontend *fe)
704 struct au8522_state *state = fe->demodulator_priv;
705 dprintk("%s()\n", __func__);
708 au8522_led_ctrl(state, 0);
710 /* Power down the chip */
711 au8522_writereg(state, 0xa4, 1 << 5);
713 state->current_frequency = 0;
718 static int au8522_read_status(struct dvb_frontend *fe, fe_status_t *status)
720 struct au8522_state *state = fe->demodulator_priv;
722 u32 tuner_status = 0;
726 if (state->current_modulation == VSB_8) {
727 dprintk("%s() Checking VSB_8\n", __func__);
728 reg = au8522_readreg(state, 0x4088);
729 if ((reg & 0x03) == 0x03)
730 *status |= FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI;
732 dprintk("%s() Checking QAM\n", __func__);
733 reg = au8522_readreg(state, 0x4541);
735 *status |= FE_HAS_VITERBI;
737 *status |= FE_HAS_LOCK | FE_HAS_SYNC;
740 switch (state->config->status_mode) {
741 case AU8522_DEMODLOCKING:
742 dprintk("%s() DEMODLOCKING\n", __func__);
743 if (*status & FE_HAS_VITERBI)
744 *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
746 case AU8522_TUNERLOCKING:
747 /* Get the tuner status */
748 dprintk("%s() TUNERLOCKING\n", __func__);
749 if (fe->ops.tuner_ops.get_status) {
750 if (fe->ops.i2c_gate_ctrl)
751 fe->ops.i2c_gate_ctrl(fe, 1);
753 fe->ops.tuner_ops.get_status(fe, &tuner_status);
755 if (fe->ops.i2c_gate_ctrl)
756 fe->ops.i2c_gate_ctrl(fe, 0);
759 *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
762 state->fe_status = *status;
764 if (*status & FE_HAS_LOCK)
765 /* turn on LED, if it isn't on already */
766 au8522_led_ctrl(state, -1);
769 au8522_led_ctrl(state, 0);
771 dprintk("%s() status 0x%08x\n", __func__, *status);
776 static int au8522_led_status(struct au8522_state *state, const u16 *snr)
778 struct au8522_led_config *led_config = state->config->led_cfg;
782 /* bail out if we cant control an LED */
786 if (0 == (state->fe_status & FE_HAS_LOCK))
787 return au8522_led_ctrl(state, 0);
788 else if (state->current_modulation == QAM_256)
789 strong = led_config->qam256_strong;
790 else if (state->current_modulation == QAM_64)
791 strong = led_config->qam64_strong;
792 else /* (state->current_modulation == VSB_8) */
793 strong = led_config->vsb8_strong;
800 if ((state->led_state) &&
801 (((strong < *snr) ? (*snr - strong) : (strong - *snr)) <= 10))
802 /* snr didn't change enough to bother
803 * changing the color of the led */
806 return au8522_led_ctrl(state, led);
809 static int au8522_read_snr(struct dvb_frontend *fe, u16 *snr)
811 struct au8522_state *state = fe->demodulator_priv;
814 dprintk("%s()\n", __func__);
816 if (state->current_modulation == QAM_256)
817 ret = au8522_mse2snr_lookup(qam256_mse2snr_tab,
818 ARRAY_SIZE(qam256_mse2snr_tab),
819 au8522_readreg(state, 0x4522),
821 else if (state->current_modulation == QAM_64)
822 ret = au8522_mse2snr_lookup(qam64_mse2snr_tab,
823 ARRAY_SIZE(qam64_mse2snr_tab),
824 au8522_readreg(state, 0x4522),
827 ret = au8522_mse2snr_lookup(vsb_mse2snr_tab,
828 ARRAY_SIZE(vsb_mse2snr_tab),
829 au8522_readreg(state, 0x4311),
832 if (state->config->led_cfg)
833 au8522_led_status(state, snr);
838 static int au8522_read_signal_strength(struct dvb_frontend *fe,
839 u16 *signal_strength)
841 return au8522_read_snr(fe, signal_strength);
844 static int au8522_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
846 struct au8522_state *state = fe->demodulator_priv;
848 if (state->current_modulation == VSB_8)
849 *ucblocks = au8522_readreg(state, 0x4087);
851 *ucblocks = au8522_readreg(state, 0x4543);
856 static int au8522_read_ber(struct dvb_frontend *fe, u32 *ber)
858 return au8522_read_ucblocks(fe, ber);
861 static int au8522_get_frontend(struct dvb_frontend *fe,
862 struct dvb_frontend_parameters *p)
864 struct au8522_state *state = fe->demodulator_priv;
866 p->frequency = state->current_frequency;
867 p->u.vsb.modulation = state->current_modulation;
872 static int au8522_get_tune_settings(struct dvb_frontend *fe,
873 struct dvb_frontend_tune_settings *tune)
875 tune->min_delay_ms = 1000;
879 static struct dvb_frontend_ops au8522_ops;
881 int au8522_get_state(struct au8522_state **state, struct i2c_adapter *i2c,
886 mutex_lock(&au8522_list_mutex);
887 ret = hybrid_tuner_request_state(struct au8522_state, (*state),
888 hybrid_tuner_instance_list,
889 i2c, client_address, "au8522");
890 mutex_unlock(&au8522_list_mutex);
895 void au8522_release_state(struct au8522_state *state)
897 mutex_lock(&au8522_list_mutex);
899 hybrid_tuner_release_state(state);
900 mutex_unlock(&au8522_list_mutex);
904 static void au8522_release(struct dvb_frontend *fe)
906 struct au8522_state *state = fe->demodulator_priv;
907 au8522_release_state(state);
910 struct dvb_frontend *au8522_attach(const struct au8522_config *config,
911 struct i2c_adapter *i2c)
913 struct au8522_state *state = NULL;
916 /* allocate memory for the internal state */
917 instance = au8522_get_state(&state, i2c, config->demod_address);
920 dprintk("%s state allocation failed\n", __func__);
923 /* new demod instance */
924 dprintk("%s using new instance\n", __func__);
927 /* existing demod instance */
928 dprintk("%s using existing instance\n", __func__);
932 /* setup the state */
933 state->config = config;
935 /* create dvb_frontend */
936 memcpy(&state->frontend.ops, &au8522_ops,
937 sizeof(struct dvb_frontend_ops));
938 state->frontend.demodulator_priv = state;
940 if (au8522_init(&state->frontend) != 0) {
941 printk(KERN_ERR "%s: Failed to initialize correctly\n",
946 /* Note: Leaving the I2C gate open here. */
947 au8522_i2c_gate_ctrl(&state->frontend, 1);
949 return &state->frontend;
952 au8522_release_state(state);
955 EXPORT_SYMBOL(au8522_attach);
957 static struct dvb_frontend_ops au8522_ops = {
960 .name = "Auvitek AU8522 QAM/8VSB Frontend",
962 .frequency_min = 54000000,
963 .frequency_max = 858000000,
964 .frequency_stepsize = 62500,
965 .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
969 .sleep = au8522_sleep,
970 .i2c_gate_ctrl = au8522_i2c_gate_ctrl,
971 .set_frontend = au8522_set_frontend,
972 .get_frontend = au8522_get_frontend,
973 .get_tune_settings = au8522_get_tune_settings,
974 .read_status = au8522_read_status,
975 .read_ber = au8522_read_ber,
976 .read_signal_strength = au8522_read_signal_strength,
977 .read_snr = au8522_read_snr,
978 .read_ucblocks = au8522_read_ucblocks,
979 .release = au8522_release,
982 module_param(debug, int, 0644);
983 MODULE_PARM_DESC(debug, "Enable verbose debug messages");
985 MODULE_DESCRIPTION("Auvitek AU8522 QAM-B/ATSC Demodulator driver");
986 MODULE_AUTHOR("Steven Toth");
987 MODULE_LICENSE("GPL");