2 Auvitek AU8522 QAM/8VSB demodulator driver
4 Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
5 Copyright (C) 2008 Devin Heitmueller <dheitmueller@linuxtv.org>
6 Copyright (C) 2005-2008 Auvitek International, Ltd.
7 Copyright (C) 2012 Michael Krufky <mkrufky@linuxtv.org>
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include <linux/i2c.h>
26 #include "dvb_frontend.h"
27 #include "au8522_priv.h"
31 #define dprintk(arg...)\
36 /* Despite the name "hybrid_tuner", the framework works just as well for
37 hybrid demodulators as well... */
38 static LIST_HEAD(hybrid_tuner_instance_list);
39 static DEFINE_MUTEX(au8522_list_mutex);
41 /* 16 bit registers, 8 bit values */
42 int au8522_writereg(struct au8522_state *state, u16 reg, u8 data)
45 u8 buf[] = { (reg >> 8) | 0x80, reg & 0xff, data };
47 struct i2c_msg msg = { .addr = state->config->demod_address,
48 .flags = 0, .buf = buf, .len = 3 };
50 ret = i2c_transfer(state->i2c, &msg, 1);
53 printk("%s: writereg error (reg == 0x%02x, val == 0x%04x, "
54 "ret == %i)\n", __func__, reg, data, ret);
56 return (ret != 1) ? -1 : 0;
58 EXPORT_SYMBOL(au8522_writereg);
60 u8 au8522_readreg(struct au8522_state *state, u16 reg)
63 u8 b0[] = { (reg >> 8) | 0x40, reg & 0xff };
66 struct i2c_msg msg[] = {
67 { .addr = state->config->demod_address, .flags = 0,
68 .buf = b0, .len = 2 },
69 { .addr = state->config->demod_address, .flags = I2C_M_RD,
70 .buf = b1, .len = 1 } };
72 ret = i2c_transfer(state->i2c, msg, 2);
75 printk(KERN_ERR "%s: readreg error (ret == %i)\n",
79 EXPORT_SYMBOL(au8522_readreg);
81 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);
87 if (state->operational_mode == AU8522_ANALOG_MODE) {
88 /* We're being asked to manage the gate even though we're
89 not in digital mode. This can occur if we get switched
90 over to analog mode before the dvb_frontend kernel thread
91 has completely shutdown */
96 return au8522_writereg(state, 0x106, 1);
98 return au8522_writereg(state, 0x106, 0);
100 EXPORT_SYMBOL(au8522_i2c_gate_ctrl);
102 int au8522_analog_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
104 struct au8522_state *state = fe->demodulator_priv;
106 dprintk("%s(%d)\n", __func__, enable);
109 return au8522_writereg(state, 0x106, 1);
111 return au8522_writereg(state, 0x106, 0);
113 EXPORT_SYMBOL(au8522_analog_i2c_gate_ctrl);
115 /* Reset the demod hardware and reset all of the configuration registers
116 to a default state. */
117 int au8522_get_state(struct au8522_state **state, struct i2c_adapter *i2c,
122 mutex_lock(&au8522_list_mutex);
123 ret = hybrid_tuner_request_state(struct au8522_state, (*state),
124 hybrid_tuner_instance_list,
125 i2c, client_address, "au8522");
126 mutex_unlock(&au8522_list_mutex);
130 EXPORT_SYMBOL(au8522_get_state);
132 void au8522_release_state(struct au8522_state *state)
134 mutex_lock(&au8522_list_mutex);
136 hybrid_tuner_release_state(state);
137 mutex_unlock(&au8522_list_mutex);
139 EXPORT_SYMBOL(au8522_release_state);
141 static int au8522_led_gpio_enable(struct au8522_state *state, int onoff)
143 struct au8522_led_config *led_config = state->config->led_cfg;
146 /* bail out if we can't control an LED */
147 if (!led_config || !led_config->gpio_output ||
148 !led_config->gpio_output_enable || !led_config->gpio_output_disable)
151 val = au8522_readreg(state, 0x4000 |
152 (led_config->gpio_output & ~0xc000));
154 /* enable GPIO output */
155 val &= ~((led_config->gpio_output_enable >> 8) & 0xff);
156 val |= (led_config->gpio_output_enable & 0xff);
158 /* disable GPIO output */
159 val &= ~((led_config->gpio_output_disable >> 8) & 0xff);
160 val |= (led_config->gpio_output_disable & 0xff);
162 return au8522_writereg(state, 0x8000 |
163 (led_config->gpio_output & ~0xc000), val);
167 * led = 1 | signal ok
168 * led = 2 | signal strong
169 * led < 0 | only light led if leds are currently off
171 int au8522_led_ctrl(struct au8522_state *state, int led)
173 struct au8522_led_config *led_config = state->config->led_cfg;
176 /* bail out if we can't control an LED */
177 if (!led_config || !led_config->gpio_leds ||
178 !led_config->num_led_states || !led_config->led_states)
182 /* if LED is already lit, then leave it as-is */
183 if (state->led_state)
189 /* toggle LED if changing state */
190 if (state->led_state != led) {
193 dprintk("%s: %d\n", __func__, led);
195 au8522_led_gpio_enable(state, 1);
197 val = au8522_readreg(state, 0x4000 |
198 (led_config->gpio_leds & ~0xc000));
200 /* start with all leds off */
201 for (i = 0; i < led_config->num_led_states; i++)
202 val &= ~led_config->led_states[i];
204 /* set selected LED state */
205 if (led < led_config->num_led_states)
206 val |= led_config->led_states[led];
207 else if (led_config->num_led_states)
209 led_config->led_states[led_config->num_led_states - 1];
211 ret = au8522_writereg(state, 0x8000 |
212 (led_config->gpio_leds & ~0xc000), val);
216 state->led_state = led;
219 au8522_led_gpio_enable(state, 0);
224 EXPORT_SYMBOL(au8522_led_ctrl);
226 int au8522_init(struct dvb_frontend *fe)
228 struct au8522_state *state = fe->demodulator_priv;
229 dprintk("%s()\n", __func__);
231 state->operational_mode = AU8522_DIGITAL_MODE;
233 /* Clear out any state associated with the digital side of the
234 chip, so that when it gets powered back up it won't think
235 that it is already tuned */
236 state->current_frequency = 0;
238 au8522_writereg(state, 0xa4, 1 << 5);
240 au8522_i2c_gate_ctrl(fe, 1);
244 EXPORT_SYMBOL(au8522_init);
246 int au8522_sleep(struct dvb_frontend *fe)
248 struct au8522_state *state = fe->demodulator_priv;
249 dprintk("%s()\n", __func__);
251 /* Only power down if the digital side is currently using the chip */
252 if (state->operational_mode == AU8522_ANALOG_MODE) {
253 /* We're not in one of the expected power modes, which means
254 that the DVB thread is probably telling us to go to sleep
255 even though the analog frontend has already started using
256 the chip. So ignore the request */
261 au8522_led_ctrl(state, 0);
263 /* Power down the chip */
264 au8522_writereg(state, 0xa4, 1 << 5);
266 state->current_frequency = 0;
270 EXPORT_SYMBOL(au8522_sleep);
272 module_param(debug, int, 0644);
273 MODULE_PARM_DESC(debug, "Enable verbose debug messages");
275 MODULE_DESCRIPTION("Auvitek AU8522 QAM-B/ATSC Demodulator driver");
276 MODULE_AUTHOR("Steven Toth");
277 MODULE_LICENSE("GPL");