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
26
27
28
29
30
31
32
33#include <linux/module.h>
34#include <linux/kernel.h>
35#include <linux/sched.h>
36
37#include <linux/videodev2.h>
38#include <linux/i2c.h>
39#include <media/v4l2-device.h>
40#include <media/v4l2-i2c-drv.h>
41
42MODULE_DESCRIPTION("Philips SAA717x audio/video decoder driver");
43MODULE_AUTHOR("K. Ohta, T. Adachi, Hans Verkuil");
44MODULE_LICENSE("GPL");
45
46static int debug;
47module_param(debug, int, 0644);
48MODULE_PARM_DESC(debug, "Debug level (0-1)");
49
50
51
52
53
54
55struct saa717x_state {
56 struct v4l2_subdev sd;
57 v4l2_std_id std;
58 int input;
59 int enable;
60 int radio;
61 int bright;
62 int contrast;
63 int hue;
64 int sat;
65 int playback;
66 int audio;
67 int tuner_audio_mode;
68 int audio_main_mute;
69 int audio_main_vol_r;
70 int audio_main_vol_l;
71 u16 audio_main_bass;
72 u16 audio_main_treble;
73 u16 audio_main_volume;
74 u16 audio_main_balance;
75 int audio_input;
76};
77
78static inline struct saa717x_state *to_state(struct v4l2_subdev *sd)
79{
80 return container_of(sd, struct saa717x_state, sd);
81}
82
83
84
85
86#define TUNER_AUDIO_MONO 0
87#define TUNER_AUDIO_STEREO 1
88#define TUNER_AUDIO_LANG1 2
89#define TUNER_AUDIO_LANG2 3
90
91#define SAA717X_NTSC_WIDTH (704)
92#define SAA717X_NTSC_HEIGHT (480)
93
94
95
96static int saa717x_write(struct v4l2_subdev *sd, u32 reg, u32 value)
97{
98 struct i2c_client *client = v4l2_get_subdevdata(sd);
99 struct i2c_adapter *adap = client->adapter;
100 int fw_addr = reg == 0x454 || (reg >= 0x464 && reg <= 0x478) || reg == 0x480 || reg == 0x488;
101 unsigned char mm1[6];
102 struct i2c_msg msg;
103
104 msg.flags = 0;
105 msg.addr = client->addr;
106 mm1[0] = (reg >> 8) & 0xff;
107 mm1[1] = reg & 0xff;
108
109 if (fw_addr) {
110 mm1[4] = (value >> 16) & 0xff;
111 mm1[3] = (value >> 8) & 0xff;
112 mm1[2] = value & 0xff;
113 } else {
114 mm1[2] = value & 0xff;
115 }
116 msg.len = fw_addr ? 5 : 3;
117 msg.buf = mm1;
118 v4l2_dbg(2, debug, sd, "wrote: reg 0x%03x=%08x\n", reg, value);
119 return i2c_transfer(adap, &msg, 1) == 1;
120}
121
122static void saa717x_write_regs(struct v4l2_subdev *sd, u32 *data)
123{
124 while (data[0] || data[1]) {
125 saa717x_write(sd, data[0], data[1]);
126 data += 2;
127 }
128}
129
130static u32 saa717x_read(struct v4l2_subdev *sd, u32 reg)
131{
132 struct i2c_client *client = v4l2_get_subdevdata(sd);
133 struct i2c_adapter *adap = client->adapter;
134 int fw_addr = (reg >= 0x404 && reg <= 0x4b8) || reg == 0x528;
135 unsigned char mm1[2];
136 unsigned char mm2[4] = { 0, 0, 0, 0 };
137 struct i2c_msg msgs[2];
138 u32 value;
139
140 msgs[0].flags = 0;
141 msgs[1].flags = I2C_M_RD;
142 msgs[0].addr = msgs[1].addr = client->addr;
143 mm1[0] = (reg >> 8) & 0xff;
144 mm1[1] = reg & 0xff;
145 msgs[0].len = 2;
146 msgs[0].buf = mm1;
147 msgs[1].len = fw_addr ? 3 : 1;
148 msgs[1].buf = mm2;
149 i2c_transfer(adap, msgs, 2);
150
151 if (fw_addr)
152 value = (mm2[2] & 0xff) | ((mm2[1] & 0xff) >> 8) | ((mm2[0] & 0xff) >> 16);
153 else
154 value = mm2[0] & 0xff;
155
156 v4l2_dbg(2, debug, sd, "read: reg 0x%03x=0x%08x\n", reg, value);
157 return value;
158}
159
160
161
162static u32 reg_init_initialize[] =
163{
164
165 0x101, 0x008,
166
167 0x103, 0x000,
168 0x104, 0x090,
169 0x105, 0x090,
170 0x106, 0x0eb,
171 0x107, 0x0e0,
172 0x109, 0x055,
173
174 0x10f, 0x02a,
175 0x110, 0x000,
176
177 0x114, 0x045,
178
179 0x118, 0x040,
180 0x119, 0x080,
181
182 0x044, 0x000,
183 0x045, 0x000,
184 0x046, 0x0cf,
185 0x047, 0x002,
186
187 0x049, 0x000,
188
189 0x04c, 0x0d0,
190 0x04d, 0x002,
191
192 0x064, 0x080,
193 0x065, 0x040,
194 0x066, 0x040,
195
196 0x068, 0x000,
197 0x069, 0x004,
198 0x06a, 0x000,
199
200 0x06e, 0x000,
201 0x06f, 0x000,
202
203 0x072, 0x000,
204
205 0x084, 0x000,
206 0x085, 0x000,
207 0x086, 0x0cf,
208 0x087, 0x002,
209
210 0x089, 0x000,
211
212 0x08c, 0x0d0,
213 0x08d, 0x002,
214
215 0x0a4, 0x080,
216 0x0a5, 0x040,
217 0x0a6, 0x040,
218
219 0x0a8, 0x000,
220 0x0a9, 0x004,
221 0x0aa, 0x000,
222
223 0x0ae, 0x000,
224 0x0af, 0x000,
225
226 0x0b2, 0x000,
227
228 0x00c, 0x000,
229 0x00d, 0x000,
230 0x00e, 0x000,
231
232 0x010, 0x010,
233 0x011, 0x020,
234 0x012, 0x030,
235 0x013, 0x040,
236 0x014, 0x050,
237 0x015, 0x060,
238 0x016, 0x070,
239 0x017, 0x080,
240 0x018, 0x090,
241 0x019, 0x0a0,
242 0x01a, 0x0b0,
243 0x01b, 0x0c0,
244 0x01c, 0x0d0,
245 0x01d, 0x0e0,
246 0x01e, 0x0f0,
247 0x01f, 0x0ff,
248
249 0x020, 0x010,
250 0x021, 0x020,
251 0x022, 0x030,
252 0x023, 0x040,
253 0x024, 0x050,
254 0x025, 0x060,
255 0x026, 0x070,
256 0x027, 0x080,
257 0x028, 0x090,
258 0x029, 0x0a0,
259 0x02a, 0x0b0,
260 0x02b, 0x0c0,
261 0x02c, 0x0d0,
262 0x02d, 0x0e0,
263 0x02e, 0x0f0,
264 0x02f, 0x0ff,
265
266 0x030, 0x010,
267 0x031, 0x020,
268 0x032, 0x030,
269 0x033, 0x040,
270 0x034, 0x050,
271 0x035, 0x060,
272 0x036, 0x070,
273 0x037, 0x080,
274 0x038, 0x090,
275 0x039, 0x0a0,
276 0x03a, 0x0b0,
277 0x03b, 0x0c0,
278 0x03c, 0x0d0,
279 0x03d, 0x0e0,
280 0x03e, 0x0f0,
281 0x03f, 0x0ff,
282
283 0x109, 0x085,
284
285
286 0x584, 0x000,
287 0x585, 0x000,
288 0x586, 0x003,
289 0x588, 0x0ff,
290 0x589, 0x00f,
291 0x58a, 0x000,
292 0x58b, 0x000,
293 0x58c, 0x010,
294 0x58d, 0x032,
295 0x58e, 0x054,
296 0x58f, 0x023,
297 0x590, 0x000,
298
299 0x595, 0x000,
300 0x596, 0x000,
301 0x597, 0x000,
302
303 0x464, 0x00,
304
305 0x46c, 0xbbbb10,
306 0x470, 0x101010,
307
308 0x478, 0x00,
309
310 0x474, 0x18,
311
312 0x454, 0x0425b9,
313 0x454, 0x042539,
314
315
316
317 0x042, 0x003,
318
319 0x082, 0x003,
320
321 0x108, 0x0f8,
322 0x2a9, 0x0fd,
323 0x102, 0x089,
324 0x111, 0x000,
325
326 0x10e, 0x00a,
327
328 0x594, 0x002,
329
330 0x454, 0x0425b9,
331 0x454, 0x042539,
332
333 0x111, 0x000,
334 0x10e, 0x00a,
335 0x464, 0x000,
336 0x300, 0x000,
337 0x301, 0x006,
338 0x302, 0x000,
339 0x303, 0x006,
340 0x308, 0x040,
341 0x309, 0x000,
342 0x30a, 0x000,
343 0x30b, 0x000,
344 0x000, 0x002,
345 0x001, 0x000,
346 0x002, 0x000,
347 0x003, 0x000,
348 0x004, 0x033,
349 0x040, 0x01d,
350 0x041, 0x001,
351 0x042, 0x004,
352 0x043, 0x000,
353 0x080, 0x01e,
354 0x081, 0x001,
355 0x082, 0x004,
356 0x083, 0x000,
357 0x190, 0x018,
358 0x115, 0x000,
359 0x116, 0x012,
360 0x117, 0x018,
361 0x04a, 0x011,
362 0x08a, 0x011,
363 0x04b, 0x000,
364 0x08b, 0x000,
365 0x048, 0x000,
366 0x088, 0x000,
367 0x04e, 0x012,
368 0x08e, 0x012,
369 0x058, 0x012,
370 0x098, 0x012,
371 0x059, 0x000,
372 0x099, 0x000,
373 0x05a, 0x003,
374 0x09a, 0x003,
375 0x05b, 0x001,
376 0x09b, 0x001,
377 0x054, 0x008,
378 0x094, 0x008,
379 0x055, 0x000,
380 0x095, 0x000,
381 0x056, 0x0c7,
382 0x096, 0x0c7,
383 0x057, 0x002,
384 0x097, 0x002,
385 0x0ff, 0x0ff,
386 0x060, 0x001,
387 0x0a0, 0x001,
388 0x061, 0x000,
389 0x0a1, 0x000,
390 0x062, 0x000,
391 0x0a2, 0x000,
392 0x063, 0x000,
393 0x0a3, 0x000,
394 0x070, 0x000,
395 0x0b0, 0x000,
396 0x071, 0x004,
397 0x0b1, 0x004,
398 0x06c, 0x0e9,
399 0x0ac, 0x0e9,
400 0x06d, 0x003,
401 0x0ad, 0x003,
402 0x05c, 0x0d0,
403 0x09c, 0x0d0,
404 0x05d, 0x002,
405 0x09d, 0x002,
406 0x05e, 0x0f2,
407 0x09e, 0x0f2,
408 0x05f, 0x000,
409 0x09f, 0x000,
410 0x074, 0x000,
411 0x0b4, 0x000,
412 0x075, 0x000,
413 0x0b5, 0x000,
414 0x076, 0x000,
415 0x0b6, 0x000,
416 0x077, 0x000,
417 0x0b7, 0x000,
418 0x195, 0x008,
419 0x0ff, 0x0ff,
420 0x108, 0x0f8,
421 0x111, 0x000,
422 0x10e, 0x00a,
423 0x2a9, 0x0fd,
424 0x464, 0x001,
425 0x454, 0x042135,
426 0x598, 0x0e7,
427 0x599, 0x07d,
428 0x59a, 0x018,
429 0x59c, 0x066,
430 0x59d, 0x090,
431 0x59e, 0x001,
432 0x584, 0x000,
433 0x585, 0x000,
434 0x586, 0x003,
435 0x588, 0x0ff,
436 0x589, 0x00f,
437 0x58a, 0x000,
438 0x58b, 0x000,
439 0x58c, 0x010,
440 0x58d, 0x032,
441 0x58e, 0x054,
442 0x58f, 0x023,
443 0x590, 0x000,
444 0x595, 0x000,
445 0x596, 0x000,
446 0x597, 0x000,
447 0x464, 0x000,
448 0x46c, 0xbbbb10,
449 0x470, 0x101010,
450
451
452 0x478, 0x000,
453 0x474, 0x018,
454 0x454, 0x042135,
455 0x598, 0x0e7,
456 0x599, 0x07d,
457 0x59a, 0x018,
458 0x59c, 0x066,
459 0x59d, 0x090,
460 0x59e, 0x001,
461 0x584, 0x000,
462 0x585, 0x000,
463 0x586, 0x003,
464 0x588, 0x0ff,
465 0x589, 0x00f,
466 0x58a, 0x000,
467 0x58b, 0x000,
468 0x58c, 0x010,
469 0x58d, 0x032,
470 0x58e, 0x054,
471 0x58f, 0x023,
472 0x590, 0x000,
473 0x595, 0x000,
474 0x596, 0x000,
475 0x597, 0x000,
476 0x464, 0x000,
477 0x46c, 0xbbbb10,
478 0x470, 0x101010,
479
480 0x478, 0x000,
481 0x474, 0x018,
482 0x454, 0x042135,
483 0x598, 0x0e7,
484 0x599, 0x07d,
485 0x59a, 0x018,
486 0x59c, 0x066,
487 0x59d, 0x090,
488 0x59e, 0x001,
489 0x584, 0x000,
490 0x585, 0x000,
491 0x586, 0x003,
492 0x588, 0x0ff,
493 0x589, 0x00f,
494 0x58a, 0x000,
495 0x58b, 0x000,
496 0x58c, 0x010,
497 0x58d, 0x032,
498 0x58e, 0x054,
499 0x58f, 0x023,
500 0x590, 0x000,
501 0x595, 0x000,
502 0x596, 0x000,
503 0x597, 0x000,
504 0x464, 0x000,
505 0x46c, 0xbbbb10,
506 0x470, 0x101010,
507 0x478, 0x000,
508 0x474, 0x018,
509 0x454, 0x042135,
510 0x193, 0x000,
511 0x300, 0x000,
512 0x301, 0x006,
513 0x302, 0x000,
514 0x303, 0x006,
515 0x308, 0x040,
516 0x309, 0x000,
517 0x30a, 0x000,
518 0x30b, 0x000,
519 0x000, 0x002,
520 0x001, 0x000,
521 0x002, 0x000,
522 0x003, 0x000,
523 0x004, 0x033,
524 0x040, 0x01d,
525 0x041, 0x001,
526 0x042, 0x004,
527 0x043, 0x000,
528 0x080, 0x01e,
529 0x081, 0x001,
530 0x082, 0x004,
531 0x083, 0x000,
532 0x190, 0x018,
533 0x115, 0x000,
534 0x116, 0x012,
535 0x117, 0x018,
536 0x04a, 0x011,
537 0x08a, 0x011,
538 0x04b, 0x000,
539 0x08b, 0x000,
540 0x048, 0x000,
541 0x088, 0x000,
542 0x04e, 0x012,
543 0x08e, 0x012,
544 0x058, 0x012,
545 0x098, 0x012,
546 0x059, 0x000,
547 0x099, 0x000,
548 0x05a, 0x003,
549 0x09a, 0x003,
550 0x05b, 0x001,
551 0x09b, 0x001,
552 0x054, 0x008,
553 0x094, 0x008,
554 0x055, 0x000,
555 0x095, 0x000,
556 0x056, 0x0c7,
557 0x096, 0x0c7,
558 0x057, 0x002,
559 0x097, 0x002,
560 0x060, 0x001,
561 0x0a0, 0x001,
562 0x061, 0x000,
563 0x0a1, 0x000,
564 0x062, 0x000,
565 0x0a2, 0x000,
566 0x063, 0x000,
567 0x0a3, 0x000,
568 0x070, 0x000,
569 0x0b0, 0x000,
570 0x071, 0x004,
571 0x0b1, 0x004,
572 0x06c, 0x0e9,
573 0x0ac, 0x0e9,
574 0x06d, 0x003,
575 0x0ad, 0x003,
576 0x05c, 0x0d0,
577 0x09c, 0x0d0,
578 0x05d, 0x002,
579 0x09d, 0x002,
580 0x05e, 0x0f2,
581 0x09e, 0x0f2,
582 0x05f, 0x000,
583 0x09f, 0x000,
584 0x074, 0x000,
585 0x0b4, 0x000,
586 0x075, 0x000,
587 0x0b5, 0x000,
588 0x076, 0x000,
589 0x0b6, 0x000,
590 0x077, 0x000,
591 0x0b7, 0x000,
592 0x195, 0x008,
593 0x598, 0x0e7,
594 0x599, 0x07d,
595 0x59a, 0x018,
596 0x59c, 0x066,
597 0x59d, 0x090,
598 0x59e, 0x001,
599 0x584, 0x000,
600 0x585, 0x000,
601 0x586, 0x003,
602 0x588, 0x0ff,
603 0x589, 0x00f,
604 0x58a, 0x000,
605 0x58b, 0x000,
606 0x58c, 0x010,
607 0x58d, 0x032,
608 0x58e, 0x054,
609 0x58f, 0x023,
610 0x590, 0x000,
611 0x595, 0x000,
612 0x596, 0x000,
613 0x597, 0x000,
614 0x464, 0x000,
615 0x46c, 0xbbbb10,
616 0x470, 0x101010,
617 0x478, 0x000,
618 0x474, 0x018,
619 0x454, 0x042135,
620 0x193, 0x0a6,
621 0x108, 0x0f8,
622 0x042, 0x003,
623 0x082, 0x003,
624 0x454, 0x0425b9,
625 0x454, 0x042539,
626 0x193, 0x000,
627 0x193, 0x0a6,
628 0x464, 0x000,
629
630 0, 0
631};
632
633
634static u32 reg_init_tuner_input[] = {
635 0x108, 0x0f8,
636 0x111, 0x000,
637 0x10e, 0x00a,
638 0, 0
639};
640
641
642static u32 reg_init_composite_input[] = {
643 0x108, 0x0e8,
644 0x111, 0x000,
645 0x10e, 0x04a,
646 0, 0
647};
648
649
650static u32 reg_init_svideo_input[] = {
651 0x108, 0x0e8,
652 0x111, 0x000,
653 0x10e, 0x04a,
654 0, 0
655};
656
657static u32 reg_set_audio_template[4][2] =
658{
659 {
660
661
662
663
664
665
666
667
668
669 0xbbbb00,
670
671
672
673
674
675 0x00,
676 },
677 {
678 0xbbbb10, 0x101010,
679 },
680 {
681 0xbbbb00, 0x00,
682 },
683 {
684 0xbbbb11, 0x111111,
685 }
686};
687
688
689
690static void get_inf_dev_status(struct v4l2_subdev *sd,
691 int *dual_flag, int *stereo_flag)
692{
693 u32 reg_data3;
694
695 static char *stdres[0x20] = {
696 [0x00] = "no standard detected",
697 [0x01] = "B/G (in progress)",
698 [0x02] = "D/K (in progress)",
699 [0x03] = "M (in progress)",
700
701 [0x04] = "B/G A2",
702 [0x05] = "B/G NICAM",
703 [0x06] = "D/K A2 (1)",
704 [0x07] = "D/K A2 (2)",
705 [0x08] = "D/K A2 (3)",
706 [0x09] = "D/K NICAM",
707 [0x0a] = "L NICAM",
708 [0x0b] = "I NICAM",
709
710 [0x0c] = "M Korea",
711 [0x0d] = "M BTSC ",
712 [0x0e] = "M EIAJ",
713
714 [0x0f] = "FM radio / IF 10.7 / 50 deemp",
715 [0x10] = "FM radio / IF 10.7 / 75 deemp",
716 [0x11] = "FM radio / IF sel / 50 deemp",
717 [0x12] = "FM radio / IF sel / 75 deemp",
718
719 [0x13 ... 0x1e] = "unknown",
720 [0x1f] = "??? [in progress]",
721 };
722
723
724 *dual_flag = *stereo_flag = 0;
725
726
727
728
729 reg_data3 = saa717x_read(sd, 0x0528);
730
731 v4l2_dbg(1, debug, sd, "tvaudio thread status: 0x%x [%s%s%s]\n",
732 reg_data3, stdres[reg_data3 & 0x1f],
733 (reg_data3 & 0x000020) ? ",stereo" : "",
734 (reg_data3 & 0x000040) ? ",dual" : "");
735 v4l2_dbg(1, debug, sd, "detailed status: "
736 "%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s\n",
737 (reg_data3 & 0x000080) ? " A2/EIAJ pilot tone " : "",
738 (reg_data3 & 0x000100) ? " A2/EIAJ dual " : "",
739 (reg_data3 & 0x000200) ? " A2/EIAJ stereo " : "",
740 (reg_data3 & 0x000400) ? " A2/EIAJ noise mute " : "",
741
742 (reg_data3 & 0x000800) ? " BTSC/FM radio pilot " : "",
743 (reg_data3 & 0x001000) ? " SAP carrier " : "",
744 (reg_data3 & 0x002000) ? " BTSC stereo noise mute " : "",
745 (reg_data3 & 0x004000) ? " SAP noise mute " : "",
746 (reg_data3 & 0x008000) ? " VDSP " : "",
747
748 (reg_data3 & 0x010000) ? " NICST " : "",
749 (reg_data3 & 0x020000) ? " NICDU " : "",
750 (reg_data3 & 0x040000) ? " NICAM muted " : "",
751 (reg_data3 & 0x080000) ? " NICAM reserve sound " : "",
752
753 (reg_data3 & 0x100000) ? " init done " : "");
754
755 if (reg_data3 & 0x000220) {
756 v4l2_dbg(1, debug, sd, "ST!!!\n");
757 *stereo_flag = 1;
758 }
759
760 if (reg_data3 & 0x000140) {
761 v4l2_dbg(1, debug, sd, "DUAL!!!\n");
762 *dual_flag = 1;
763 }
764}
765
766
767static void set_audio_mode(struct v4l2_subdev *sd, int audio_mode)
768{
769 v4l2_dbg(1, debug, sd, "writing registers to set audio mode by set %d\n",
770 audio_mode);
771
772 saa717x_write(sd, 0x46c, reg_set_audio_template[audio_mode][0]);
773 saa717x_write(sd, 0x470, reg_set_audio_template[audio_mode][1]);
774}
775
776
777static void set_video_output_level_regs(struct v4l2_subdev *sd,
778 struct saa717x_state *decoder)
779{
780
781 saa717x_write(sd, 0x10a, decoder->bright);
782
783
784
785
786
787 saa717x_write(sd, 0x10b, decoder->contrast);
788
789
790
791
792 saa717x_write(sd, 0x10c, decoder->sat);
793
794
795
796 saa717x_write(sd, 0x10d, decoder->hue);
797}
798
799
800static int set_audio_regs(struct v4l2_subdev *sd,
801 struct saa717x_state *decoder)
802{
803 u8 mute = 0xac;
804 u32 val;
805 unsigned int work_l, work_r;
806
807
808 saa717x_write(sd, 0x0594, decoder->audio_input);
809 v4l2_dbg(1, debug, sd, "set audio input %d\n",
810 decoder->audio_input);
811
812
813 work_l = (min(65536 - decoder->audio_main_balance, 32768) * decoder->audio_main_volume) / 32768;
814 work_r = (min(decoder->audio_main_balance, (u16)32768) * decoder->audio_main_volume) / 32768;
815 decoder->audio_main_vol_l = (long)work_l * (24 - (-40)) / 65535 - 40;
816 decoder->audio_main_vol_r = (long)work_r * (24 - (-40)) / 65535 - 40;
817
818
819
820
821
822 if (decoder->audio_main_mute) {
823 val = mute | (mute << 8);
824 } else {
825 val = (u8)decoder->audio_main_vol_l |
826 ((u8)decoder->audio_main_vol_r << 8);
827 }
828
829 saa717x_write(sd, 0x480, val);
830
831
832
833 val = decoder->audio_main_bass | (decoder->audio_main_treble << 8);
834 saa717x_write(sd, 0x488, val);
835 return 0;
836}
837
838
839static void set_h_prescale(struct v4l2_subdev *sd,
840 int task, int prescale)
841{
842 static const struct {
843 int xpsc;
844 int xacl;
845 int xc2_1;
846 int xdcg;
847 int vpfy;
848 } vals[] = {
849
850 { 1, 0, 0, 0, 0 },
851 { 2, 2, 1, 2, 2 },
852 { 3, 4, 1, 3, 2 },
853 { 4, 8, 1, 4, 2 },
854 { 5, 8, 1, 4, 2 },
855 { 6, 8, 1, 4, 3 },
856 { 7, 8, 1, 4, 3 },
857 { 8, 15, 0, 4, 3 },
858 { 9, 15, 0, 4, 3 },
859 { 10, 16, 1, 5, 3 },
860 };
861 static const int count = ARRAY_SIZE(vals);
862 int i, task_shift;
863
864 task_shift = task * 0x40;
865 for (i = 0; i < count; i++)
866 if (vals[i].xpsc == prescale)
867 break;
868 if (i == count)
869 return;
870
871
872 saa717x_write(sd, 0x60 + task_shift, vals[i].xpsc);
873
874 saa717x_write(sd, 0x61 + task_shift, vals[i].xacl);
875
876 saa717x_write(sd, 0x62 + task_shift,
877 (vals[i].xc2_1 << 3) | vals[i].xdcg);
878
879 saa717x_write(sd, 0x63 + task_shift,
880 (vals[i].vpfy << 2) | vals[i].vpfy);
881}
882
883
884static void set_v_scale(struct v4l2_subdev *sd, int task, int yscale)
885{
886 int task_shift;
887
888 task_shift = task * 0x40;
889
890 saa717x_write(sd, 0x70 + task_shift, yscale & 0xff);
891
892 saa717x_write(sd, 0x71 + task_shift, yscale >> 8);
893}
894
895static int saa717x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
896{
897 struct saa717x_state *state = to_state(sd);
898
899 switch (ctrl->id) {
900 case V4L2_CID_BRIGHTNESS:
901 if (ctrl->value < 0 || ctrl->value > 255) {
902 v4l2_err(sd, "invalid brightness setting %d\n", ctrl->value);
903 return -ERANGE;
904 }
905
906 state->bright = ctrl->value;
907 v4l2_dbg(1, debug, sd, "bright:%d\n", state->bright);
908 saa717x_write(sd, 0x10a, state->bright);
909 break;
910
911 case V4L2_CID_CONTRAST:
912 if (ctrl->value < 0 || ctrl->value > 127) {
913 v4l2_err(sd, "invalid contrast setting %d\n", ctrl->value);
914 return -ERANGE;
915 }
916
917 state->contrast = ctrl->value;
918 v4l2_dbg(1, debug, sd, "contrast:%d\n", state->contrast);
919 saa717x_write(sd, 0x10b, state->contrast);
920 break;
921
922 case V4L2_CID_SATURATION:
923 if (ctrl->value < 0 || ctrl->value > 127) {
924 v4l2_err(sd, "invalid saturation setting %d\n", ctrl->value);
925 return -ERANGE;
926 }
927
928 state->sat = ctrl->value;
929 v4l2_dbg(1, debug, sd, "sat:%d\n", state->sat);
930 saa717x_write(sd, 0x10c, state->sat);
931 break;
932
933 case V4L2_CID_HUE:
934 if (ctrl->value < -128 || ctrl->value > 127) {
935 v4l2_err(sd, "invalid hue setting %d\n", ctrl->value);
936 return -ERANGE;
937 }
938
939 state->hue = ctrl->value;
940 v4l2_dbg(1, debug, sd, "hue:%d\n", state->hue);
941 saa717x_write(sd, 0x10d, state->hue);
942 break;
943
944 case V4L2_CID_AUDIO_MUTE:
945 state->audio_main_mute = ctrl->value;
946 set_audio_regs(sd, state);
947 break;
948
949 case V4L2_CID_AUDIO_VOLUME:
950 state->audio_main_volume = ctrl->value;
951 set_audio_regs(sd, state);
952 break;
953
954 case V4L2_CID_AUDIO_BALANCE:
955 state->audio_main_balance = ctrl->value;
956 set_audio_regs(sd, state);
957 break;
958
959 case V4L2_CID_AUDIO_TREBLE:
960 state->audio_main_treble = ctrl->value;
961 set_audio_regs(sd, state);
962 break;
963
964 case V4L2_CID_AUDIO_BASS:
965 state->audio_main_bass = ctrl->value;
966 set_audio_regs(sd, state);
967 break;
968
969 default:
970 return -EINVAL;
971 }
972
973 return 0;
974}
975
976static int saa717x_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
977{
978 struct saa717x_state *state = to_state(sd);
979
980 switch (ctrl->id) {
981 case V4L2_CID_BRIGHTNESS:
982 ctrl->value = state->bright;
983 break;
984
985 case V4L2_CID_CONTRAST:
986 ctrl->value = state->contrast;
987 break;
988
989 case V4L2_CID_SATURATION:
990 ctrl->value = state->sat;
991 break;
992
993 case V4L2_CID_HUE:
994 ctrl->value = state->hue;
995 break;
996
997 case V4L2_CID_AUDIO_MUTE:
998 ctrl->value = state->audio_main_mute;
999 break;
1000
1001 case V4L2_CID_AUDIO_VOLUME:
1002 ctrl->value = state->audio_main_volume;
1003 break;
1004
1005 case V4L2_CID_AUDIO_BALANCE:
1006 ctrl->value = state->audio_main_balance;
1007 break;
1008
1009 case V4L2_CID_AUDIO_TREBLE:
1010 ctrl->value = state->audio_main_treble;
1011 break;
1012
1013 case V4L2_CID_AUDIO_BASS:
1014 ctrl->value = state->audio_main_bass;
1015 break;
1016
1017 default:
1018 return -EINVAL;
1019 }
1020
1021 return 0;
1022}
1023
1024static struct v4l2_queryctrl saa717x_qctrl[] = {
1025 {
1026 .id = V4L2_CID_BRIGHTNESS,
1027 .type = V4L2_CTRL_TYPE_INTEGER,
1028 .name = "Brightness",
1029 .minimum = 0,
1030 .maximum = 255,
1031 .step = 1,
1032 .default_value = 128,
1033 .flags = 0,
1034 }, {
1035 .id = V4L2_CID_CONTRAST,
1036 .type = V4L2_CTRL_TYPE_INTEGER,
1037 .name = "Contrast",
1038 .minimum = 0,
1039 .maximum = 255,
1040 .step = 1,
1041 .default_value = 64,
1042 .flags = 0,
1043 }, {
1044 .id = V4L2_CID_SATURATION,
1045 .type = V4L2_CTRL_TYPE_INTEGER,
1046 .name = "Saturation",
1047 .minimum = 0,
1048 .maximum = 255,
1049 .step = 1,
1050 .default_value = 64,
1051 .flags = 0,
1052 }, {
1053 .id = V4L2_CID_HUE,
1054 .type = V4L2_CTRL_TYPE_INTEGER,
1055 .name = "Hue",
1056 .minimum = -128,
1057 .maximum = 127,
1058 .step = 1,
1059 .default_value = 0,
1060 .flags = 0,
1061 }, {
1062 .id = V4L2_CID_AUDIO_VOLUME,
1063 .type = V4L2_CTRL_TYPE_INTEGER,
1064 .name = "Volume",
1065 .minimum = 0,
1066 .maximum = 65535,
1067 .step = 65535 / 100,
1068 .default_value = 58880,
1069 .flags = 0,
1070 }, {
1071 .id = V4L2_CID_AUDIO_BALANCE,
1072 .type = V4L2_CTRL_TYPE_INTEGER,
1073 .name = "Balance",
1074 .minimum = 0,
1075 .maximum = 65535,
1076 .step = 65535 / 100,
1077 .default_value = 32768,
1078 .flags = 0,
1079 }, {
1080 .id = V4L2_CID_AUDIO_MUTE,
1081 .type = V4L2_CTRL_TYPE_BOOLEAN,
1082 .name = "Mute",
1083 .minimum = 0,
1084 .maximum = 1,
1085 .step = 1,
1086 .default_value = 1,
1087 .flags = 0,
1088 }, {
1089 .id = V4L2_CID_AUDIO_BASS,
1090 .type = V4L2_CTRL_TYPE_INTEGER,
1091 .name = "Bass",
1092 .minimum = 0,
1093 .maximum = 65535,
1094 .step = 65535 / 100,
1095 .default_value = 32768,
1096 }, {
1097 .id = V4L2_CID_AUDIO_TREBLE,
1098 .type = V4L2_CTRL_TYPE_INTEGER,
1099 .name = "Treble",
1100 .minimum = 0,
1101 .maximum = 65535,
1102 .step = 65535 / 100,
1103 .default_value = 32768,
1104 },
1105};
1106
1107static int saa717x_s_video_routing(struct v4l2_subdev *sd,
1108 u32 input, u32 output, u32 config)
1109{
1110 struct saa717x_state *decoder = to_state(sd);
1111 int is_tuner = input & 0x80;
1112
1113 input &= 0x7f;
1114
1115 v4l2_dbg(1, debug, sd, "decoder set input (%d)\n", input);
1116
1117
1118 if (input < 0 || input > 9 || input == 5)
1119 return -EINVAL;
1120
1121 if (decoder->input != input) {
1122 int input_line = input;
1123
1124 decoder->input = input_line;
1125 v4l2_dbg(1, debug, sd, "now setting %s input %d\n",
1126 input_line >= 6 ? "S-Video" : "Composite",
1127 input_line);
1128
1129
1130 saa717x_write(sd, 0x102,
1131 (saa717x_read(sd, 0x102) & 0xf0) |
1132 input_line);
1133
1134
1135 saa717x_write(sd, 0x109,
1136 (saa717x_read(sd, 0x109) & 0x7f) |
1137 (input_line < 6 ? 0x0 : 0x80));
1138
1139
1140 if (is_tuner) {
1141
1142 set_audio_mode(sd, decoder->tuner_audio_mode);
1143 } else {
1144
1145
1146 set_audio_mode(sd, TUNER_AUDIO_STEREO);
1147 }
1148
1149 if (is_tuner)
1150 saa717x_write_regs(sd, reg_init_tuner_input);
1151 else if (input_line >= 6)
1152 saa717x_write_regs(sd, reg_init_svideo_input);
1153 else
1154 saa717x_write_regs(sd, reg_init_composite_input);
1155 }
1156
1157 return 0;
1158}
1159
1160static int saa717x_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
1161{
1162 int i;
1163
1164 for (i = 0; i < ARRAY_SIZE(saa717x_qctrl); i++)
1165 if (qc->id && qc->id == saa717x_qctrl[i].id) {
1166 memcpy(qc, &saa717x_qctrl[i], sizeof(*qc));
1167 return 0;
1168 }
1169 return -EINVAL;
1170}
1171
1172#ifdef CONFIG_VIDEO_ADV_DEBUG
1173static int saa717x_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
1174{
1175 struct i2c_client *client = v4l2_get_subdevdata(sd);
1176
1177 if (!v4l2_chip_match_i2c_client(client, ®->match))
1178 return -EINVAL;
1179 if (!capable(CAP_SYS_ADMIN))
1180 return -EPERM;
1181 reg->val = saa717x_read(sd, reg->reg);
1182 reg->size = 1;
1183 return 0;
1184}
1185
1186static int saa717x_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
1187{
1188 struct i2c_client *client = v4l2_get_subdevdata(sd);
1189 u16 addr = reg->reg & 0xffff;
1190 u8 val = reg->val & 0xff;
1191
1192 if (!v4l2_chip_match_i2c_client(client, ®->match))
1193 return -EINVAL;
1194 if (!capable(CAP_SYS_ADMIN))
1195 return -EPERM;
1196 saa717x_write(sd, addr, val);
1197 return 0;
1198}
1199#endif
1200
1201static int saa717x_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
1202{
1203 struct v4l2_pix_format *pix;
1204 int prescale, h_scale, v_scale;
1205
1206 pix = &fmt->fmt.pix;
1207 v4l2_dbg(1, debug, sd, "decoder set size\n");
1208
1209
1210 if (pix->width < 1 || pix->width > 1440)
1211 return -EINVAL;
1212 if (pix->height < 1 || pix->height > 960)
1213 return -EINVAL;
1214
1215
1216
1217 prescale = SAA717X_NTSC_WIDTH / pix->width;
1218 if (prescale == 0)
1219 prescale = 1;
1220 h_scale = 1024 * SAA717X_NTSC_WIDTH / prescale / pix->width;
1221
1222 v_scale = 512 * 2 * SAA717X_NTSC_HEIGHT / pix->height;
1223
1224
1225 set_h_prescale(sd, 0, prescale);
1226 set_h_prescale(sd, 1, prescale);
1227
1228
1229
1230 saa717x_write(sd, 0x6C, (u8)(h_scale & 0xFF));
1231 saa717x_write(sd, 0x6D, (u8)((h_scale >> 8) & 0xFF));
1232
1233 saa717x_write(sd, 0xAC, (u8)(h_scale & 0xFF));
1234 saa717x_write(sd, 0xAD, (u8)((h_scale >> 8) & 0xFF));
1235
1236
1237 set_v_scale(sd, 0, v_scale);
1238 set_v_scale(sd, 1, v_scale);
1239
1240
1241
1242
1243 saa717x_write(sd, 0x5C, (u8)(pix->width & 0xFF));
1244 saa717x_write(sd, 0x5D, (u8)((pix->width >> 8) & 0xFF));
1245
1246 saa717x_write(sd, 0x9C, (u8)(pix->width & 0xFF));
1247 saa717x_write(sd, 0x9D, (u8)((pix->width >> 8) & 0xFF));
1248
1249
1250
1251 saa717x_write(sd, 0x5E, (u8)(pix->height & 0xFF));
1252 saa717x_write(sd, 0x5F, (u8)((pix->height >> 8) & 0xFF));
1253
1254 saa717x_write(sd, 0x9E, (u8)(pix->height & 0xFF));
1255 saa717x_write(sd, 0x9F, (u8)((pix->height >> 8) & 0xFF));
1256 return 0;
1257}
1258
1259static int saa717x_s_radio(struct v4l2_subdev *sd)
1260{
1261 struct saa717x_state *decoder = to_state(sd);
1262
1263 decoder->radio = 1;
1264 return 0;
1265}
1266
1267static int saa717x_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
1268{
1269 struct saa717x_state *decoder = to_state(sd);
1270
1271 v4l2_dbg(1, debug, sd, "decoder set norm ");
1272 v4l2_dbg(1, debug, sd, "(not yet implementd)\n");
1273
1274 decoder->radio = 0;
1275 decoder->std = std;
1276 return 0;
1277}
1278
1279static int saa717x_s_audio_routing(struct v4l2_subdev *sd,
1280 u32 input, u32 output, u32 config)
1281{
1282 struct saa717x_state *decoder = to_state(sd);
1283
1284 if (input < 3) {
1285 decoder->audio_input = input;
1286 v4l2_dbg(1, debug, sd,
1287 "set decoder audio input to %d\n",
1288 decoder->audio_input);
1289 set_audio_regs(sd, decoder);
1290 return 0;
1291 }
1292 return -ERANGE;
1293}
1294
1295static int saa717x_s_stream(struct v4l2_subdev *sd, int enable)
1296{
1297 struct saa717x_state *decoder = to_state(sd);
1298
1299 v4l2_dbg(1, debug, sd, "decoder %s output\n",
1300 enable ? "enable" : "disable");
1301 decoder->enable = enable;
1302 saa717x_write(sd, 0x193, enable ? 0xa6 : 0x26);
1303 return 0;
1304}
1305
1306
1307static int saa717x_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
1308{
1309 struct saa717x_state *decoder = to_state(sd);
1310 int audio_mode;
1311 char *mes[4] = {
1312 "MONO", "STEREO", "LANG1", "LANG2/SAP"
1313 };
1314
1315 audio_mode = V4L2_TUNER_MODE_STEREO;
1316
1317 switch (vt->audmode) {
1318 case V4L2_TUNER_MODE_MONO:
1319 audio_mode = TUNER_AUDIO_MONO;
1320 break;
1321 case V4L2_TUNER_MODE_STEREO:
1322 audio_mode = TUNER_AUDIO_STEREO;
1323 break;
1324 case V4L2_TUNER_MODE_LANG2:
1325 audio_mode = TUNER_AUDIO_LANG2;
1326 break;
1327 case V4L2_TUNER_MODE_LANG1:
1328 audio_mode = TUNER_AUDIO_LANG1;
1329 break;
1330 }
1331
1332 v4l2_dbg(1, debug, sd, "change audio mode to %s\n",
1333 mes[audio_mode]);
1334 decoder->tuner_audio_mode = audio_mode;
1335
1336
1337 set_audio_mode(sd, decoder->tuner_audio_mode);
1338 return 0;
1339}
1340
1341static int saa717x_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
1342{
1343 struct saa717x_state *decoder = to_state(sd);
1344 int dual_f, stereo_f;
1345
1346 if (decoder->radio)
1347 return 0;
1348 get_inf_dev_status(sd, &dual_f, &stereo_f);
1349
1350 v4l2_dbg(1, debug, sd, "DETECT==st:%d dual:%d\n",
1351 stereo_f, dual_f);
1352
1353
1354 if ((dual_f == 0) && (stereo_f == 0)) {
1355 vt->rxsubchans = V4L2_TUNER_SUB_MONO;
1356 v4l2_dbg(1, debug, sd, "DETECT==MONO\n");
1357 }
1358
1359
1360 if (stereo_f == 1) {
1361 if (vt->audmode == V4L2_TUNER_MODE_STEREO ||
1362 vt->audmode == V4L2_TUNER_MODE_LANG1) {
1363 vt->rxsubchans = V4L2_TUNER_SUB_STEREO;
1364 v4l2_dbg(1, debug, sd, "DETECT==ST(ST)\n");
1365 } else {
1366 vt->rxsubchans = V4L2_TUNER_SUB_MONO;
1367 v4l2_dbg(1, debug, sd, "DETECT==ST(MONO)\n");
1368 }
1369 }
1370
1371
1372 if (dual_f == 1) {
1373 if (vt->audmode == V4L2_TUNER_MODE_LANG2) {
1374 vt->rxsubchans = V4L2_TUNER_SUB_LANG2 | V4L2_TUNER_SUB_MONO;
1375 v4l2_dbg(1, debug, sd, "DETECT==DUAL1\n");
1376 } else {
1377 vt->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_MONO;
1378 v4l2_dbg(1, debug, sd, "DETECT==DUAL2\n");
1379 }
1380 }
1381 return 0;
1382}
1383
1384
1385
1386static const struct v4l2_subdev_core_ops saa717x_core_ops = {
1387#ifdef CONFIG_VIDEO_ADV_DEBUG
1388 .g_register = saa717x_g_register,
1389 .s_register = saa717x_s_register,
1390#endif
1391 .queryctrl = saa717x_queryctrl,
1392 .g_ctrl = saa717x_g_ctrl,
1393 .s_ctrl = saa717x_s_ctrl,
1394 .s_std = saa717x_s_std,
1395};
1396
1397static const struct v4l2_subdev_tuner_ops saa717x_tuner_ops = {
1398 .g_tuner = saa717x_g_tuner,
1399 .s_tuner = saa717x_s_tuner,
1400 .s_radio = saa717x_s_radio,
1401};
1402
1403static const struct v4l2_subdev_video_ops saa717x_video_ops = {
1404 .s_routing = saa717x_s_video_routing,
1405 .s_fmt = saa717x_s_fmt,
1406 .s_stream = saa717x_s_stream,
1407};
1408
1409static const struct v4l2_subdev_audio_ops saa717x_audio_ops = {
1410 .s_routing = saa717x_s_audio_routing,
1411};
1412
1413static const struct v4l2_subdev_ops saa717x_ops = {
1414 .core = &saa717x_core_ops,
1415 .tuner = &saa717x_tuner_ops,
1416 .audio = &saa717x_audio_ops,
1417 .video = &saa717x_video_ops,
1418};
1419
1420
1421
1422
1423
1424
1425
1426static int saa717x_probe(struct i2c_client *client,
1427 const struct i2c_device_id *did)
1428{
1429 struct saa717x_state *decoder;
1430 struct v4l2_subdev *sd;
1431 u8 id = 0;
1432 char *p = "";
1433
1434
1435 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
1436 return -EIO;
1437
1438 decoder = kzalloc(sizeof(struct saa717x_state), GFP_KERNEL);
1439 if (decoder == NULL)
1440 return -ENOMEM;
1441
1442 sd = &decoder->sd;
1443 v4l2_i2c_subdev_init(sd, client, &saa717x_ops);
1444
1445 if (saa717x_write(sd, 0x5a4, 0xfe) &&
1446 saa717x_write(sd, 0x5a5, 0x0f) &&
1447 saa717x_write(sd, 0x5a6, 0x00) &&
1448 saa717x_write(sd, 0x5a7, 0x01))
1449 id = saa717x_read(sd, 0x5a0);
1450 if (id != 0xc2 && id != 0x32 && id != 0xf2 && id != 0x6c) {
1451 v4l2_dbg(1, debug, sd, "saa717x not found (id=%02x)\n", id);
1452 kfree(decoder);
1453 return -ENODEV;
1454 }
1455 if (id == 0xc2)
1456 p = "saa7173";
1457 else if (id == 0x32)
1458 p = "saa7174A";
1459 else if (id == 0x6c)
1460 p = "saa7174HL";
1461 else
1462 p = "saa7171";
1463 v4l2_info(sd, "%s found @ 0x%x (%s)\n", p,
1464 client->addr << 1, client->adapter->name);
1465 decoder->std = V4L2_STD_NTSC;
1466 decoder->input = -1;
1467 decoder->enable = 1;
1468
1469
1470 decoder->bright = 0x80;
1471 decoder->contrast = 0x44;
1472 decoder->sat = 0x40;
1473 decoder->hue = 0x00;
1474
1475
1476 decoder->playback = 0;
1477 decoder->audio = 1;
1478
1479 decoder->audio_input = 2;
1480
1481 decoder->tuner_audio_mode = TUNER_AUDIO_STEREO;
1482
1483 decoder->audio_main_vol_l = 6;
1484 decoder->audio_main_vol_r = 6;
1485 decoder->audio_main_bass = 0;
1486 decoder->audio_main_treble = 0;
1487 decoder->audio_main_mute = 0;
1488 decoder->audio_main_balance = 32768;
1489
1490 decoder->audio_main_volume =
1491 (decoder->audio_main_vol_r + 41) * 65535 / (24 - (-40));
1492
1493 v4l2_dbg(1, debug, sd, "writing init values\n");
1494
1495
1496 saa717x_write_regs(sd, reg_init_initialize);
1497 set_video_output_level_regs(sd, decoder);
1498
1499 decoder->audio_main_bass = 0;
1500 decoder->audio_main_treble = 0;
1501 set_audio_regs(sd, decoder);
1502
1503 set_current_state(TASK_INTERRUPTIBLE);
1504 schedule_timeout(2*HZ);
1505 return 0;
1506}
1507
1508static int saa717x_remove(struct i2c_client *client)
1509{
1510 struct v4l2_subdev *sd = i2c_get_clientdata(client);
1511
1512 v4l2_device_unregister_subdev(sd);
1513 kfree(to_state(sd));
1514 return 0;
1515}
1516
1517
1518
1519static const struct i2c_device_id saa717x_id[] = {
1520 { "saa717x", 0 },
1521 { }
1522};
1523MODULE_DEVICE_TABLE(i2c, saa717x_id);
1524
1525static struct v4l2_i2c_driver_data v4l2_i2c_data = {
1526 .name = "saa717x",
1527 .probe = saa717x_probe,
1528 .remove = saa717x_remove,
1529 .id_table = saa717x_id,
1530};
1531