1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25#include <linux/i2c.h>
26#include <media/dvb_frontend.h>
27#include "au8522_priv.h"
28
29static int debug;
30
31#define dprintk(arg...)\
32 do { if (debug)\
33 printk(arg);\
34 } while (0)
35
36
37
38static LIST_HEAD(hybrid_tuner_instance_list);
39static DEFINE_MUTEX(au8522_list_mutex);
40
41
42int au8522_writereg(struct au8522_state *state, u16 reg, u8 data)
43{
44 int ret;
45 u8 buf[] = { (reg >> 8) | 0x80, reg & 0xff, data };
46
47 struct i2c_msg msg = { .addr = state->config.demod_address,
48 .flags = 0, .buf = buf, .len = 3 };
49
50 ret = i2c_transfer(state->i2c, &msg, 1);
51
52 if (ret != 1)
53 printk("%s: writereg error (reg == 0x%02x, val == 0x%04x, ret == %i)\n",
54 __func__, reg, data, ret);
55
56 return (ret != 1) ? -1 : 0;
57}
58EXPORT_SYMBOL(au8522_writereg);
59
60u8 au8522_readreg(struct au8522_state *state, u16 reg)
61{
62 int ret;
63 u8 b0[] = { (reg >> 8) | 0x40, reg & 0xff };
64 u8 b1[] = { 0 };
65
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 } };
71
72 ret = i2c_transfer(state->i2c, msg, 2);
73
74 if (ret != 2)
75 printk(KERN_ERR "%s: readreg error (ret == %i)\n",
76 __func__, ret);
77 return b1[0];
78}
79EXPORT_SYMBOL(au8522_readreg);
80
81int au8522_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
82{
83 struct au8522_state *state = fe->demodulator_priv;
84
85 dprintk("%s(%d)\n", __func__, enable);
86
87 if (state->operational_mode == AU8522_ANALOG_MODE) {
88
89
90
91
92 return 0;
93 }
94
95 if (enable)
96 return au8522_writereg(state, 0x106, 1);
97 else
98 return au8522_writereg(state, 0x106, 0);
99}
100EXPORT_SYMBOL(au8522_i2c_gate_ctrl);
101
102int au8522_analog_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
103{
104 struct au8522_state *state = fe->demodulator_priv;
105
106 dprintk("%s(%d)\n", __func__, enable);
107
108 if (enable)
109 return au8522_writereg(state, 0x106, 1);
110 else
111 return au8522_writereg(state, 0x106, 0);
112}
113EXPORT_SYMBOL(au8522_analog_i2c_gate_ctrl);
114
115
116
117int au8522_get_state(struct au8522_state **state, struct i2c_adapter *i2c,
118 u8 client_address)
119{
120 int ret;
121
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);
127
128 return ret;
129}
130EXPORT_SYMBOL(au8522_get_state);
131
132void au8522_release_state(struct au8522_state *state)
133{
134 mutex_lock(&au8522_list_mutex);
135 if (state != NULL)
136 hybrid_tuner_release_state(state);
137 mutex_unlock(&au8522_list_mutex);
138}
139EXPORT_SYMBOL(au8522_release_state);
140
141static int au8522_led_gpio_enable(struct au8522_state *state, int onoff)
142{
143 struct au8522_led_config *led_config = state->config.led_cfg;
144 u8 val;
145
146
147 if (!led_config || !led_config->gpio_output ||
148 !led_config->gpio_output_enable || !led_config->gpio_output_disable)
149 return 0;
150
151 val = au8522_readreg(state, 0x4000 |
152 (led_config->gpio_output & ~0xc000));
153 if (onoff) {
154
155 val &= ~((led_config->gpio_output_enable >> 8) & 0xff);
156 val |= (led_config->gpio_output_enable & 0xff);
157 } else {
158
159 val &= ~((led_config->gpio_output_disable >> 8) & 0xff);
160 val |= (led_config->gpio_output_disable & 0xff);
161 }
162 return au8522_writereg(state, 0x8000 |
163 (led_config->gpio_output & ~0xc000), val);
164}
165
166
167
168
169
170
171int au8522_led_ctrl(struct au8522_state *state, int led)
172{
173 struct au8522_led_config *led_config = state->config.led_cfg;
174 int i, ret = 0;
175
176
177 if (!led_config || !led_config->gpio_leds ||
178 !led_config->num_led_states || !led_config->led_states)
179 return 0;
180
181 if (led < 0) {
182
183 if (state->led_state)
184 return 0;
185 else
186 led *= -1;
187 }
188
189
190 if (state->led_state != led) {
191 u8 val;
192
193 dprintk("%s: %d\n", __func__, led);
194
195 au8522_led_gpio_enable(state, 1);
196
197 val = au8522_readreg(state, 0x4000 |
198 (led_config->gpio_leds & ~0xc000));
199
200
201 for (i = 0; i < led_config->num_led_states; i++)
202 val &= ~led_config->led_states[i];
203
204
205 if (led < led_config->num_led_states)
206 val |= led_config->led_states[led];
207 else if (led_config->num_led_states)
208 val |=
209 led_config->led_states[led_config->num_led_states - 1];
210
211 ret = au8522_writereg(state, 0x8000 |
212 (led_config->gpio_leds & ~0xc000), val);
213 if (ret < 0)
214 return ret;
215
216 state->led_state = led;
217
218 if (led == 0)
219 au8522_led_gpio_enable(state, 0);
220 }
221
222 return 0;
223}
224EXPORT_SYMBOL(au8522_led_ctrl);
225
226int au8522_init(struct dvb_frontend *fe)
227{
228 struct au8522_state *state = fe->demodulator_priv;
229 dprintk("%s()\n", __func__);
230
231 state->operational_mode = AU8522_DIGITAL_MODE;
232
233
234
235
236 state->current_frequency = 0;
237 state->current_modulation = VSB_8;
238
239 au8522_writereg(state, 0xa4, 1 << 5);
240
241 au8522_i2c_gate_ctrl(fe, 1);
242
243 return 0;
244}
245EXPORT_SYMBOL(au8522_init);
246
247int au8522_sleep(struct dvb_frontend *fe)
248{
249 struct au8522_state *state = fe->demodulator_priv;
250 dprintk("%s()\n", __func__);
251
252
253 if (state->operational_mode == AU8522_ANALOG_MODE) {
254
255
256
257
258 return 0;
259 }
260
261
262 au8522_led_ctrl(state, 0);
263
264
265 au8522_writereg(state, 0xa4, 1 << 5);
266
267 state->current_frequency = 0;
268
269 return 0;
270}
271EXPORT_SYMBOL(au8522_sleep);
272
273module_param(debug, int, 0644);
274MODULE_PARM_DESC(debug, "Enable verbose debug messages");
275
276MODULE_DESCRIPTION("Auvitek AU8522 QAM-B/ATSC Demodulator driver");
277MODULE_AUTHOR("Steven Toth");
278MODULE_LICENSE("GPL");
279