blob: 2220f9569941e04a767d1692546500294bc0cf7e [file] [log] [blame]
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001/*
2 * saa717x - Philips SAA717xHL video decoder driver
3 *
4 * Based on the saa7115 driver
5 *
6 * Changes by Ohta Kyuma <alpha292@bremen.or.jp>
7 * - Apply to SAA717x,NEC uPD64031,uPD64083. (1/31/2004)
8 *
9 * Changes by T.Adachi (tadachi@tadachi-net.com)
10 * - support audio, video scaler etc, and checked the initialize sequence.
11 *
12 * Cleaned up by Hans Verkuil <hverkuil@xs4all.nl>
13 *
14 * Note: this is a reversed engineered driver based on captures from
15 * the I2C bus under Windows. This chip is very similar to the saa7134,
16 * though. Unfortunately, this driver is currently only working for NTSC.
17 *
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
22 *
23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
27 *
28 * You should have received a copy of the GNU General Public License
29 * along with this program; if not, write to the Free Software
30 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
31 */
32
33#include <linux/version.h>
34#include <linux/module.h>
35#include <linux/kernel.h>
36#include <linux/sched.h>
37
38#include <linux/videodev.h>
39#include <linux/videodev2.h>
40#include <linux/i2c.h>
41#include <media/v4l2-common.h>
42#include <media/v4l2-i2c-drv.h>
43
44MODULE_DESCRIPTION("Philips SAA717x audio/video decoder driver");
45MODULE_AUTHOR("K. Ohta, T. Adachi, Hans Verkuil");
46MODULE_LICENSE("GPL");
47
48static int debug;
49module_param(debug, int, 0644);
50MODULE_PARM_DESC(debug, "Debug level (0-1)");
51
52/*
53 * Generic i2c probe
54 * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
55 */
56
57struct saa717x_state {
58 v4l2_std_id std;
59 int input;
60 int enable;
61 int radio;
62 int bright;
63 int contrast;
64 int hue;
65 int sat;
66 int playback;
67 int audio;
68 int tuner_audio_mode;
69 int audio_main_mute;
70 int audio_main_vol_r;
71 int audio_main_vol_l;
72 u16 audio_main_bass;
73 u16 audio_main_treble;
74 u16 audio_main_volume;
75 u16 audio_main_balance;
76 int audio_input;
77};
78
79/* ----------------------------------------------------------------------- */
80
81/* for audio mode */
82#define TUNER_AUDIO_MONO 0 /* LL */
83#define TUNER_AUDIO_STEREO 1 /* LR */
84#define TUNER_AUDIO_LANG1 2 /* LL */
85#define TUNER_AUDIO_LANG2 3 /* RR */
86
87#define SAA717X_NTSC_WIDTH (704)
88#define SAA717X_NTSC_HEIGHT (480)
89
90/* ----------------------------------------------------------------------- */
91
92static int saa717x_write(struct i2c_client *client, u32 reg, u32 value)
93{
94 struct i2c_adapter *adap = client->adapter;
95 int fw_addr = reg == 0x454 || (reg >= 0x464 && reg <= 0x478) || reg == 0x480 || reg == 0x488;
96 unsigned char mm1[6];
97 struct i2c_msg msg;
98
99 msg.flags = 0;
100 msg.addr = client->addr;
101 mm1[0] = (reg >> 8) & 0xff;
102 mm1[1] = reg & 0xff;
103
104 if (fw_addr) {
105 mm1[4] = (value >> 16) & 0xff;
106 mm1[3] = (value >> 8) & 0xff;
107 mm1[2] = value & 0xff;
108 } else {
109 mm1[2] = value & 0xff;
110 }
111 msg.len = fw_addr ? 5 : 3; /* Long Registers have *only* three bytes! */
112 msg.buf = mm1;
113 v4l_dbg(2, debug, client, "wrote: reg 0x%03x=%08x\n", reg, value);
114 return i2c_transfer(adap, &msg, 1) == 1;
115}
116
117static void saa717x_write_regs(struct i2c_client *client, u32 *data)
118{
119 while (data[0] || data[1]) {
120 saa717x_write(client, data[0], data[1]);
121 data += 2;
122 }
123}
124
125static u32 saa717x_read(struct i2c_client *client, u32 reg)
126{
127 struct i2c_adapter *adap = client->adapter;
128 int fw_addr = (reg >= 0x404 && reg <= 0x4b8) || reg == 0x528;
129 unsigned char mm1[2];
130 unsigned char mm2[4] = { 0, 0, 0, 0 };
131 struct i2c_msg msgs[2];
132 u32 value;
133
134 msgs[0].flags = 0;
135 msgs[1].flags = I2C_M_RD;
136 msgs[0].addr = msgs[1].addr = client->addr;
137 mm1[0] = (reg >> 8) & 0xff;
138 mm1[1] = reg & 0xff;
139 msgs[0].len = 2;
140 msgs[0].buf = mm1;
141 msgs[1].len = fw_addr ? 3 : 1; /* Multibyte Registers contains *only* 3 bytes */
142 msgs[1].buf = mm2;
143 i2c_transfer(adap, msgs, 2);
144
145 if (fw_addr)
146 value = (mm2[2] & 0xff) | ((mm2[1] & 0xff) >> 8) | ((mm2[0] & 0xff) >> 16);
147 else
148 value = mm2[0] & 0xff;
149
150 v4l_dbg(2, debug, client, "read: reg 0x%03x=0x%08x\n", reg, value);
151 return value;
152}
153
154/* ----------------------------------------------------------------------- */
155
156static u32 reg_init_initialize[] =
157{
158 /* from linux driver */
159 0x101, 0x008, /* Increment delay */
160
161 0x103, 0x000, /* Analog input control 2 */
162 0x104, 0x090, /* Analog input control 3 */
163 0x105, 0x090, /* Analog input control 4 */
164 0x106, 0x0eb, /* Horizontal sync start */
165 0x107, 0x0e0, /* Horizontal sync stop */
166 0x109, 0x055, /* Luminance control */
167
168 0x10f, 0x02a, /* Chroma gain control */
169 0x110, 0x000, /* Chroma control 2 */
170
171 0x114, 0x045, /* analog/ADC */
172
173 0x118, 0x040, /* RAW data gain */
174 0x119, 0x080, /* RAW data offset */
175
176 0x044, 0x000, /* VBI horizontal input window start (L) TASK A */
177 0x045, 0x000, /* VBI horizontal input window start (H) TASK A */
178 0x046, 0x0cf, /* VBI horizontal input window stop (L) TASK A */
179 0x047, 0x002, /* VBI horizontal input window stop (H) TASK A */
180
181 0x049, 0x000, /* VBI vertical input window start (H) TASK A */
182
183 0x04c, 0x0d0, /* VBI horizontal output length (L) TASK A */
184 0x04d, 0x002, /* VBI horizontal output length (H) TASK A */
185
186 0x064, 0x080, /* Lumina brightness TASK A */
187 0x065, 0x040, /* Luminance contrast TASK A */
188 0x066, 0x040, /* Chroma saturation TASK A */
189 /* 067H: Reserved */
190 0x068, 0x000, /* VBI horizontal scaling increment (L) TASK A */
191 0x069, 0x004, /* VBI horizontal scaling increment (H) TASK A */
192 0x06a, 0x000, /* VBI phase offset TASK A */
193
194 0x06e, 0x000, /* Horizontal phase offset Luma TASK A */
195 0x06f, 0x000, /* Horizontal phase offset Chroma TASK A */
196
197 0x072, 0x000, /* Vertical filter mode TASK A */
198
199 0x084, 0x000, /* VBI horizontal input window start (L) TAKS B */
200 0x085, 0x000, /* VBI horizontal input window start (H) TAKS B */
201 0x086, 0x0cf, /* VBI horizontal input window stop (L) TAKS B */
202 0x087, 0x002, /* VBI horizontal input window stop (H) TAKS B */
203
204 0x089, 0x000, /* VBI vertical input window start (H) TAKS B */
205
206 0x08c, 0x0d0, /* VBI horizontal output length (L) TASK B */
207 0x08d, 0x002, /* VBI horizontal output length (H) TASK B */
208
209 0x0a4, 0x080, /* Lumina brightness TASK B */
210 0x0a5, 0x040, /* Luminance contrast TASK B */
211 0x0a6, 0x040, /* Chroma saturation TASK B */
212 /* 0A7H reserved */
213 0x0a8, 0x000, /* VBI horizontal scaling increment (L) TASK B */
214 0x0a9, 0x004, /* VBI horizontal scaling increment (H) TASK B */
215 0x0aa, 0x000, /* VBI phase offset TASK B */
216
217 0x0ae, 0x000, /* Horizontal phase offset Luma TASK B */
218 0x0af, 0x000, /*Horizontal phase offset Chroma TASK B */
219
220 0x0b2, 0x000, /* Vertical filter mode TASK B */
221
222 0x00c, 0x000, /* Start point GREEN path */
223 0x00d, 0x000, /* Start point BLUE path */
224 0x00e, 0x000, /* Start point RED path */
225
226 0x010, 0x010, /* GREEN path gamma curve --- */
227 0x011, 0x020,
228 0x012, 0x030,
229 0x013, 0x040,
230 0x014, 0x050,
231 0x015, 0x060,
232 0x016, 0x070,
233 0x017, 0x080,
234 0x018, 0x090,
235 0x019, 0x0a0,
236 0x01a, 0x0b0,
237 0x01b, 0x0c0,
238 0x01c, 0x0d0,
239 0x01d, 0x0e0,
240 0x01e, 0x0f0,
241 0x01f, 0x0ff, /* --- GREEN path gamma curve */
242
243 0x020, 0x010, /* BLUE path gamma curve --- */
244 0x021, 0x020,
245 0x022, 0x030,
246 0x023, 0x040,
247 0x024, 0x050,
248 0x025, 0x060,
249 0x026, 0x070,
250 0x027, 0x080,
251 0x028, 0x090,
252 0x029, 0x0a0,
253 0x02a, 0x0b0,
254 0x02b, 0x0c0,
255 0x02c, 0x0d0,
256 0x02d, 0x0e0,
257 0x02e, 0x0f0,
258 0x02f, 0x0ff, /* --- BLUE path gamma curve */
259
260 0x030, 0x010, /* RED path gamma curve --- */
261 0x031, 0x020,
262 0x032, 0x030,
263 0x033, 0x040,
264 0x034, 0x050,
265 0x035, 0x060,
266 0x036, 0x070,
267 0x037, 0x080,
268 0x038, 0x090,
269 0x039, 0x0a0,
270 0x03a, 0x0b0,
271 0x03b, 0x0c0,
272 0x03c, 0x0d0,
273 0x03d, 0x0e0,
274 0x03e, 0x0f0,
275 0x03f, 0x0ff, /* --- RED path gamma curve */
276
277 0x109, 0x085, /* Luminance control */
278
279 /**** from app start ****/
280 0x584, 0x000, /* AGC gain control */
281 0x585, 0x000, /* Program count */
282 0x586, 0x003, /* Status reset */
283 0x588, 0x0ff, /* Number of audio samples (L) */
284 0x589, 0x00f, /* Number of audio samples (M) */
285 0x58a, 0x000, /* Number of audio samples (H) */
286 0x58b, 0x000, /* Audio select */
287 0x58c, 0x010, /* Audio channel assign1 */
288 0x58d, 0x032, /* Audio channel assign2 */
289 0x58e, 0x054, /* Audio channel assign3 */
290 0x58f, 0x023, /* Audio format */
291 0x590, 0x000, /* SIF control */
292
293 0x595, 0x000, /* ?? */
294 0x596, 0x000, /* ?? */
295 0x597, 0x000, /* ?? */
296
297 0x464, 0x00, /* Digital input crossbar1 */
298
299 0x46c, 0xbbbb10, /* Digital output selection1-3 */
300 0x470, 0x101010, /* Digital output selection4-6 */
301
302 0x478, 0x00, /* Sound feature control */
303
304 0x474, 0x18, /* Softmute control */
305
306 0x454, 0x0425b9, /* Sound Easy programming(reset) */
307 0x454, 0x042539, /* Sound Easy programming(reset) */
308
309
310 /**** common setting( of DVD play, including scaler commands) ****/
311 0x042, 0x003, /* Data path configuration for VBI (TASK A) */
312
313 0x082, 0x003, /* Data path configuration for VBI (TASK B) */
314
315 0x108, 0x0f8, /* Sync control */
316 0x2a9, 0x0fd, /* ??? */
317 0x102, 0x089, /* select video input "mode 9" */
318 0x111, 0x000, /* Mode/delay control */
319
320 0x10e, 0x00a, /* Chroma control 1 */
321
322 0x594, 0x002, /* SIF, analog I/O select */
323
324 0x454, 0x0425b9, /* Sound */
325 0x454, 0x042539,
326
327 0x111, 0x000,
328 0x10e, 0x00a,
329 0x464, 0x000,
330 0x300, 0x000,
331 0x301, 0x006,
332 0x302, 0x000,
333 0x303, 0x006,
334 0x308, 0x040,
335 0x309, 0x000,
336 0x30a, 0x000,
337 0x30b, 0x000,
338 0x000, 0x002,
339 0x001, 0x000,
340 0x002, 0x000,
341 0x003, 0x000,
342 0x004, 0x033,
343 0x040, 0x01d,
344 0x041, 0x001,
345 0x042, 0x004,
346 0x043, 0x000,
347 0x080, 0x01e,
348 0x081, 0x001,
349 0x082, 0x004,
350 0x083, 0x000,
351 0x190, 0x018,
352 0x115, 0x000,
353 0x116, 0x012,
354 0x117, 0x018,
355 0x04a, 0x011,
356 0x08a, 0x011,
357 0x04b, 0x000,
358 0x08b, 0x000,
359 0x048, 0x000,
360 0x088, 0x000,
361 0x04e, 0x012,
362 0x08e, 0x012,
363 0x058, 0x012,
364 0x098, 0x012,
365 0x059, 0x000,
366 0x099, 0x000,
367 0x05a, 0x003,
368 0x09a, 0x003,
369 0x05b, 0x001,
370 0x09b, 0x001,
371 0x054, 0x008,
372 0x094, 0x008,
373 0x055, 0x000,
374 0x095, 0x000,
375 0x056, 0x0c7,
376 0x096, 0x0c7,
377 0x057, 0x002,
378 0x097, 0x002,
379 0x0ff, 0x0ff,
380 0x060, 0x001,
381 0x0a0, 0x001,
382 0x061, 0x000,
383 0x0a1, 0x000,
384 0x062, 0x000,
385 0x0a2, 0x000,
386 0x063, 0x000,
387 0x0a3, 0x000,
388 0x070, 0x000,
389 0x0b0, 0x000,
390 0x071, 0x004,
391 0x0b1, 0x004,
392 0x06c, 0x0e9,
393 0x0ac, 0x0e9,
394 0x06d, 0x003,
395 0x0ad, 0x003,
396 0x05c, 0x0d0,
397 0x09c, 0x0d0,
398 0x05d, 0x002,
399 0x09d, 0x002,
400 0x05e, 0x0f2,
401 0x09e, 0x0f2,
402 0x05f, 0x000,
403 0x09f, 0x000,
404 0x074, 0x000,
405 0x0b4, 0x000,
406 0x075, 0x000,
407 0x0b5, 0x000,
408 0x076, 0x000,
409 0x0b6, 0x000,
410 0x077, 0x000,
411 0x0b7, 0x000,
412 0x195, 0x008,
413 0x0ff, 0x0ff,
414 0x108, 0x0f8,
415 0x111, 0x000,
416 0x10e, 0x00a,
417 0x2a9, 0x0fd,
418 0x464, 0x001,
419 0x454, 0x042135,
420 0x598, 0x0e7,
421 0x599, 0x07d,
422 0x59a, 0x018,
423 0x59c, 0x066,
424 0x59d, 0x090,
425 0x59e, 0x001,
426 0x584, 0x000,
427 0x585, 0x000,
428 0x586, 0x003,
429 0x588, 0x0ff,
430 0x589, 0x00f,
431 0x58a, 0x000,
432 0x58b, 0x000,
433 0x58c, 0x010,
434 0x58d, 0x032,
435 0x58e, 0x054,
436 0x58f, 0x023,
437 0x590, 0x000,
438 0x595, 0x000,
439 0x596, 0x000,
440 0x597, 0x000,
441 0x464, 0x000,
442 0x46c, 0xbbbb10,
443 0x470, 0x101010,
444
445
446 0x478, 0x000,
447 0x474, 0x018,
448 0x454, 0x042135,
449 0x598, 0x0e7,
450 0x599, 0x07d,
451 0x59a, 0x018,
452 0x59c, 0x066,
453 0x59d, 0x090,
454 0x59e, 0x001,
455 0x584, 0x000,
456 0x585, 0x000,
457 0x586, 0x003,
458 0x588, 0x0ff,
459 0x589, 0x00f,
460 0x58a, 0x000,
461 0x58b, 0x000,
462 0x58c, 0x010,
463 0x58d, 0x032,
464 0x58e, 0x054,
465 0x58f, 0x023,
466 0x590, 0x000,
467 0x595, 0x000,
468 0x596, 0x000,
469 0x597, 0x000,
470 0x464, 0x000,
471 0x46c, 0xbbbb10,
472 0x470, 0x101010,
473
474 0x478, 0x000,
475 0x474, 0x018,
476 0x454, 0x042135,
477 0x598, 0x0e7,
478 0x599, 0x07d,
479 0x59a, 0x018,
480 0x59c, 0x066,
481 0x59d, 0x090,
482 0x59e, 0x001,
483 0x584, 0x000,
484 0x585, 0x000,
485 0x586, 0x003,
486 0x588, 0x0ff,
487 0x589, 0x00f,
488 0x58a, 0x000,
489 0x58b, 0x000,
490 0x58c, 0x010,
491 0x58d, 0x032,
492 0x58e, 0x054,
493 0x58f, 0x023,
494 0x590, 0x000,
495 0x595, 0x000,
496 0x596, 0x000,
497 0x597, 0x000,
498 0x464, 0x000,
499 0x46c, 0xbbbb10,
500 0x470, 0x101010,
501 0x478, 0x000,
502 0x474, 0x018,
503 0x454, 0x042135,
504 0x193, 0x000,
505 0x300, 0x000,
506 0x301, 0x006,
507 0x302, 0x000,
508 0x303, 0x006,
509 0x308, 0x040,
510 0x309, 0x000,
511 0x30a, 0x000,
512 0x30b, 0x000,
513 0x000, 0x002,
514 0x001, 0x000,
515 0x002, 0x000,
516 0x003, 0x000,
517 0x004, 0x033,
518 0x040, 0x01d,
519 0x041, 0x001,
520 0x042, 0x004,
521 0x043, 0x000,
522 0x080, 0x01e,
523 0x081, 0x001,
524 0x082, 0x004,
525 0x083, 0x000,
526 0x190, 0x018,
527 0x115, 0x000,
528 0x116, 0x012,
529 0x117, 0x018,
530 0x04a, 0x011,
531 0x08a, 0x011,
532 0x04b, 0x000,
533 0x08b, 0x000,
534 0x048, 0x000,
535 0x088, 0x000,
536 0x04e, 0x012,
537 0x08e, 0x012,
538 0x058, 0x012,
539 0x098, 0x012,
540 0x059, 0x000,
541 0x099, 0x000,
542 0x05a, 0x003,
543 0x09a, 0x003,
544 0x05b, 0x001,
545 0x09b, 0x001,
546 0x054, 0x008,
547 0x094, 0x008,
548 0x055, 0x000,
549 0x095, 0x000,
550 0x056, 0x0c7,
551 0x096, 0x0c7,
552 0x057, 0x002,
553 0x097, 0x002,
554 0x060, 0x001,
555 0x0a0, 0x001,
556 0x061, 0x000,
557 0x0a1, 0x000,
558 0x062, 0x000,
559 0x0a2, 0x000,
560 0x063, 0x000,
561 0x0a3, 0x000,
562 0x070, 0x000,
563 0x0b0, 0x000,
564 0x071, 0x004,
565 0x0b1, 0x004,
566 0x06c, 0x0e9,
567 0x0ac, 0x0e9,
568 0x06d, 0x003,
569 0x0ad, 0x003,
570 0x05c, 0x0d0,
571 0x09c, 0x0d0,
572 0x05d, 0x002,
573 0x09d, 0x002,
574 0x05e, 0x0f2,
575 0x09e, 0x0f2,
576 0x05f, 0x000,
577 0x09f, 0x000,
578 0x074, 0x000,
579 0x0b4, 0x000,
580 0x075, 0x000,
581 0x0b5, 0x000,
582 0x076, 0x000,
583 0x0b6, 0x000,
584 0x077, 0x000,
585 0x0b7, 0x000,
586 0x195, 0x008,
587 0x598, 0x0e7,
588 0x599, 0x07d,
589 0x59a, 0x018,
590 0x59c, 0x066,
591 0x59d, 0x090,
592 0x59e, 0x001,
593 0x584, 0x000,
594 0x585, 0x000,
595 0x586, 0x003,
596 0x588, 0x0ff,
597 0x589, 0x00f,
598 0x58a, 0x000,
599 0x58b, 0x000,
600 0x58c, 0x010,
601 0x58d, 0x032,
602 0x58e, 0x054,
603 0x58f, 0x023,
604 0x590, 0x000,
605 0x595, 0x000,
606 0x596, 0x000,
607 0x597, 0x000,
608 0x464, 0x000,
609 0x46c, 0xbbbb10,
610 0x470, 0x101010,
611 0x478, 0x000,
612 0x474, 0x018,
613 0x454, 0x042135,
614 0x193, 0x0a6,
615 0x108, 0x0f8,
616 0x042, 0x003,
617 0x082, 0x003,
618 0x454, 0x0425b9,
619 0x454, 0x042539,
620 0x193, 0x000,
621 0x193, 0x0a6,
622 0x464, 0x000,
623
624 0, 0
625};
626
627/* Tuner */
628static u32 reg_init_tuner_input[] = {
629 0x108, 0x0f8, /* Sync control */
630 0x111, 0x000, /* Mode/delay control */
631 0x10e, 0x00a, /* Chroma control 1 */
632 0, 0
633};
634
635/* Composite */
636static u32 reg_init_composite_input[] = {
637 0x108, 0x0e8, /* Sync control */
638 0x111, 0x000, /* Mode/delay control */
639 0x10e, 0x04a, /* Chroma control 1 */
640 0, 0
641};
642
643/* S-Video */
644static u32 reg_init_svideo_input[] = {
645 0x108, 0x0e8, /* Sync control */
646 0x111, 0x000, /* Mode/delay control */
647 0x10e, 0x04a, /* Chroma control 1 */
648 0, 0
649};
650
651static u32 reg_set_audio_template[4][2] =
652{
653 { /* for MONO
654 tadachi 6/29 DMA audio output select?
655 Register 0x46c
656 7-4: DMA2, 3-0: DMA1 ch. DMA4, DMA3 DMA2, DMA1
657 0: MAIN left, 1: MAIN right
658 2: AUX1 left, 3: AUX1 right
659 4: AUX2 left, 5: AUX2 right
660 6: DPL left, 7: DPL right
661 8: DPL center, 9: DPL surround
662 A: monitor output, B: digital sense */
663 0xbbbb00,
664
665 /* tadachi 6/29 DAC and I2S output select?
666 Register 0x470
667 7-4:DAC right ch. 3-0:DAC left ch.
668 I2S1 right,left I2S2 right,left */
669 0x00,
670 },
671 { /* for STEREO */
672 0xbbbb10, 0x101010,
673 },
674 { /* for LANG1 */
675 0xbbbb00, 0x00,
676 },
677 { /* for LANG2/SAP */
678 0xbbbb11, 0x111111,
679 }
680};
681
682
683/* Get detected audio flags (from saa7134 driver) */
684static void get_inf_dev_status(struct i2c_client *client,
685 int *dual_flag, int *stereo_flag)
686{
687 u32 reg_data3;
688
689 static char *stdres[0x20] = {
690 [0x00] = "no standard detected",
691 [0x01] = "B/G (in progress)",
692 [0x02] = "D/K (in progress)",
693 [0x03] = "M (in progress)",
694
695 [0x04] = "B/G A2",
696 [0x05] = "B/G NICAM",
697 [0x06] = "D/K A2 (1)",
698 [0x07] = "D/K A2 (2)",
699 [0x08] = "D/K A2 (3)",
700 [0x09] = "D/K NICAM",
701 [0x0a] = "L NICAM",
702 [0x0b] = "I NICAM",
703
704 [0x0c] = "M Korea",
705 [0x0d] = "M BTSC ",
706 [0x0e] = "M EIAJ",
707
708 [0x0f] = "FM radio / IF 10.7 / 50 deemp",
709 [0x10] = "FM radio / IF 10.7 / 75 deemp",
710 [0x11] = "FM radio / IF sel / 50 deemp",
711 [0x12] = "FM radio / IF sel / 75 deemp",
712
713 [0x13 ... 0x1e] = "unknown",
714 [0x1f] = "??? [in progress]",
715 };
716
717
718 *dual_flag = *stereo_flag = 0;
719
720 /* (demdec status: 0x528) */
721
722 /* read current status */
723 reg_data3 = saa717x_read(client, 0x0528);
724
725 v4l_dbg(1, debug, client, "tvaudio thread status: 0x%x [%s%s%s]\n",
726 reg_data3, stdres[reg_data3 & 0x1f],
727 (reg_data3 & 0x000020) ? ",stereo" : "",
728 (reg_data3 & 0x000040) ? ",dual" : "");
729 v4l_dbg(1, debug, client, "detailed status: "
730 "%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s\n",
731 (reg_data3 & 0x000080) ? " A2/EIAJ pilot tone " : "",
732 (reg_data3 & 0x000100) ? " A2/EIAJ dual " : "",
733 (reg_data3 & 0x000200) ? " A2/EIAJ stereo " : "",
734 (reg_data3 & 0x000400) ? " A2/EIAJ noise mute " : "",
735
736 (reg_data3 & 0x000800) ? " BTSC/FM radio pilot " : "",
737 (reg_data3 & 0x001000) ? " SAP carrier " : "",
738 (reg_data3 & 0x002000) ? " BTSC stereo noise mute " : "",
739 (reg_data3 & 0x004000) ? " SAP noise mute " : "",
740 (reg_data3 & 0x008000) ? " VDSP " : "",
741
742 (reg_data3 & 0x010000) ? " NICST " : "",
743 (reg_data3 & 0x020000) ? " NICDU " : "",
744 (reg_data3 & 0x040000) ? " NICAM muted " : "",
745 (reg_data3 & 0x080000) ? " NICAM reserve sound " : "",
746
747 (reg_data3 & 0x100000) ? " init done " : "");
748
749 if (reg_data3 & 0x000220) {
750 v4l_dbg(1, debug, client, "ST!!!\n");
751 *stereo_flag = 1;
752 }
753
754 if (reg_data3 & 0x000140) {
755 v4l_dbg(1, debug, client, "DUAL!!!\n");
756 *dual_flag = 1;
757 }
758}
759
760/* regs write to set audio mode */
761static void set_audio_mode(struct i2c_client *client, int audio_mode)
762{
763 v4l_dbg(1, debug, client, "writing registers to set audio mode by set %d\n",
764 audio_mode);
765
766 saa717x_write(client, 0x46c, reg_set_audio_template[audio_mode][0]);
767 saa717x_write(client, 0x470, reg_set_audio_template[audio_mode][1]);
768}
769
770/* write regs to video output level (bright,contrast,hue,sat) */
771static void set_video_output_level_regs(struct i2c_client *client,
772 struct saa717x_state *decoder)
773{
774 /* brightness ffh (bright) - 80h (ITU level) - 00h (dark) */
775 saa717x_write(client, 0x10a, decoder->bright);
776
777 /* contrast 7fh (max: 1.984) - 44h (ITU) - 40h (1.0) -
778 0h (luminance off) 40: i2c dump
779 c0h (-1.0 inverse chrominance)
780 80h (-2.0 inverse chrominance) */
781 saa717x_write(client, 0x10b, decoder->contrast);
782
783 /* saturation? 7fh(max)-40h(ITU)-0h(color off)
784 c0h (-1.0 inverse chrominance)
785 80h (-2.0 inverse chrominance) */
786 saa717x_write(client, 0x10c, decoder->sat);
787
788 /* color hue (phase) control
789 7fh (+178.6) - 0h (0 normal) - 80h (-180.0) */
790 saa717x_write(client, 0x10d, decoder->hue);
791}
792
793/* write regs to set audio volume, bass and treble */
794static int set_audio_regs(struct i2c_client *client,
795 struct saa717x_state *decoder)
796{
797 u8 mute = 0xac; /* -84 dB */
798 u32 val;
799 unsigned int work_l, work_r;
800
801 /* set SIF analog I/O select */
802 saa717x_write(client, 0x0594, decoder->audio_input);
803 v4l_dbg(1, debug, client, "set audio input %d\n",
804 decoder->audio_input);
805
806 /* normalize ( 65535 to 0 -> 24 to -40 (not -84)) */
807 work_l = (min(65536 - decoder->audio_main_balance, 32768) * decoder->audio_main_volume) / 32768;
808 work_r = (min(decoder->audio_main_balance, (u16)32768) * decoder->audio_main_volume) / 32768;
809 decoder->audio_main_vol_l = (long)work_l * (24 - (-40)) / 65535 - 40;
810 decoder->audio_main_vol_r = (long)work_r * (24 - (-40)) / 65535 - 40;
811
812 /* set main volume */
813 /* main volume L[7-0],R[7-0],0x00 24=24dB,-83dB, -84(mute) */
814 /* def:0dB->6dB(MPG600GR) */
815 /* if mute is on, set mute */
816 if (decoder->audio_main_mute) {
817 val = mute | (mute << 8);
818 } else {
819 val = (u8)decoder->audio_main_vol_l |
820 ((u8)decoder->audio_main_vol_r << 8);
821 }
822
823 saa717x_write(client, 0x480, val);
824
825 /* bass and treble; go to another function */
826 /* set bass and treble */
827 val = decoder->audio_main_bass | (decoder->audio_main_treble << 8);
828 saa717x_write(client, 0x488, val);
829 return 0;
830}
831
832/********** scaling staff ***********/
833static void set_h_prescale(struct i2c_client *client,
834 int task, int prescale)
835{
836 static const struct {
837 int xpsc;
838 int xacl;
839 int xc2_1;
840 int xdcg;
841 int vpfy;
842 } vals[] = {
843 /* XPSC XACL XC2_1 XDCG VPFY */
844 { 1, 0, 0, 0, 0 },
845 { 2, 2, 1, 2, 2 },
846 { 3, 4, 1, 3, 2 },
847 { 4, 8, 1, 4, 2 },
848 { 5, 8, 1, 4, 2 },
849 { 6, 8, 1, 4, 3 },
850 { 7, 8, 1, 4, 3 },
851 { 8, 15, 0, 4, 3 },
852 { 9, 15, 0, 4, 3 },
853 { 10, 16, 1, 5, 3 },
854 };
855 static const int count = ARRAY_SIZE(vals);
856 int i, task_shift;
857
858 task_shift = task * 0x40;
859 for (i = 0; i < count; i++)
860 if (vals[i].xpsc == prescale)
861 break;
862 if (i == count)
863 return;
864
865 /* horizonal prescaling */
866 saa717x_write(client, 0x60 + task_shift, vals[i].xpsc);
867 /* accumulation length */
868 saa717x_write(client, 0x61 + task_shift, vals[i].xacl);
869 /* level control */
870 saa717x_write(client, 0x62 + task_shift,
871 (vals[i].xc2_1 << 3) | vals[i].xdcg);
872 /*FIR prefilter control */
873 saa717x_write(client, 0x63 + task_shift,
874 (vals[i].vpfy << 2) | vals[i].vpfy);
875}
876
877/********** scaling staff ***********/
878static void set_v_scale(struct i2c_client *client, int task, int yscale)
879{
880 int task_shift;
881
882 task_shift = task * 0x40;
883 /* Vertical scaling ratio (LOW) */
884 saa717x_write(client, 0x70 + task_shift, yscale & 0xff);
885 /* Vertical scaling ratio (HI) */
886 saa717x_write(client, 0x71 + task_shift, yscale >> 8);
887}
888
889static int saa717x_set_audio_clock_freq(struct i2c_client *client, u32 freq)
890{
891 /* not yet implament, so saa717x_cfg_??hz_??_audio is not defined. */
892 return 0;
893}
894
895static int saa717x_set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
896{
897 struct saa717x_state *state = i2c_get_clientdata(client);
898
899 switch (ctrl->id) {
900 case V4L2_CID_BRIGHTNESS:
901 if (ctrl->value < 0 || ctrl->value > 255) {
902 v4l_err(client, "invalid brightness setting %d\n", ctrl->value);
903 return -ERANGE;
904 }
905
906 state->bright = ctrl->value;
907 v4l_dbg(1, debug, client, "bright:%d\n", state->bright);
908 saa717x_write(client, 0x10a, state->bright);
909 break;
910
911 case V4L2_CID_CONTRAST:
912 if (ctrl->value < 0 || ctrl->value > 127) {
913 v4l_err(client, "invalid contrast setting %d\n", ctrl->value);
914 return -ERANGE;
915 }
916
917 state->contrast = ctrl->value;
918 v4l_dbg(1, debug, client, "contrast:%d\n", state->contrast);
919 saa717x_write(client, 0x10b, state->contrast);
920 break;
921
922 case V4L2_CID_SATURATION:
923 if (ctrl->value < 0 || ctrl->value > 127) {
924 v4l_err(client, "invalid saturation setting %d\n", ctrl->value);
925 return -ERANGE;
926 }
927
928 state->sat = ctrl->value;
929 v4l_dbg(1, debug, client, "sat:%d\n", state->sat);
930 saa717x_write(client, 0x10c, state->sat);
931 break;
932
933 case V4L2_CID_HUE:
934 if (ctrl->value < -127 || ctrl->value > 127) {
935 v4l_err(client, "invalid hue setting %d\n", ctrl->value);
936 return -ERANGE;
937 }
938
939 state->hue = ctrl->value;
940 v4l_dbg(1, debug, client, "hue:%d\n", state->hue);
941 saa717x_write(client, 0x10d, state->hue);
942 break;
943
944 case V4L2_CID_AUDIO_MUTE:
945 state->audio_main_mute = ctrl->value;
946 set_audio_regs(client, state);
947 break;
948
949 case V4L2_CID_AUDIO_VOLUME:
950 state->audio_main_volume = ctrl->value;
951 set_audio_regs(client, state);
952 break;
953
954 case V4L2_CID_AUDIO_BALANCE:
955 state->audio_main_balance = ctrl->value;
956 set_audio_regs(client, state);
957 break;
958
959 case V4L2_CID_AUDIO_TREBLE:
960 state->audio_main_treble = ctrl->value;
961 set_audio_regs(client, state);
962 break;
963
964 case V4L2_CID_AUDIO_BASS:
965 state->audio_main_bass = ctrl->value;
966 set_audio_regs(client, state);
967 break;
968
969 default:
970 return -EINVAL;
971 }
972
973 return 0;
974}
975
976static int saa717x_get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
977{
978 struct saa717x_state *state = i2c_get_clientdata(client);
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_set_video_input(struct i2c_client *client, struct saa717x_state *decoder, int inp)
1108{
1109 int is_tuner = inp & 0x80; /* tuner input flag */
1110
1111 inp &= 0x7f;
1112
1113 v4l_dbg(1, debug, client, "decoder set input (%d)\n", inp);
1114 /* inputs from 0-9 are available*/
1115 /* saa717x have mode0-mode9 but mode5 is reserved. */
1116 if (inp < 0 || inp > 9 || inp == 5)
1117 return -EINVAL;
1118
1119 if (decoder->input != inp) {
1120 int input_line = inp;
1121
1122 decoder->input = input_line;
1123 v4l_dbg(1, debug, client, "now setting %s input %d\n",
1124 input_line >= 6 ? "S-Video" : "Composite",
1125 input_line);
1126
1127 /* select mode */
1128 saa717x_write(client, 0x102,
1129 (saa717x_read(client, 0x102) & 0xf0) |
1130 input_line);
1131
1132 /* bypass chrominance trap for modes 6..9 */
1133 saa717x_write(client, 0x109,
1134 (saa717x_read(client, 0x109) & 0x7f) |
1135 (input_line < 6 ? 0x0 : 0x80));
1136
1137 /* change audio_mode */
1138 if (is_tuner) {
1139 /* tuner */
1140 set_audio_mode(client, decoder->tuner_audio_mode);
1141 } else {
1142 /* Force to STEREO mode if Composite or
1143 * S-Video were chosen */
1144 set_audio_mode(client, TUNER_AUDIO_STEREO);
1145 }
1146 /* change initialize procedure (Composite/S-Video) */
1147 if (is_tuner)
1148 saa717x_write_regs(client, reg_init_tuner_input);
1149 else if (input_line >= 6)
1150 saa717x_write_regs(client, reg_init_svideo_input);
1151 else
1152 saa717x_write_regs(client, reg_init_composite_input);
1153 }
1154
1155 return 0;
1156}
1157
1158static int saa717x_command(struct i2c_client *client, unsigned cmd, void *arg)
1159{
1160 struct saa717x_state *decoder = i2c_get_clientdata(client);
1161
1162 v4l_dbg(1, debug, client, "IOCTL: %08x\n", cmd);
1163
1164 switch (cmd) {
1165 case VIDIOC_INT_AUDIO_CLOCK_FREQ:
1166 return saa717x_set_audio_clock_freq(client, *(u32 *)arg);
1167
1168 case VIDIOC_G_CTRL:
1169 return saa717x_get_v4lctrl(client, (struct v4l2_control *)arg);
1170
1171 case VIDIOC_S_CTRL:
1172 return saa717x_set_v4lctrl(client, (struct v4l2_control *)arg);
1173
1174 case VIDIOC_QUERYCTRL: {
1175 struct v4l2_queryctrl *qc = arg;
1176 int i;
1177
1178 for (i = 0; i < ARRAY_SIZE(saa717x_qctrl); i++)
1179 if (qc->id && qc->id == saa717x_qctrl[i].id) {
1180 memcpy(qc, &saa717x_qctrl[i], sizeof(*qc));
1181 return 0;
1182 }
1183 return -EINVAL;
1184 }
1185
1186#ifdef CONFIG_VIDEO_ADV_DEBUG
1187 case VIDIOC_DBG_G_REGISTER: {
1188 struct v4l2_register *reg = arg;
1189
1190 if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip))
1191 return -EINVAL;
1192 if (!capable(CAP_SYS_ADMIN))
1193 return -EPERM;
1194 reg->val = saa717x_read(client, reg->reg);
1195 break;
1196 }
1197
1198 case VIDIOC_DBG_S_REGISTER: {
1199 struct v4l2_register *reg = arg;
1200 u16 addr = reg->reg & 0xffff;
1201 u8 val = reg->val & 0xff;
1202
1203 if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip))
1204 return -EINVAL;
1205 if (!capable(CAP_SYS_ADMIN))
1206 return -EPERM;
1207 saa717x_write(client, addr, val);
1208 break;
1209 }
1210#endif
1211
1212 case VIDIOC_S_FMT: {
1213 struct v4l2_format *fmt = (struct v4l2_format *)arg;
1214 struct v4l2_pix_format *pix;
1215 int prescale, h_scale, v_scale;
1216
1217 pix = &fmt->fmt.pix;
1218 v4l_dbg(1, debug, client, "decoder set size\n");
1219
1220 /* FIXME need better bounds checking here */
1221 if (pix->width < 1 || pix->width > 1440)
1222 return -EINVAL;
1223 if (pix->height < 1 || pix->height > 960)
1224 return -EINVAL;
1225
1226 /* scaling setting */
1227 /* NTSC and interlace only */
1228 prescale = SAA717X_NTSC_WIDTH / pix->width;
1229 if (prescale == 0)
1230 prescale = 1;
1231 h_scale = 1024 * SAA717X_NTSC_WIDTH / prescale / pix->width;
1232 /* interlace */
1233 v_scale = 512 * 2 * SAA717X_NTSC_HEIGHT / pix->height;
1234
1235 /* Horizontal prescaling etc */
1236 set_h_prescale(client, 0, prescale);
1237 set_h_prescale(client, 1, prescale);
1238
1239 /* Horizontal scaling increment */
1240 /* TASK A */
1241 saa717x_write(client, 0x6C, (u8)(h_scale & 0xFF));
1242 saa717x_write(client, 0x6D, (u8)((h_scale >> 8) & 0xFF));
1243 /* TASK B */
1244 saa717x_write(client, 0xAC, (u8)(h_scale & 0xFF));
1245 saa717x_write(client, 0xAD, (u8)((h_scale >> 8) & 0xFF));
1246
1247 /* Vertical prescaling etc */
1248 set_v_scale(client, 0, v_scale);
1249 set_v_scale(client, 1, v_scale);
1250
1251 /* set video output size */
1252 /* video number of pixels at output */
1253 /* TASK A */
1254 saa717x_write(client, 0x5C, (u8)(pix->width & 0xFF));
1255 saa717x_write(client, 0x5D, (u8)((pix->width >> 8) & 0xFF));
1256 /* TASK B */
1257 saa717x_write(client, 0x9C, (u8)(pix->width & 0xFF));
1258 saa717x_write(client, 0x9D, (u8)((pix->width >> 8) & 0xFF));
1259
1260 /* video number of lines at output */
1261 /* TASK A */
1262 saa717x_write(client, 0x5E, (u8)(pix->height & 0xFF));
1263 saa717x_write(client, 0x5F, (u8)((pix->height >> 8) & 0xFF));
1264 /* TASK B */
1265 saa717x_write(client, 0x9E, (u8)(pix->height & 0xFF));
1266 saa717x_write(client, 0x9F, (u8)((pix->height >> 8) & 0xFF));
1267 break;
1268 }
1269
1270 case AUDC_SET_RADIO:
1271 decoder->radio = 1;
1272 break;
1273
1274 case VIDIOC_S_STD: {
1275 v4l2_std_id std = *(v4l2_std_id *) arg;
1276
1277 v4l_dbg(1, debug, client, "decoder set norm ");
1278 v4l_dbg(1, debug, client, "(not yet implementd)\n");
1279
1280 decoder->radio = 0;
1281 decoder->std = std;
1282 break;
1283 }
1284
1285 case VIDIOC_INT_G_AUDIO_ROUTING: {
1286 struct v4l2_routing *route = arg;
1287
1288 route->input = decoder->audio_input;
1289 route->output = 0;
1290 break;
1291 }
1292
1293 case VIDIOC_INT_S_AUDIO_ROUTING: {
1294 struct v4l2_routing *route = arg;
1295
1296 if (route->input < 3) { /* FIXME! --tadachi */
1297 decoder->audio_input = route->input;
1298 v4l_dbg(1, debug, client,
1299 "set decoder audio input to %d\n",
1300 decoder->audio_input);
1301 set_audio_regs(client, decoder);
1302 break;
1303 }
1304 return -ERANGE;
1305 }
1306
1307 case VIDIOC_INT_S_VIDEO_ROUTING: {
1308 struct v4l2_routing *route = arg;
1309 int inp = route->input;
1310
1311 return saa717x_set_video_input(client, decoder, inp);
1312 }
1313
1314 case VIDIOC_STREAMON: {
1315 v4l_dbg(1, debug, client, "decoder enable output\n");
1316 decoder->enable = 1;
1317 saa717x_write(client, 0x193, 0xa6);
1318 break;
1319 }
1320
1321 case VIDIOC_STREAMOFF: {
1322 v4l_dbg(1, debug, client, "decoder disable output\n");
1323 decoder->enable = 0;
1324 saa717x_write(client, 0x193, 0x26); /* right? FIXME!--tadachi */
1325 break;
1326 }
1327
1328 /* change audio mode */
1329 case VIDIOC_S_TUNER: {
1330 struct v4l2_tuner *vt = (struct v4l2_tuner *)arg;
1331 int audio_mode;
1332 char *mes[4] = {
1333 "MONO", "STEREO", "LANG1", "LANG2/SAP"
1334 };
1335
1336 audio_mode = V4L2_TUNER_MODE_STEREO;
1337
1338 switch (vt->audmode) {
1339 case V4L2_TUNER_MODE_MONO:
1340 audio_mode = TUNER_AUDIO_MONO;
1341 break;
1342 case V4L2_TUNER_MODE_STEREO:
1343 audio_mode = TUNER_AUDIO_STEREO;
1344 break;
1345 case V4L2_TUNER_MODE_LANG2:
1346 audio_mode = TUNER_AUDIO_LANG2;
1347 break;
1348 case V4L2_TUNER_MODE_LANG1:
1349 audio_mode = TUNER_AUDIO_LANG1;
1350 break;
1351 }
1352
1353 v4l_dbg(1, debug, client, "change audio mode to %s\n",
1354 mes[audio_mode]);
1355 decoder->tuner_audio_mode = audio_mode;
1356 /* The registers are not changed here. */
1357 /* See DECODER_ENABLE_OUTPUT section. */
1358 set_audio_mode(client, decoder->tuner_audio_mode);
1359 break;
1360 }
1361
1362 case VIDIOC_G_TUNER: {
1363 struct v4l2_tuner *vt = (struct v4l2_tuner *)arg;
1364 int dual_f, stereo_f;
1365
1366 if (decoder->radio)
1367 break;
1368 get_inf_dev_status(client, &dual_f, &stereo_f);
1369
1370 v4l_dbg(1, debug, client, "DETECT==st:%d dual:%d\n",
1371 stereo_f, dual_f);
1372
1373 /* mono */
1374 if ((dual_f == 0) && (stereo_f == 0)) {
1375 vt->rxsubchans = V4L2_TUNER_SUB_MONO;
1376 v4l_dbg(1, debug, client, "DETECT==MONO\n");
1377 }
1378
1379 /* stereo */
1380 if (stereo_f == 1) {
1381 if (vt->audmode == V4L2_TUNER_MODE_STEREO ||
1382 vt->audmode == V4L2_TUNER_MODE_LANG1) {
1383 vt->rxsubchans = V4L2_TUNER_SUB_STEREO;
1384 v4l_dbg(1, debug, client, "DETECT==ST(ST)\n");
1385 } else {
1386 vt->rxsubchans = V4L2_TUNER_SUB_MONO;
1387 v4l_dbg(1, debug, client, "DETECT==ST(MONO)\n");
1388 }
1389 }
1390
1391 /* dual */
1392 if (dual_f == 1) {
1393 if (vt->audmode == V4L2_TUNER_MODE_LANG2) {
1394 vt->rxsubchans = V4L2_TUNER_SUB_LANG2 | V4L2_TUNER_SUB_MONO;
1395 v4l_dbg(1, debug, client, "DETECT==DUAL1\n");
1396 } else {
1397 vt->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_MONO;
1398 v4l_dbg(1, debug, client, "DETECT==DUAL2\n");
1399 }
1400 }
1401 break;
1402 }
1403
1404 case VIDIOC_LOG_STATUS:
1405 /* not yet implemented */
1406 break;
1407
1408 default:
1409 return -EINVAL;
1410 }
1411
1412 return 0;
1413}
1414
1415/* ----------------------------------------------------------------------- */
1416
1417
1418/* i2c implementation */
1419
1420/* ----------------------------------------------------------------------- */
Jean Delvared2653e92008-04-29 23:11:39 +02001421static int saa717x_probe(struct i2c_client *client,
1422 const struct i2c_device_id *did)
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001423{
1424 struct saa717x_state *decoder;
1425 u8 id = 0;
1426 char *p = "";
1427
1428 /* Check if the adapter supports the needed features */
1429 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
1430 return -EIO;
1431
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001432 if (saa717x_write(client, 0x5a4, 0xfe) &&
1433 saa717x_write(client, 0x5a5, 0x0f) &&
1434 saa717x_write(client, 0x5a6, 0x00) &&
1435 saa717x_write(client, 0x5a7, 0x01))
1436 id = saa717x_read(client, 0x5a0);
1437 if (id != 0xc2 && id != 0x32 && id != 0xf2 && id != 0x6c) {
1438 v4l_dbg(1, debug, client, "saa717x not found (id=%02x)\n", id);
1439 return -ENODEV;
1440 }
1441 if (id == 0xc2)
1442 p = "saa7173";
1443 else if (id == 0x32)
1444 p = "saa7174A";
1445 else if (id == 0x6c)
1446 p = "saa7174HL";
1447 else
1448 p = "saa7171";
1449 v4l_info(client, "%s found @ 0x%x (%s)\n", p,
1450 client->addr << 1, client->adapter->name);
1451
1452 decoder = kzalloc(sizeof(struct saa717x_state), GFP_KERNEL);
1453 i2c_set_clientdata(client, decoder);
1454
1455 if (decoder == NULL)
1456 return -ENOMEM;
1457 decoder->std = V4L2_STD_NTSC;
1458 decoder->input = -1;
1459 decoder->enable = 1;
1460
1461 /* tune these parameters */
1462 decoder->bright = 0x80;
1463 decoder->contrast = 0x44;
1464 decoder->sat = 0x40;
1465 decoder->hue = 0x00;
1466
1467 /* FIXME!! */
1468 decoder->playback = 0; /* initially capture mode used */
1469 decoder->audio = 1; /* DECODER_AUDIO_48_KHZ */
1470
1471 decoder->audio_input = 2; /* FIXME!! */
1472
1473 decoder->tuner_audio_mode = TUNER_AUDIO_STEREO;
1474 /* set volume, bass and treble */
1475 decoder->audio_main_vol_l = 6;
1476 decoder->audio_main_vol_r = 6;
1477 decoder->audio_main_bass = 0;
1478 decoder->audio_main_treble = 0;
1479 decoder->audio_main_mute = 0;
1480 decoder->audio_main_balance = 32768;
1481 /* normalize (24 to -40 (not -84) -> 65535 to 0) */
1482 decoder->audio_main_volume =
1483 (decoder->audio_main_vol_r + 41) * 65535 / (24 - (-40));
1484
1485 v4l_dbg(1, debug, client, "writing init values\n");
1486
1487 /* FIXME!! */
1488 saa717x_write_regs(client, reg_init_initialize);
1489 set_video_output_level_regs(client, decoder);
1490 /* set bass,treble to 0db 20041101 K.Ohta */
1491 decoder->audio_main_bass = 0;
1492 decoder->audio_main_treble = 0;
1493 set_audio_regs(client, decoder);
1494
1495 set_current_state(TASK_INTERRUPTIBLE);
1496 schedule_timeout(2*HZ);
1497 return 0;
1498}
1499
1500static int saa717x_remove(struct i2c_client *client)
1501{
1502 kfree(i2c_get_clientdata(client));
1503 return 0;
1504}
1505
1506/* ----------------------------------------------------------------------- */
1507
Jean Delvareaf294862008-05-18 20:49:40 +02001508static const struct i2c_device_id saa717x_id[] = {
1509 { "saa717x", 0 },
1510 { }
1511};
1512MODULE_DEVICE_TABLE(i2c, saa717x_id);
1513
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001514static struct v4l2_i2c_driver_data v4l2_i2c_data = {
1515 .name = "saa717x",
1516 .driverid = I2C_DRIVERID_SAA717X,
1517 .command = saa717x_command,
1518 .probe = saa717x_probe,
1519 .remove = saa717x_remove,
1520 .legacy_class = I2C_CLASS_TV_ANALOG | I2C_CLASS_TV_DIGITAL,
Jean Delvareaf294862008-05-18 20:49:40 +02001521 .id_table = saa717x_id,
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001522};