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