Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/media/dvb/frontends/au8522_dig.c
15112 views
1
/*
2
Auvitek AU8522 QAM/8VSB demodulator driver
3
4
Copyright (C) 2008 Steven Toth <[email protected]>
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
31
static int debug;
32
33
/* Despite the name "hybrid_tuner", the framework works just as well for
34
hybrid demodulators as well... */
35
static LIST_HEAD(hybrid_tuner_instance_list);
36
static 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 */
44
int 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
61
u8 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
81
static 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
101
struct mse2snr_tab {
102
u16 val;
103
u16 data;
104
};
105
106
/* VSB SNR lookup table */
107
static 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 */
141
static 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 */
222
static 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
289
static 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
306
static 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 */
344
static 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 */
378
static 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 */
457
static 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
535
static 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 */
579
static 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. */
614
int 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
633
static 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 can't 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
*/
663
static 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 can't 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
717
int 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
742
static 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
800
static 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 can't 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
833
static 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
862
static int au8522_read_signal_strength(struct dvb_frontend *fe,
863
u16 *signal_strength)
864
{
865
return au8522_read_snr(fe, signal_strength);
866
}
867
868
static 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
880
static int au8522_read_ber(struct dvb_frontend *fe, u32 *ber)
881
{
882
return au8522_read_ucblocks(fe, ber);
883
}
884
885
static 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
896
static 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
903
static struct dvb_frontend_ops au8522_ops;
904
905
int 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
919
void 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
928
static void au8522_release(struct dvb_frontend *fe)
929
{
930
struct au8522_state *state = fe->demodulator_priv;
931
au8522_release_state(state);
932
}
933
934
struct 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
977
error:
978
au8522_release_state(state);
979
return NULL;
980
}
981
EXPORT_SYMBOL(au8522_attach);
982
983
static 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
1008
module_param(debug, int, 0644);
1009
MODULE_PARM_DESC(debug, "Enable verbose debug messages");
1010
1011
MODULE_DESCRIPTION("Auvitek AU8522 QAM-B/ATSC Demodulator driver");
1012
MODULE_AUTHOR("Steven Toth");
1013
MODULE_LICENSE("GPL");
1014
1015