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