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 "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, "
54 "ret == %i)\n", __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 gmb();
207 val |= led_config->led_states[led];
208 } else if (led_config->num_led_states) {
209 val |=
210 led_config->led_states[led_config->num_led_states - 1];
211 }
212
213 ret = au8522_writereg(state, 0x8000 |
214 (led_config->gpio_leds & ~0xc000), val);
215 if (ret < 0)
216 return ret;
217
218 state->led_state = led;
219
220 if (led == 0)
221 au8522_led_gpio_enable(state, 0);
222 }
223
224 return 0;
225}
226EXPORT_SYMBOL(au8522_led_ctrl);
227
228int au8522_init(struct dvb_frontend *fe)
229{
230 struct au8522_state *state = fe->demodulator_priv;
231 dprintk("%s()\n", __func__);
232
233 state->operational_mode = AU8522_DIGITAL_MODE;
234
235
236
237
238 state->current_frequency = 0;
239
240 au8522_writereg(state, 0xa4, 1 << 5);
241
242 au8522_i2c_gate_ctrl(fe, 1);
243
244 return 0;
245}
246EXPORT_SYMBOL(au8522_init);
247
248int au8522_sleep(struct dvb_frontend *fe)
249{
250 struct au8522_state *state = fe->demodulator_priv;
251 dprintk("%s()\n", __func__);
252
253
254 if (state->operational_mode == AU8522_ANALOG_MODE) {
255
256
257
258
259 return 0;
260 }
261
262
263 au8522_led_ctrl(state, 0);
264
265
266 au8522_writereg(state, 0xa4, 1 << 5);
267
268 state->current_frequency = 0;
269
270 return 0;
271}
272EXPORT_SYMBOL(au8522_sleep);
273
274module_param(debug, int, 0644);
275MODULE_PARM_DESC(debug, "Enable verbose debug messages");
276
277MODULE_DESCRIPTION("Auvitek AU8522 QAM-B/ATSC Demodulator driver");
278MODULE_AUTHOR("Steven Toth");
279MODULE_LICENSE("GPL");
280