]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - drivers/media/dvb/frontends/au8522_dig.c
[media] dvb: remove dvb_frontend_parameters from calc_regs()
[mirror_ubuntu-artful-kernel.git] / drivers / media / dvb / frontends / au8522_dig.c
CommitLineData
265a6510
ST
1/*
2 Auvitek AU8522 QAM/8VSB demodulator driver
3
6d897616 4 Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
265a6510
ST
5
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.
10
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.
15
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.
19
20*/
21
22#include <linux/kernel.h>
23#include <linux/init.h>
24#include <linux/module.h>
25#include <linux/string.h>
265a6510
ST
26#include <linux/delay.h>
27#include "dvb_frontend.h"
265a6510 28#include "au8522.h"
0c44bf36 29#include "au8522_priv.h"
265a6510 30
18d73c58
MCC
31static int debug;
32
209fdf66
DH
33/* Despite the name "hybrid_tuner", the framework works just as well for
34 hybrid demodulators as well... */
35static LIST_HEAD(hybrid_tuner_instance_list);
4ff5ed44 36static DEFINE_MUTEX(au8522_list_mutex);
209fdf66 37
62899a28
DH
38#define dprintk(arg...)\
39 do { if (debug)\
40 printk(arg);\
18d73c58 41 } while (0)
265a6510
ST
42
43/* 16 bit registers, 8 bit values */
0c44bf36 44int au8522_writereg(struct au8522_state *state, u16 reg, u8 data)
265a6510
ST
45{
46 int ret;
62899a28 47 u8 buf[] = { (reg >> 8) | 0x80, reg & 0xff, data };
265a6510
ST
48
49 struct i2c_msg msg = { .addr = state->config->demod_address,
50 .flags = 0, .buf = buf, .len = 3 };
51
52 ret = i2c_transfer(state->i2c, &msg, 1);
53
54 if (ret != 1)
55 printk("%s: writereg error (reg == 0x%02x, val == 0x%04x, "
ce1719a6 56 "ret == %i)\n", __func__, reg, data, ret);
265a6510
ST
57
58 return (ret != 1) ? -1 : 0;
59}
60
0c44bf36 61u8 au8522_readreg(struct au8522_state *state, u16 reg)
265a6510
ST
62{
63 int ret;
62899a28
DH
64 u8 b0[] = { (reg >> 8) | 0x40, reg & 0xff };
65 u8 b1[] = { 0 };
265a6510 66
62899a28 67 struct i2c_msg msg[] = {
265a6510
ST
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 } };
72
73 ret = i2c_transfer(state->i2c, msg, 2);
74
75 if (ret != 2)
ce1719a6
MK
76 printk(KERN_ERR "%s: readreg error (ret == %i)\n",
77 __func__, ret);
265a6510
ST
78 return b1[0];
79}
80
e059b0fa 81static int au8522_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
265a6510 82{
e059b0fa 83 struct au8522_state *state = fe->demodulator_priv;
265a6510 84
ce1719a6 85 dprintk("%s(%d)\n", __func__, enable);
265a6510 86
7f2c983c
DH
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 */
92 return 0;
93 }
94
265a6510
ST
95 if (enable)
96 return au8522_writereg(state, 0x106, 1);
97 else
98 return au8522_writereg(state, 0x106, 0);
99}
100
0daa5de7 101struct mse2snr_tab {
f01699b4
ST
102 u16 val;
103 u16 data;
0daa5de7
MK
104};
105
106/* VSB SNR lookup table */
107static struct mse2snr_tab vsb_mse2snr_tab[] = {
f01699b4
ST
108 { 0, 270 },
109 { 2, 250 },
110 { 3, 240 },
111 { 5, 230 },
112 { 7, 220 },
113 { 9, 210 },
114 { 12, 200 },
115 { 13, 195 },
116 { 15, 190 },
117 { 17, 185 },
118 { 19, 180 },
119 { 21, 175 },
120 { 24, 170 },
121 { 27, 165 },
122 { 31, 160 },
123 { 32, 158 },
124 { 33, 156 },
125 { 36, 152 },
126 { 37, 150 },
127 { 39, 148 },
128 { 40, 146 },
129 { 41, 144 },
130 { 43, 142 },
131 { 44, 140 },
132 { 48, 135 },
133 { 50, 130 },
134 { 43, 142 },
135 { 53, 125 },
136 { 56, 120 },
137 { 256, 115 },
138};
139
140/* QAM64 SNR lookup table */
0daa5de7 141static struct mse2snr_tab qam64_mse2snr_tab[] = {
f01699b4
ST
142 { 15, 0 },
143 { 16, 290 },
144 { 17, 288 },
145 { 18, 286 },
146 { 19, 284 },
147 { 20, 282 },
148 { 21, 281 },
149 { 22, 279 },
150 { 23, 277 },
151 { 24, 275 },
152 { 25, 273 },
153 { 26, 271 },
154 { 27, 269 },
155 { 28, 268 },
156 { 29, 266 },
157 { 30, 264 },
158 { 31, 262 },
159 { 32, 260 },
160 { 33, 259 },
161 { 34, 258 },
162 { 35, 256 },
163 { 36, 255 },
164 { 37, 254 },
165 { 38, 252 },
166 { 39, 251 },
167 { 40, 250 },
168 { 41, 249 },
169 { 42, 248 },
170 { 43, 246 },
171 { 44, 245 },
172 { 45, 244 },
173 { 46, 242 },
174 { 47, 241 },
175 { 48, 240 },
176 { 50, 239 },
177 { 51, 238 },
178 { 53, 237 },
179 { 54, 236 },
180 { 56, 235 },
181 { 57, 234 },
182 { 59, 233 },
183 { 60, 232 },
184 { 62, 231 },
185 { 63, 230 },
186 { 65, 229 },
187 { 67, 228 },
188 { 68, 227 },
189 { 70, 226 },
190 { 71, 225 },
191 { 73, 224 },
192 { 74, 223 },
193 { 76, 222 },
194 { 78, 221 },
195 { 80, 220 },
196 { 82, 219 },
197 { 85, 218 },
198 { 88, 217 },
199 { 90, 216 },
200 { 92, 215 },
201 { 93, 214 },
202 { 94, 212 },
203 { 95, 211 },
204 { 97, 210 },
205 { 99, 209 },
206 { 101, 208 },
207 { 102, 207 },
208 { 104, 206 },
209 { 107, 205 },
210 { 111, 204 },
211 { 114, 203 },
212 { 118, 202 },
213 { 122, 201 },
214 { 125, 200 },
215 { 128, 199 },
216 { 130, 198 },
217 { 132, 197 },
218 { 256, 190 },
219};
220
221/* QAM256 SNR lookup table */
0daa5de7 222static struct mse2snr_tab qam256_mse2snr_tab[] = {
f01699b4
ST
223 { 16, 0 },
224 { 17, 400 },
225 { 18, 398 },
226 { 19, 396 },
227 { 20, 394 },
228 { 21, 392 },
229 { 22, 390 },
230 { 23, 388 },
231 { 24, 386 },
232 { 25, 384 },
233 { 26, 382 },
234 { 27, 380 },
235 { 28, 379 },
236 { 29, 378 },
237 { 30, 377 },
238 { 31, 376 },
239 { 32, 375 },
240 { 33, 374 },
241 { 34, 373 },
242 { 35, 372 },
243 { 36, 371 },
244 { 37, 370 },
245 { 38, 362 },
246 { 39, 354 },
247 { 40, 346 },
248 { 41, 338 },
249 { 42, 330 },
250 { 43, 328 },
251 { 44, 326 },
252 { 45, 324 },
253 { 46, 322 },
254 { 47, 320 },
255 { 48, 319 },
256 { 49, 318 },
257 { 50, 317 },
258 { 51, 316 },
259 { 52, 315 },
260 { 53, 314 },
261 { 54, 313 },
262 { 55, 312 },
263 { 56, 311 },
264 { 57, 310 },
265 { 58, 308 },
266 { 59, 306 },
267 { 60, 304 },
268 { 61, 302 },
269 { 62, 300 },
270 { 63, 298 },
271 { 65, 295 },
272 { 68, 294 },
273 { 70, 293 },
274 { 73, 292 },
275 { 76, 291 },
276 { 78, 290 },
277 { 79, 289 },
278 { 81, 288 },
279 { 82, 287 },
280 { 83, 286 },
281 { 84, 285 },
282 { 85, 284 },
283 { 86, 283 },
284 { 88, 282 },
285 { 89, 281 },
286 { 256, 280 },
287};
288
18d73c58
MCC
289static int au8522_mse2snr_lookup(struct mse2snr_tab *tab, int sz, int mse,
290 u16 *snr)
f01699b4
ST
291{
292 int i, ret = -EINVAL;
293 dprintk("%s()\n", __func__);
294
0daa5de7
MK
295 for (i = 0; i < sz; i++) {
296 if (mse < tab[i].val) {
297 *snr = tab[i].data;
f01699b4
ST
298 ret = 0;
299 break;
300 }
301 }
302 dprintk("%s() snr=%d\n", __func__, *snr);
303 return ret;
304}
305
2e7acd75
MK
306static int au8522_set_if(struct dvb_frontend *fe, enum au8522_if_freq if_freq)
307{
308 struct au8522_state *state = fe->demodulator_priv;
df76de09
MK
309 u8 r0b5, r0b6, r0b7;
310 char *ifmhz;
2e7acd75
MK
311
312 switch (if_freq) {
313 case AU8522_IF_3_25MHZ:
df76de09
MK
314 ifmhz = "3.25";
315 r0b5 = 0x00;
316 r0b6 = 0x3d;
317 r0b7 = 0xa0;
2e7acd75
MK
318 break;
319 case AU8522_IF_4MHZ:
df76de09
MK
320 ifmhz = "4.00";
321 r0b5 = 0x00;
322 r0b6 = 0x4b;
323 r0b7 = 0xd9;
2e7acd75
MK
324 break;
325 case AU8522_IF_6MHZ:
df76de09
MK
326 ifmhz = "6.00";
327 r0b5 = 0xfb;
328 r0b6 = 0x8e;
329 r0b7 = 0x39;
2e7acd75
MK
330 break;
331 default:
332 dprintk("%s() IF Frequency not supported\n", __func__);
333 return -EINVAL;
334 }
df76de09
MK
335 dprintk("%s() %s MHz\n", __func__, ifmhz);
336 au8522_writereg(state, 0x80b5, r0b5);
337 au8522_writereg(state, 0x80b6, r0b6);
338 au8522_writereg(state, 0x80b7, r0b7);
339
2e7acd75
MK
340 return 0;
341}
342
f01699b4
ST
343/* VSB Modulation table */
344static struct {
345 u16 reg;
346 u16 data;
347} VSB_mod_tab[] = {
348 { 0x8090, 0x84 },
349 { 0x4092, 0x11 },
350 { 0x2005, 0x00 },
351 { 0x8091, 0x80 },
352 { 0x80a3, 0x0c },
353 { 0x80a4, 0xe8 },
354 { 0x8081, 0xc4 },
355 { 0x80a5, 0x40 },
356 { 0x80a7, 0x40 },
357 { 0x80a6, 0x67 },
358 { 0x8262, 0x20 },
359 { 0x821c, 0x30 },
360 { 0x80d8, 0x1a },
361 { 0x8227, 0xa0 },
362 { 0x8121, 0xff },
363 { 0x80a8, 0xf0 },
364 { 0x80a9, 0x05 },
365 { 0x80aa, 0x77 },
366 { 0x80ab, 0xf0 },
367 { 0x80ac, 0x05 },
368 { 0x80ad, 0x77 },
369 { 0x80ae, 0x41 },
370 { 0x80af, 0x66 },
371 { 0x821b, 0xcc },
372 { 0x821d, 0x80 },
f01699b4
ST
373 { 0x80a4, 0xe8 },
374 { 0x8231, 0x13 },
375};
376
040d4cbf 377/* QAM64 Modulation table */
f01699b4
ST
378static struct {
379 u16 reg;
380 u16 data;
040d4cbf
FD
381} QAM64_mod_tab[] = {
382 { 0x00a3, 0x09 },
383 { 0x00a4, 0x00 },
384 { 0x0081, 0xc4 },
385 { 0x00a5, 0x40 },
386 { 0x00aa, 0x77 },
387 { 0x00ad, 0x77 },
388 { 0x00a6, 0x67 },
389 { 0x0262, 0x20 },
390 { 0x021c, 0x30 },
391 { 0x00b8, 0x3e },
392 { 0x00b9, 0xf0 },
393 { 0x00ba, 0x01 },
394 { 0x00bb, 0x18 },
395 { 0x00bc, 0x50 },
396 { 0x00bd, 0x00 },
397 { 0x00be, 0xea },
398 { 0x00bf, 0xef },
399 { 0x00c0, 0xfc },
400 { 0x00c1, 0xbd },
401 { 0x00c2, 0x1f },
402 { 0x00c3, 0xfc },
403 { 0x00c4, 0xdd },
404 { 0x00c5, 0xaf },
405 { 0x00c6, 0x00 },
406 { 0x00c7, 0x38 },
407 { 0x00c8, 0x30 },
408 { 0x00c9, 0x05 },
409 { 0x00ca, 0x4a },
410 { 0x00cb, 0xd0 },
411 { 0x00cc, 0x01 },
412 { 0x00cd, 0xd9 },
413 { 0x00ce, 0x6f },
414 { 0x00cf, 0xf9 },
415 { 0x00d0, 0x70 },
416 { 0x00d1, 0xdf },
417 { 0x00d2, 0xf7 },
418 { 0x00d3, 0xc2 },
419 { 0x00d4, 0xdf },
420 { 0x00d5, 0x02 },
421 { 0x00d6, 0x9a },
422 { 0x00d7, 0xd0 },
423 { 0x0250, 0x0d },
424 { 0x0251, 0xcd },
425 { 0x0252, 0xe0 },
426 { 0x0253, 0x05 },
427 { 0x0254, 0xa7 },
428 { 0x0255, 0xff },
429 { 0x0256, 0xed },
430 { 0x0257, 0x5b },
431 { 0x0258, 0xae },
432 { 0x0259, 0xe6 },
433 { 0x025a, 0x3d },
434 { 0x025b, 0x0f },
435 { 0x025c, 0x0d },
436 { 0x025d, 0xea },
437 { 0x025e, 0xf2 },
438 { 0x025f, 0x51 },
439 { 0x0260, 0xf5 },
440 { 0x0261, 0x06 },
441 { 0x021a, 0x00 },
442 { 0x0546, 0x40 },
443 { 0x0210, 0xc7 },
444 { 0x0211, 0xaa },
445 { 0x0212, 0xab },
446 { 0x0213, 0x02 },
447 { 0x0502, 0x00 },
448 { 0x0121, 0x04 },
449 { 0x0122, 0x04 },
450 { 0x052e, 0x10 },
451 { 0x00a4, 0xca },
452 { 0x00a7, 0x40 },
453 { 0x0526, 0x01 },
454};
455
456/* QAM256 Modulation table */
457static struct {
458 u16 reg;
459 u16 data;
460} QAM256_mod_tab[] = {
f01699b4
ST
461 { 0x80a3, 0x09 },
462 { 0x80a4, 0x00 },
463 { 0x8081, 0xc4 },
464 { 0x80a5, 0x40 },
f01699b4
ST
465 { 0x80aa, 0x77 },
466 { 0x80ad, 0x77 },
467 { 0x80a6, 0x67 },
468 { 0x8262, 0x20 },
469 { 0x821c, 0x30 },
470 { 0x80b8, 0x3e },
471 { 0x80b9, 0xf0 },
472 { 0x80ba, 0x01 },
473 { 0x80bb, 0x18 },
474 { 0x80bc, 0x50 },
475 { 0x80bd, 0x00 },
476 { 0x80be, 0xea },
477 { 0x80bf, 0xef },
478 { 0x80c0, 0xfc },
479 { 0x80c1, 0xbd },
480 { 0x80c2, 0x1f },
481 { 0x80c3, 0xfc },
482 { 0x80c4, 0xdd },
483 { 0x80c5, 0xaf },
484 { 0x80c6, 0x00 },
485 { 0x80c7, 0x38 },
486 { 0x80c8, 0x30 },
487 { 0x80c9, 0x05 },
488 { 0x80ca, 0x4a },
489 { 0x80cb, 0xd0 },
490 { 0x80cc, 0x01 },
491 { 0x80cd, 0xd9 },
492 { 0x80ce, 0x6f },
493 { 0x80cf, 0xf9 },
494 { 0x80d0, 0x70 },
495 { 0x80d1, 0xdf },
496 { 0x80d2, 0xf7 },
497 { 0x80d3, 0xc2 },
498 { 0x80d4, 0xdf },
499 { 0x80d5, 0x02 },
500 { 0x80d6, 0x9a },
501 { 0x80d7, 0xd0 },
502 { 0x8250, 0x0d },
503 { 0x8251, 0xcd },
504 { 0x8252, 0xe0 },
505 { 0x8253, 0x05 },
506 { 0x8254, 0xa7 },
507 { 0x8255, 0xff },
508 { 0x8256, 0xed },
509 { 0x8257, 0x5b },
510 { 0x8258, 0xae },
511 { 0x8259, 0xe6 },
512 { 0x825a, 0x3d },
513 { 0x825b, 0x0f },
514 { 0x825c, 0x0d },
515 { 0x825d, 0xea },
516 { 0x825e, 0xf2 },
517 { 0x825f, 0x51 },
518 { 0x8260, 0xf5 },
519 { 0x8261, 0x06 },
520 { 0x821a, 0x00 },
521 { 0x8546, 0x40 },
522 { 0x8210, 0x26 },
523 { 0x8211, 0xf6 },
524 { 0x8212, 0x84 },
525 { 0x8213, 0x02 },
526 { 0x8502, 0x01 },
527 { 0x8121, 0x04 },
528 { 0x8122, 0x04 },
529 { 0x852e, 0x10 },
530 { 0x80a4, 0xca },
531 { 0x80a7, 0x40 },
532 { 0x8526, 0x01 },
533};
534
e059b0fa
MK
535static int au8522_enable_modulation(struct dvb_frontend *fe,
536 fe_modulation_t m)
265a6510 537{
e059b0fa 538 struct au8522_state *state = fe->demodulator_priv;
f01699b4 539 int i;
265a6510 540
ce1719a6 541 dprintk("%s(0x%08x)\n", __func__, m);
265a6510 542
18d73c58 543 switch (m) {
265a6510 544 case VSB_8:
ce1719a6 545 dprintk("%s() VSB_8\n", __func__);
f01699b4
ST
546 for (i = 0; i < ARRAY_SIZE(VSB_mod_tab); i++)
547 au8522_writereg(state,
548 VSB_mod_tab[i].reg,
549 VSB_mod_tab[i].data);
2e7acd75 550 au8522_set_if(fe, state->config->vsb_if);
265a6510
ST
551 break;
552 case QAM_64:
040d4cbf
FD
553 dprintk("%s() QAM 64\n", __func__);
554 for (i = 0; i < ARRAY_SIZE(QAM64_mod_tab); i++)
555 au8522_writereg(state,
556 QAM64_mod_tab[i].reg,
557 QAM64_mod_tab[i].data);
558 au8522_set_if(fe, state->config->qam_if);
559 break;
265a6510 560 case QAM_256:
040d4cbf
FD
561 dprintk("%s() QAM 256\n", __func__);
562 for (i = 0; i < ARRAY_SIZE(QAM256_mod_tab); i++)
f01699b4 563 au8522_writereg(state,
040d4cbf
FD
564 QAM256_mod_tab[i].reg,
565 QAM256_mod_tab[i].data);
2e7acd75 566 au8522_set_if(fe, state->config->qam_if);
265a6510
ST
567 break;
568 default:
ce1719a6 569 dprintk("%s() Invalid modulation\n", __func__);
265a6510
ST
570 return -EINVAL;
571 }
572
573 state->current_modulation = m;
574
575 return 0;
576}
577
578/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
e059b0fa
MK
579static int au8522_set_frontend(struct dvb_frontend *fe,
580 struct dvb_frontend_parameters *p)
265a6510 581{
e059b0fa 582 struct au8522_state *state = fe->demodulator_priv;
74d50724 583 int ret = -EINVAL;
265a6510 584
ce1719a6 585 dprintk("%s(frequency=%d)\n", __func__, p->frequency);
265a6510 586
74d50724
MK
587 if ((state->current_frequency == p->frequency) &&
588 (state->current_modulation == p->u.vsb.modulation))
589 return 0;
265a6510
ST
590
591 au8522_enable_modulation(fe, p->u.vsb.modulation);
592
593 /* Allow the demod to settle */
594 msleep(100);
595
596 if (fe->ops.tuner_ops.set_params) {
18d73c58
MCC
597 if (fe->ops.i2c_gate_ctrl)
598 fe->ops.i2c_gate_ctrl(fe, 1);
74d50724 599 ret = fe->ops.tuner_ops.set_params(fe, p);
18d73c58
MCC
600 if (fe->ops.i2c_gate_ctrl)
601 fe->ops.i2c_gate_ctrl(fe, 0);
265a6510
ST
602 }
603
74d50724
MK
604 if (ret < 0)
605 return ret;
606
607 state->current_frequency = p->frequency;
608
265a6510
ST
609 return 0;
610}
611
612/* Reset the demod hardware and reset all of the configuration registers
613 to a default state. */
0c44bf36 614int au8522_init(struct dvb_frontend *fe)
265a6510 615{
e059b0fa 616 struct au8522_state *state = fe->demodulator_priv;
ce1719a6 617 dprintk("%s()\n", __func__);
265a6510 618
7f2c983c
DH
619 state->operational_mode = AU8522_DIGITAL_MODE;
620
b628a2a3
DH
621 /* Clear out any state associated with the digital side of the
622 chip, so that when it gets powered back up it won't think
623 that it is already tuned */
624 state->current_frequency = 0;
625
265a6510
ST
626 au8522_writereg(state, 0xa4, 1 << 5);
627
628 au8522_i2c_gate_ctrl(fe, 1);
629
630 return 0;
631}
632
adeeac3b
MK
633static int au8522_led_gpio_enable(struct au8522_state *state, int onoff)
634{
635 struct au8522_led_config *led_config = state->config->led_cfg;
636 u8 val;
637
25985edc 638 /* bail out if we can't control an LED */
adeeac3b
MK
639 if (!led_config || !led_config->gpio_output ||
640 !led_config->gpio_output_enable || !led_config->gpio_output_disable)
641 return 0;
642
643 val = au8522_readreg(state, 0x4000 |
644 (led_config->gpio_output & ~0xc000));
645 if (onoff) {
646 /* enable GPIO output */
647 val &= ~((led_config->gpio_output_enable >> 8) & 0xff);
648 val |= (led_config->gpio_output_enable & 0xff);
649 } else {
650 /* disable GPIO output */
651 val &= ~((led_config->gpio_output_disable >> 8) & 0xff);
652 val |= (led_config->gpio_output_disable & 0xff);
653 }
654 return au8522_writereg(state, 0x8000 |
655 (led_config->gpio_output & ~0xc000), val);
656}
657
658/* led = 0 | off
659 * led = 1 | signal ok
660 * led = 2 | signal strong
661 * led < 0 | only light led if leds are currently off
662 */
663static int au8522_led_ctrl(struct au8522_state *state, int led)
664{
665 struct au8522_led_config *led_config = state->config->led_cfg;
666 int i, ret = 0;
667
25985edc 668 /* bail out if we can't control an LED */
adeeac3b
MK
669 if (!led_config || !led_config->gpio_leds ||
670 !led_config->num_led_states || !led_config->led_states)
671 return 0;
672
673 if (led < 0) {
674 /* if LED is already lit, then leave it as-is */
675 if (state->led_state)
676 return 0;
677 else
678 led *= -1;
679 }
680
681 /* toggle LED if changing state */
682 if (state->led_state != led) {
683 u8 val;
684
685 dprintk("%s: %d\n", __func__, led);
686
687 au8522_led_gpio_enable(state, 1);
688
689 val = au8522_readreg(state, 0x4000 |
690 (led_config->gpio_leds & ~0xc000));
691
692 /* start with all leds off */
693 for (i = 0; i < led_config->num_led_states; i++)
694 val &= ~led_config->led_states[i];
695
696 /* set selected LED state */
697 if (led < led_config->num_led_states)
698 val |= led_config->led_states[led];
699 else if (led_config->num_led_states)
700 val |=
701 led_config->led_states[led_config->num_led_states - 1];
702
703 ret = au8522_writereg(state, 0x8000 |
704 (led_config->gpio_leds & ~0xc000), val);
705 if (ret < 0)
706 return ret;
707
708 state->led_state = led;
709
710 if (led == 0)
711 au8522_led_gpio_enable(state, 0);
712 }
713
714 return 0;
715}
716
0c44bf36 717int au8522_sleep(struct dvb_frontend *fe)
74d50724
MK
718{
719 struct au8522_state *state = fe->demodulator_priv;
720 dprintk("%s()\n", __func__);
721
7f2c983c
DH
722 /* Only power down if the digital side is currently using the chip */
723 if (state->operational_mode == AU8522_ANALOG_MODE) {
724 /* We're not in one of the expected power modes, which means
725 that the DVB thread is probably telling us to go to sleep
726 even though the analog frontend has already started using
727 the chip. So ignore the request */
728 return 0;
729 }
730
adeeac3b
MK
731 /* turn off led */
732 au8522_led_ctrl(state, 0);
733
7bf63eda
DH
734 /* Power down the chip */
735 au8522_writereg(state, 0xa4, 1 << 5);
736
74d50724
MK
737 state->current_frequency = 0;
738
739 return 0;
740}
741
e059b0fa 742static int au8522_read_status(struct dvb_frontend *fe, fe_status_t *status)
265a6510 743{
e059b0fa 744 struct au8522_state *state = fe->demodulator_priv;
265a6510
ST
745 u8 reg;
746 u32 tuner_status = 0;
747
748 *status = 0;
749
750 if (state->current_modulation == VSB_8) {
ce1719a6 751 dprintk("%s() Checking VSB_8\n", __func__);
265a6510 752 reg = au8522_readreg(state, 0x4088);
836c2858
ST
753 if ((reg & 0x03) == 0x03)
754 *status |= FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI;
265a6510 755 } else {
ce1719a6 756 dprintk("%s() Checking QAM\n", __func__);
265a6510 757 reg = au8522_readreg(state, 0x4541);
e059b0fa 758 if (reg & 0x80)
265a6510 759 *status |= FE_HAS_VITERBI;
e059b0fa 760 if (reg & 0x20)
265a6510
ST
761 *status |= FE_HAS_LOCK | FE_HAS_SYNC;
762 }
763
18d73c58 764 switch (state->config->status_mode) {
265a6510 765 case AU8522_DEMODLOCKING:
ce1719a6 766 dprintk("%s() DEMODLOCKING\n", __func__);
265a6510
ST
767 if (*status & FE_HAS_VITERBI)
768 *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
769 break;
770 case AU8522_TUNERLOCKING:
771 /* Get the tuner status */
ce1719a6 772 dprintk("%s() TUNERLOCKING\n", __func__);
265a6510
ST
773 if (fe->ops.tuner_ops.get_status) {
774 if (fe->ops.i2c_gate_ctrl)
775 fe->ops.i2c_gate_ctrl(fe, 1);
776
777 fe->ops.tuner_ops.get_status(fe, &tuner_status);
778
779 if (fe->ops.i2c_gate_ctrl)
780 fe->ops.i2c_gate_ctrl(fe, 0);
781 }
782 if (tuner_status)
783 *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
784 break;
785 }
adeeac3b
MK
786 state->fe_status = *status;
787
788 if (*status & FE_HAS_LOCK)
789 /* turn on LED, if it isn't on already */
790 au8522_led_ctrl(state, -1);
791 else
792 /* turn off LED */
793 au8522_led_ctrl(state, 0);
265a6510 794
ce1719a6 795 dprintk("%s() status 0x%08x\n", __func__, *status);
265a6510
ST
796
797 return 0;
798}
799
adeeac3b
MK
800static int au8522_led_status(struct au8522_state *state, const u16 *snr)
801{
802 struct au8522_led_config *led_config = state->config->led_cfg;
803 int led;
804 u16 strong;
805
25985edc 806 /* bail out if we can't control an LED */
adeeac3b
MK
807 if (!led_config)
808 return 0;
809
810 if (0 == (state->fe_status & FE_HAS_LOCK))
811 return au8522_led_ctrl(state, 0);
812 else if (state->current_modulation == QAM_256)
813 strong = led_config->qam256_strong;
814 else if (state->current_modulation == QAM_64)
815 strong = led_config->qam64_strong;
816 else /* (state->current_modulation == VSB_8) */
817 strong = led_config->vsb8_strong;
818
819 if (*snr >= strong)
820 led = 2;
821 else
822 led = 1;
823
824 if ((state->led_state) &&
825 (((strong < *snr) ? (*snr - strong) : (strong - *snr)) <= 10))
826 /* snr didn't change enough to bother
827 * changing the color of the led */
828 return 0;
829
830 return au8522_led_ctrl(state, led);
831}
832
f01699b4 833static int au8522_read_snr(struct dvb_frontend *fe, u16 *snr)
fb8152cb
MK
834{
835 struct au8522_state *state = fe->demodulator_priv;
f01699b4 836 int ret = -EINVAL;
fb8152cb 837
ce1719a6 838 dprintk("%s()\n", __func__);
265a6510 839
f01699b4 840 if (state->current_modulation == QAM_256)
0daa5de7
MK
841 ret = au8522_mse2snr_lookup(qam256_mse2snr_tab,
842 ARRAY_SIZE(qam256_mse2snr_tab),
843 au8522_readreg(state, 0x4522),
844 snr);
f01699b4 845 else if (state->current_modulation == QAM_64)
0daa5de7
MK
846 ret = au8522_mse2snr_lookup(qam64_mse2snr_tab,
847 ARRAY_SIZE(qam64_mse2snr_tab),
848 au8522_readreg(state, 0x4522),
849 snr);
f01699b4 850 else /* VSB_8 */
0daa5de7
MK
851 ret = au8522_mse2snr_lookup(vsb_mse2snr_tab,
852 ARRAY_SIZE(vsb_mse2snr_tab),
853 au8522_readreg(state, 0x4311),
854 snr);
f01699b4 855
adeeac3b
MK
856 if (state->config->led_cfg)
857 au8522_led_status(state, snr);
858
f01699b4 859 return ret;
265a6510
ST
860}
861
e059b0fa
MK
862static int au8522_read_signal_strength(struct dvb_frontend *fe,
863 u16 *signal_strength)
265a6510 864{
5279b1ff
MK
865 /* borrowed from lgdt330x.c
866 *
867 * Calculate strength from SNR up to 35dB
868 * Even though the SNR can go higher than 35dB,
869 * there is some comfort factor in having a range of
870 * strong signals that can show at 100%
871 */
872 u16 snr;
873 u32 tmp;
874 int ret = au8522_read_snr(fe, &snr);
875
876 *signal_strength = 0;
877
878 if (0 == ret) {
879 /* The following calculation method was chosen
880 * purely for the sake of code re-use from the
881 * other demod drivers that use this method */
882
883 /* Convert from SNR in dB * 10 to 8.24 fixed-point */
884 tmp = (snr * ((1 << 24) / 10));
885
886 /* Convert from 8.24 fixed-point to
887 * scale the range 0 - 35*2^24 into 0 - 65535*/
888 if (tmp >= 8960 * 0x10000)
889 *signal_strength = 0xffff;
890 else
891 *signal_strength = tmp / 8960;
892 }
893
894 return ret;
265a6510
ST
895}
896
e059b0fa 897static int au8522_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
265a6510 898{
e059b0fa 899 struct au8522_state *state = fe->demodulator_priv;
265a6510 900
8973dc4b
MK
901 if (state->current_modulation == VSB_8)
902 *ucblocks = au8522_readreg(state, 0x4087);
903 else
904 *ucblocks = au8522_readreg(state, 0x4543);
265a6510
ST
905
906 return 0;
907}
908
e059b0fa 909static int au8522_read_ber(struct dvb_frontend *fe, u32 *ber)
265a6510
ST
910{
911 return au8522_read_ucblocks(fe, ber);
912}
913
e059b0fa 914static int au8522_get_frontend(struct dvb_frontend *fe,
265a6510
ST
915 struct dvb_frontend_parameters *p)
916{
e059b0fa 917 struct au8522_state *state = fe->demodulator_priv;
265a6510
ST
918
919 p->frequency = state->current_frequency;
920 p->u.vsb.modulation = state->current_modulation;
921
922 return 0;
923}
924
e059b0fa
MK
925static int au8522_get_tune_settings(struct dvb_frontend *fe,
926 struct dvb_frontend_tune_settings *tune)
265a6510
ST
927{
928 tune->min_delay_ms = 1000;
929 return 0;
930}
931
209fdf66
DH
932static struct dvb_frontend_ops au8522_ops;
933
934int au8522_get_state(struct au8522_state **state, struct i2c_adapter *i2c,
935 u8 client_address)
936{
4ff5ed44
DH
937 int ret;
938
939 mutex_lock(&au8522_list_mutex);
940 ret = hybrid_tuner_request_state(struct au8522_state, (*state),
941 hybrid_tuner_instance_list,
942 i2c, client_address, "au8522");
943 mutex_unlock(&au8522_list_mutex);
944
945 return ret;
209fdf66
DH
946}
947
948void au8522_release_state(struct au8522_state *state)
949{
4ff5ed44 950 mutex_lock(&au8522_list_mutex);
209fdf66
DH
951 if (state != NULL)
952 hybrid_tuner_release_state(state);
4ff5ed44 953 mutex_unlock(&au8522_list_mutex);
209fdf66
DH
954}
955
956
e059b0fa 957static void au8522_release(struct dvb_frontend *fe)
265a6510 958{
e059b0fa 959 struct au8522_state *state = fe->demodulator_priv;
209fdf66 960 au8522_release_state(state);
265a6510
ST
961}
962
e059b0fa
MK
963struct dvb_frontend *au8522_attach(const struct au8522_config *config,
964 struct i2c_adapter *i2c)
265a6510 965{
e059b0fa 966 struct au8522_state *state = NULL;
209fdf66 967 int instance;
265a6510
ST
968
969 /* allocate memory for the internal state */
209fdf66
DH
970 instance = au8522_get_state(&state, i2c, config->demod_address);
971 switch (instance) {
972 case 0:
973 dprintk("%s state allocation failed\n", __func__);
974 break;
975 case 1:
976 /* new demod instance */
977 dprintk("%s using new instance\n", __func__);
978 break;
979 default:
980 /* existing demod instance */
981 dprintk("%s using existing instance\n", __func__);
982 break;
983 }
265a6510
ST
984
985 /* setup the state */
986 state->config = config;
987 state->i2c = i2c;
7f2c983c
DH
988 state->operational_mode = AU8522_DIGITAL_MODE;
989
265a6510
ST
990 /* create dvb_frontend */
991 memcpy(&state->frontend.ops, &au8522_ops,
992 sizeof(struct dvb_frontend_ops));
993 state->frontend.demodulator_priv = state;
994
995 if (au8522_init(&state->frontend) != 0) {
996 printk(KERN_ERR "%s: Failed to initialize correctly\n",
ce1719a6 997 __func__);
265a6510
ST
998 goto error;
999 }
1000
1001 /* Note: Leaving the I2C gate open here. */
1002 au8522_i2c_gate_ctrl(&state->frontend, 1);
1003
1004 return &state->frontend;
1005
1006error:
209fdf66 1007 au8522_release_state(state);
265a6510
ST
1008 return NULL;
1009}
18d73c58 1010EXPORT_SYMBOL(au8522_attach);
265a6510
ST
1011
1012static struct dvb_frontend_ops au8522_ops = {
1013
1014 .info = {
1015 .name = "Auvitek AU8522 QAM/8VSB Frontend",
1016 .type = FE_ATSC,
1017 .frequency_min = 54000000,
1018 .frequency_max = 858000000,
1019 .frequency_stepsize = 62500,
1020 .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
1021 },
1022
1023 .init = au8522_init,
74d50724 1024 .sleep = au8522_sleep,
265a6510
ST
1025 .i2c_gate_ctrl = au8522_i2c_gate_ctrl,
1026 .set_frontend = au8522_set_frontend,
1027 .get_frontend = au8522_get_frontend,
1028 .get_tune_settings = au8522_get_tune_settings,
1029 .read_status = au8522_read_status,
1030 .read_ber = au8522_read_ber,
1031 .read_signal_strength = au8522_read_signal_strength,
1032 .read_snr = au8522_read_snr,
1033 .read_ucblocks = au8522_read_ucblocks,
1034 .release = au8522_release,
1035};
1036
1037module_param(debug, int, 0644);
1038MODULE_PARM_DESC(debug, "Enable verbose debug messages");
1039
1040MODULE_DESCRIPTION("Auvitek AU8522 QAM-B/ATSC Demodulator driver");
1041MODULE_AUTHOR("Steven Toth");
1042MODULE_LICENSE("GPL");