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"
29 MODULE_LICENSE("GPL");
33 #define dprintk(arg...)\
38 /* Despite the name "hybrid_tuner", the framework works just as well for
39 hybrid demodulators as well... */
40 static LIST_HEAD(hybrid_tuner_instance_list
);
41 static DEFINE_MUTEX(au8522_list_mutex
);
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;
60 EXPORT_SYMBOL(au8522_writereg
);
62 u8
au8522_readreg(struct au8522_state
*state
, u16 reg
)
65 u8 b0
[] = { (reg
>> 8) | 0x40, reg
& 0xff };
68 struct i2c_msg msg
[] = {
69 { .addr
= state
->config
->demod_address
, .flags
= 0,
70 .buf
= b0
, .len
= 2 },
71 { .addr
= state
->config
->demod_address
, .flags
= I2C_M_RD
,
72 .buf
= b1
, .len
= 1 } };
74 ret
= i2c_transfer(state
->i2c
, msg
, 2);
77 printk(KERN_ERR
"%s: readreg error (ret == %i)\n",
81 EXPORT_SYMBOL(au8522_readreg
);
83 int au8522_i2c_gate_ctrl(struct dvb_frontend
*fe
, int enable
)
85 struct au8522_state
*state
= fe
->demodulator_priv
;
87 dprintk("%s(%d)\n", __func__
, enable
);
89 if (state
->operational_mode
== AU8522_ANALOG_MODE
) {
90 /* We're being asked to manage the gate even though we're
91 not in digital mode. This can occur if we get switched
92 over to analog mode before the dvb_frontend kernel thread
93 has completely shutdown */
98 return au8522_writereg(state
, 0x106, 1);
100 return au8522_writereg(state
, 0x106, 0);
102 EXPORT_SYMBOL(au8522_i2c_gate_ctrl
);
104 /* Reset the demod hardware and reset all of the configuration registers
105 to a default state. */
106 int au8522_get_state(struct au8522_state
**state
, struct i2c_adapter
*i2c
,
111 mutex_lock(&au8522_list_mutex
);
112 ret
= hybrid_tuner_request_state(struct au8522_state
, (*state
),
113 hybrid_tuner_instance_list
,
114 i2c
, client_address
, "au8522");
115 mutex_unlock(&au8522_list_mutex
);
119 EXPORT_SYMBOL(au8522_get_state
);
121 void au8522_release_state(struct au8522_state
*state
)
123 mutex_lock(&au8522_list_mutex
);
125 hybrid_tuner_release_state(state
);
126 mutex_unlock(&au8522_list_mutex
);
128 EXPORT_SYMBOL(au8522_release_state
);
130 static int au8522_led_gpio_enable(struct au8522_state
*state
, int onoff
)
132 struct au8522_led_config
*led_config
= state
->config
->led_cfg
;
135 /* bail out if we can't control an LED */
136 if (!led_config
|| !led_config
->gpio_output
||
137 !led_config
->gpio_output_enable
|| !led_config
->gpio_output_disable
)
140 val
= au8522_readreg(state
, 0x4000 |
141 (led_config
->gpio_output
& ~0xc000));
143 /* enable GPIO output */
144 val
&= ~((led_config
->gpio_output_enable
>> 8) & 0xff);
145 val
|= (led_config
->gpio_output_enable
& 0xff);
147 /* disable GPIO output */
148 val
&= ~((led_config
->gpio_output_disable
>> 8) & 0xff);
149 val
|= (led_config
->gpio_output_disable
& 0xff);
151 return au8522_writereg(state
, 0x8000 |
152 (led_config
->gpio_output
& ~0xc000), val
);
156 * led = 1 | signal ok
157 * led = 2 | signal strong
158 * led < 0 | only light led if leds are currently off
160 int au8522_led_ctrl(struct au8522_state
*state
, int led
)
162 struct au8522_led_config
*led_config
= state
->config
->led_cfg
;
165 /* bail out if we can't control an LED */
166 if (!led_config
|| !led_config
->gpio_leds
||
167 !led_config
->num_led_states
|| !led_config
->led_states
)
171 /* if LED is already lit, then leave it as-is */
172 if (state
->led_state
)
178 /* toggle LED if changing state */
179 if (state
->led_state
!= led
) {
182 dprintk("%s: %d\n", __func__
, led
);
184 au8522_led_gpio_enable(state
, 1);
186 val
= au8522_readreg(state
, 0x4000 |
187 (led_config
->gpio_leds
& ~0xc000));
189 /* start with all leds off */
190 for (i
= 0; i
< led_config
->num_led_states
; i
++)
191 val
&= ~led_config
->led_states
[i
];
193 /* set selected LED state */
194 if (led
< led_config
->num_led_states
)
195 val
|= led_config
->led_states
[led
];
196 else if (led_config
->num_led_states
)
198 led_config
->led_states
[led_config
->num_led_states
- 1];
200 ret
= au8522_writereg(state
, 0x8000 |
201 (led_config
->gpio_leds
& ~0xc000), val
);
205 state
->led_state
= led
;
208 au8522_led_gpio_enable(state
, 0);
213 EXPORT_SYMBOL(au8522_led_ctrl
);
215 int au8522_init(struct dvb_frontend
*fe
)
217 struct au8522_state
*state
= fe
->demodulator_priv
;
218 dprintk("%s()\n", __func__
);
220 state
->operational_mode
= AU8522_DIGITAL_MODE
;
222 /* Clear out any state associated with the digital side of the
223 chip, so that when it gets powered back up it won't think
224 that it is already tuned */
225 state
->current_frequency
= 0;
227 au8522_writereg(state
, 0xa4, 1 << 5);
229 au8522_i2c_gate_ctrl(fe
, 1);
233 EXPORT_SYMBOL(au8522_init
);
235 int au8522_sleep(struct dvb_frontend
*fe
)
237 struct au8522_state
*state
= fe
->demodulator_priv
;
238 dprintk("%s()\n", __func__
);
240 /* Only power down if the digital side is currently using the chip */
241 if (state
->operational_mode
== AU8522_ANALOG_MODE
) {
242 /* We're not in one of the expected power modes, which means
243 that the DVB thread is probably telling us to go to sleep
244 even though the analog frontend has already started using
245 the chip. So ignore the request */
250 au8522_led_ctrl(state
, 0);
252 /* Power down the chip */
253 au8522_writereg(state
, 0xa4, 1 << 5);
255 state
->current_frequency
= 0;
259 EXPORT_SYMBOL(au8522_sleep
);