• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/drivers/media/dvb/frontends/
1/*
2    Auvitek AU8522 QAM/8VSB demodulator driver
3
4    Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
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>
26#include <linux/delay.h>
27#include "dvb_frontend.h"
28#include "au8522.h"
29#include "au8522_priv.h"
30
31static int debug;
32
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);
36static DEFINE_MUTEX(au8522_list_mutex);
37
38#define dprintk(arg...)\
39	do { if (debug)\
40		printk(arg);\
41	} while (0)
42
43/* 16 bit registers, 8 bit values */
44int au8522_writereg(struct au8522_state *state, u16 reg, u8 data)
45{
46	int ret;
47	u8 buf[] = { (reg >> 8) | 0x80, reg & 0xff, data };
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, "
56		       "ret == %i)\n", __func__, reg, data, ret);
57
58	return (ret != 1) ? -1 : 0;
59}
60
61u8 au8522_readreg(struct au8522_state *state, u16 reg)
62{
63	int ret;
64	u8 b0[] = { (reg >> 8) | 0x40, reg & 0xff };
65	u8 b1[] = { 0 };
66
67	struct i2c_msg msg[] = {
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)
76		printk(KERN_ERR "%s: readreg error (ret == %i)\n",
77		       __func__, ret);
78	return b1[0];
79}
80
81static int 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		/* 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
95	if (enable)
96		return au8522_writereg(state, 0x106, 1);
97	else
98		return au8522_writereg(state, 0x106, 0);
99}
100
101struct mse2snr_tab {
102	u16 val;
103	u16 data;
104};
105
106/* VSB SNR lookup table */
107static struct mse2snr_tab vsb_mse2snr_tab[] = {
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 */
141static struct mse2snr_tab qam64_mse2snr_tab[] = {
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 */
222static struct mse2snr_tab qam256_mse2snr_tab[] = {
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
289static int au8522_mse2snr_lookup(struct mse2snr_tab *tab, int sz, int mse,
290				 u16 *snr)
291{
292	int i, ret = -EINVAL;
293	dprintk("%s()\n", __func__);
294
295	for (i = 0; i < sz; i++) {
296		if (mse < tab[i].val) {
297			*snr = tab[i].data;
298			ret = 0;
299			break;
300		}
301	}
302	dprintk("%s() snr=%d\n", __func__, *snr);
303	return ret;
304}
305
306static int au8522_set_if(struct dvb_frontend *fe, enum au8522_if_freq if_freq)
307{
308	struct au8522_state *state = fe->demodulator_priv;
309	u8 r0b5, r0b6, r0b7;
310	char *ifmhz;
311
312	switch (if_freq) {
313	case AU8522_IF_3_25MHZ:
314		ifmhz = "3.25";
315		r0b5 = 0x00;
316		r0b6 = 0x3d;
317		r0b7 = 0xa0;
318		break;
319	case AU8522_IF_4MHZ:
320		ifmhz = "4.00";
321		r0b5 = 0x00;
322		r0b6 = 0x4b;
323		r0b7 = 0xd9;
324		break;
325	case AU8522_IF_6MHZ:
326		ifmhz = "6.00";
327		r0b5 = 0xfb;
328		r0b6 = 0x8e;
329		r0b7 = 0x39;
330		break;
331	default:
332		dprintk("%s() IF Frequency not supported\n", __func__);
333		return -EINVAL;
334	}
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
340	return 0;
341}
342
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 },
373	{ 0x80a4, 0xe8 },
374	{ 0x8231, 0x13 },
375};
376
377/* QAM64 Modulation table */
378static struct {
379	u16 reg;
380	u16 data;
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[] = {
461	{ 0x80a3, 0x09 },
462	{ 0x80a4, 0x00 },
463	{ 0x8081, 0xc4 },
464	{ 0x80a5, 0x40 },
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
535static int au8522_enable_modulation(struct dvb_frontend *fe,
536				    fe_modulation_t m)
537{
538	struct au8522_state *state = fe->demodulator_priv;
539	int i;
540
541	dprintk("%s(0x%08x)\n", __func__, m);
542
543	switch (m) {
544	case VSB_8:
545		dprintk("%s() VSB_8\n", __func__);
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);
550		au8522_set_if(fe, state->config->vsb_if);
551		break;
552	case QAM_64:
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;
560	case QAM_256:
561		dprintk("%s() QAM 256\n", __func__);
562		for (i = 0; i < ARRAY_SIZE(QAM256_mod_tab); i++)
563			au8522_writereg(state,
564				QAM256_mod_tab[i].reg,
565				QAM256_mod_tab[i].data);
566		au8522_set_if(fe, state->config->qam_if);
567		break;
568	default:
569		dprintk("%s() Invalid modulation\n", __func__);
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 */
579static int au8522_set_frontend(struct dvb_frontend *fe,
580			       struct dvb_frontend_parameters *p)
581{
582	struct au8522_state *state = fe->demodulator_priv;
583	int ret = -EINVAL;
584
585	dprintk("%s(frequency=%d)\n", __func__, p->frequency);
586
587	if ((state->current_frequency == p->frequency) &&
588	    (state->current_modulation == p->u.vsb.modulation))
589		return 0;
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) {
597		if (fe->ops.i2c_gate_ctrl)
598			fe->ops.i2c_gate_ctrl(fe, 1);
599		ret = fe->ops.tuner_ops.set_params(fe, p);
600		if (fe->ops.i2c_gate_ctrl)
601			fe->ops.i2c_gate_ctrl(fe, 0);
602	}
603
604	if (ret < 0)
605		return ret;
606
607	state->current_frequency = p->frequency;
608
609	return 0;
610}
611
612/* Reset the demod hardware and reset all of the configuration registers
613   to a default state. */
614int au8522_init(struct dvb_frontend *fe)
615{
616	struct au8522_state *state = fe->demodulator_priv;
617	dprintk("%s()\n", __func__);
618
619	state->operational_mode = AU8522_DIGITAL_MODE;
620
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
626	au8522_writereg(state, 0xa4, 1 << 5);
627
628	au8522_i2c_gate_ctrl(fe, 1);
629
630	return 0;
631}
632
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
638	/* bail out if we cant control an LED */
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
668	/* bail out if we cant control an LED */
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
717int au8522_sleep(struct dvb_frontend *fe)
718{
719	struct au8522_state *state = fe->demodulator_priv;
720	dprintk("%s()\n", __func__);
721
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
731	/* turn off led */
732	au8522_led_ctrl(state, 0);
733
734	/* Power down the chip */
735	au8522_writereg(state, 0xa4, 1 << 5);
736
737	state->current_frequency = 0;
738
739	return 0;
740}
741
742static int au8522_read_status(struct dvb_frontend *fe, fe_status_t *status)
743{
744	struct au8522_state *state = fe->demodulator_priv;
745	u8 reg;
746	u32 tuner_status = 0;
747
748	*status = 0;
749
750	if (state->current_modulation == VSB_8) {
751		dprintk("%s() Checking VSB_8\n", __func__);
752		reg = au8522_readreg(state, 0x4088);
753		if ((reg & 0x03) == 0x03)
754			*status |= FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI;
755	} else {
756		dprintk("%s() Checking QAM\n", __func__);
757		reg = au8522_readreg(state, 0x4541);
758		if (reg & 0x80)
759			*status |= FE_HAS_VITERBI;
760		if (reg & 0x20)
761			*status |= FE_HAS_LOCK | FE_HAS_SYNC;
762	}
763
764	switch (state->config->status_mode) {
765	case AU8522_DEMODLOCKING:
766		dprintk("%s() DEMODLOCKING\n", __func__);
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 */
772		dprintk("%s() TUNERLOCKING\n", __func__);
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	}
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);
794
795	dprintk("%s() status 0x%08x\n", __func__, *status);
796
797	return 0;
798}
799
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
806	/* bail out if we cant control an LED */
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
833static int au8522_read_snr(struct dvb_frontend *fe, u16 *snr)
834{
835	struct au8522_state *state = fe->demodulator_priv;
836	int ret = -EINVAL;
837
838	dprintk("%s()\n", __func__);
839
840	if (state->current_modulation == QAM_256)
841		ret = au8522_mse2snr_lookup(qam256_mse2snr_tab,
842					    ARRAY_SIZE(qam256_mse2snr_tab),
843					    au8522_readreg(state, 0x4522),
844					    snr);
845	else if (state->current_modulation == QAM_64)
846		ret = au8522_mse2snr_lookup(qam64_mse2snr_tab,
847					    ARRAY_SIZE(qam64_mse2snr_tab),
848					    au8522_readreg(state, 0x4522),
849					    snr);
850	else /* VSB_8 */
851		ret = au8522_mse2snr_lookup(vsb_mse2snr_tab,
852					    ARRAY_SIZE(vsb_mse2snr_tab),
853					    au8522_readreg(state, 0x4311),
854					    snr);
855
856	if (state->config->led_cfg)
857		au8522_led_status(state, snr);
858
859	return ret;
860}
861
862static int au8522_read_signal_strength(struct dvb_frontend *fe,
863				       u16 *signal_strength)
864{
865	return au8522_read_snr(fe, signal_strength);
866}
867
868static int au8522_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
869{
870	struct au8522_state *state = fe->demodulator_priv;
871
872	if (state->current_modulation == VSB_8)
873		*ucblocks = au8522_readreg(state, 0x4087);
874	else
875		*ucblocks = au8522_readreg(state, 0x4543);
876
877	return 0;
878}
879
880static int au8522_read_ber(struct dvb_frontend *fe, u32 *ber)
881{
882	return au8522_read_ucblocks(fe, ber);
883}
884
885static int au8522_get_frontend(struct dvb_frontend *fe,
886				struct dvb_frontend_parameters *p)
887{
888	struct au8522_state *state = fe->demodulator_priv;
889
890	p->frequency = state->current_frequency;
891	p->u.vsb.modulation = state->current_modulation;
892
893	return 0;
894}
895
896static int au8522_get_tune_settings(struct dvb_frontend *fe,
897				    struct dvb_frontend_tune_settings *tune)
898{
899	tune->min_delay_ms = 1000;
900	return 0;
901}
902
903static struct dvb_frontend_ops au8522_ops;
904
905int au8522_get_state(struct au8522_state **state, struct i2c_adapter *i2c,
906		     u8 client_address)
907{
908	int ret;
909
910	mutex_lock(&au8522_list_mutex);
911	ret = hybrid_tuner_request_state(struct au8522_state, (*state),
912					 hybrid_tuner_instance_list,
913					 i2c, client_address, "au8522");
914	mutex_unlock(&au8522_list_mutex);
915
916	return ret;
917}
918
919void au8522_release_state(struct au8522_state *state)
920{
921	mutex_lock(&au8522_list_mutex);
922	if (state != NULL)
923		hybrid_tuner_release_state(state);
924	mutex_unlock(&au8522_list_mutex);
925}
926
927
928static void au8522_release(struct dvb_frontend *fe)
929{
930	struct au8522_state *state = fe->demodulator_priv;
931	au8522_release_state(state);
932}
933
934struct dvb_frontend *au8522_attach(const struct au8522_config *config,
935				   struct i2c_adapter *i2c)
936{
937	struct au8522_state *state = NULL;
938	int instance;
939
940	/* allocate memory for the internal state */
941	instance = au8522_get_state(&state, i2c, config->demod_address);
942	switch (instance) {
943	case 0:
944		dprintk("%s state allocation failed\n", __func__);
945		break;
946	case 1:
947		/* new demod instance */
948		dprintk("%s using new instance\n", __func__);
949		break;
950	default:
951		/* existing demod instance */
952		dprintk("%s using existing instance\n", __func__);
953		break;
954	}
955
956	/* setup the state */
957	state->config = config;
958	state->i2c = i2c;
959	state->operational_mode = AU8522_DIGITAL_MODE;
960
961	/* create dvb_frontend */
962	memcpy(&state->frontend.ops, &au8522_ops,
963	       sizeof(struct dvb_frontend_ops));
964	state->frontend.demodulator_priv = state;
965
966	if (au8522_init(&state->frontend) != 0) {
967		printk(KERN_ERR "%s: Failed to initialize correctly\n",
968			__func__);
969		goto error;
970	}
971
972	/* Note: Leaving the I2C gate open here. */
973	au8522_i2c_gate_ctrl(&state->frontend, 1);
974
975	return &state->frontend;
976
977error:
978	au8522_release_state(state);
979	return NULL;
980}
981EXPORT_SYMBOL(au8522_attach);
982
983static struct dvb_frontend_ops au8522_ops = {
984
985	.info = {
986		.name			= "Auvitek AU8522 QAM/8VSB Frontend",
987		.type			= FE_ATSC,
988		.frequency_min		= 54000000,
989		.frequency_max		= 858000000,
990		.frequency_stepsize	= 62500,
991		.caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
992	},
993
994	.init                 = au8522_init,
995	.sleep                = au8522_sleep,
996	.i2c_gate_ctrl        = au8522_i2c_gate_ctrl,
997	.set_frontend         = au8522_set_frontend,
998	.get_frontend         = au8522_get_frontend,
999	.get_tune_settings    = au8522_get_tune_settings,
1000	.read_status          = au8522_read_status,
1001	.read_ber             = au8522_read_ber,
1002	.read_signal_strength = au8522_read_signal_strength,
1003	.read_snr             = au8522_read_snr,
1004	.read_ucblocks        = au8522_read_ucblocks,
1005	.release              = au8522_release,
1006};
1007
1008module_param(debug, int, 0644);
1009MODULE_PARM_DESC(debug, "Enable verbose debug messages");
1010
1011MODULE_DESCRIPTION("Auvitek AU8522 QAM-B/ATSC Demodulator driver");
1012MODULE_AUTHOR("Steven Toth");
1013MODULE_LICENSE("GPL");
1014