V4L/DVB (10085): sh_mobile_ceu: add NV16 and NV61 support
[linux-2.6/verdex.git] / drivers / media / video / saa717x.c
blob9befca65905e0e6dee10882f240fac2d361b1b99
1 /*
2 * saa717x - Philips SAA717xHL video decoder driver
4 * Based on the saa7115 driver
6 * Changes by Ohta Kyuma <alpha292@bremen.or.jp>
7 * - Apply to SAA717x,NEC uPD64031,uPD64083. (1/31/2004)
9 * Changes by T.Adachi (tadachi@tadachi-net.com)
10 * - support audio, video scaler etc, and checked the initialize sequence.
12 * Cleaned up by Hans Verkuil <hverkuil@xs4all.nl>
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.
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.
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.
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.
33 #include <linux/version.h>
34 #include <linux/module.h>
35 #include <linux/kernel.h>
36 #include <linux/sched.h>
38 #include <linux/videodev2.h>
39 #include <linux/i2c.h>
40 #include <media/v4l2-device.h>
41 #include <media/v4l2-i2c-drv.h>
43 MODULE_DESCRIPTION("Philips SAA717x audio/video decoder driver");
44 MODULE_AUTHOR("K. Ohta, T. Adachi, Hans Verkuil");
45 MODULE_LICENSE("GPL");
47 static int debug;
48 module_param(debug, int, 0644);
49 MODULE_PARM_DESC(debug, "Debug level (0-1)");
52 * Generic i2c probe
53 * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
56 struct saa717x_state {
57 struct v4l2_subdev sd;
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;
79 static inline struct saa717x_state *to_state(struct v4l2_subdev *sd)
81 return container_of(sd, struct saa717x_state, sd);
84 /* ----------------------------------------------------------------------- */
86 /* for audio mode */
87 #define TUNER_AUDIO_MONO 0 /* LL */
88 #define TUNER_AUDIO_STEREO 1 /* LR */
89 #define TUNER_AUDIO_LANG1 2 /* LL */
90 #define TUNER_AUDIO_LANG2 3 /* RR */
92 #define SAA717X_NTSC_WIDTH (704)
93 #define SAA717X_NTSC_HEIGHT (480)
95 /* ----------------------------------------------------------------------- */
97 static int saa717x_write(struct v4l2_subdev *sd, u32 reg, u32 value)
99 struct i2c_client *client = v4l2_get_subdevdata(sd);
100 struct i2c_adapter *adap = client->adapter;
101 int fw_addr = reg == 0x454 || (reg >= 0x464 && reg <= 0x478) || reg == 0x480 || reg == 0x488;
102 unsigned char mm1[6];
103 struct i2c_msg msg;
105 msg.flags = 0;
106 msg.addr = client->addr;
107 mm1[0] = (reg >> 8) & 0xff;
108 mm1[1] = reg & 0xff;
110 if (fw_addr) {
111 mm1[4] = (value >> 16) & 0xff;
112 mm1[3] = (value >> 8) & 0xff;
113 mm1[2] = value & 0xff;
114 } else {
115 mm1[2] = value & 0xff;
117 msg.len = fw_addr ? 5 : 3; /* Long Registers have *only* three bytes! */
118 msg.buf = mm1;
119 v4l2_dbg(2, debug, sd, "wrote: reg 0x%03x=%08x\n", reg, value);
120 return i2c_transfer(adap, &msg, 1) == 1;
123 static void saa717x_write_regs(struct v4l2_subdev *sd, u32 *data)
125 while (data[0] || data[1]) {
126 saa717x_write(sd, data[0], data[1]);
127 data += 2;
131 static u32 saa717x_read(struct v4l2_subdev *sd, u32 reg)
133 struct i2c_client *client = v4l2_get_subdevdata(sd);
134 struct i2c_adapter *adap = client->adapter;
135 int fw_addr = (reg >= 0x404 && reg <= 0x4b8) || reg == 0x528;
136 unsigned char mm1[2];
137 unsigned char mm2[4] = { 0, 0, 0, 0 };
138 struct i2c_msg msgs[2];
139 u32 value;
141 msgs[0].flags = 0;
142 msgs[1].flags = I2C_M_RD;
143 msgs[0].addr = msgs[1].addr = client->addr;
144 mm1[0] = (reg >> 8) & 0xff;
145 mm1[1] = reg & 0xff;
146 msgs[0].len = 2;
147 msgs[0].buf = mm1;
148 msgs[1].len = fw_addr ? 3 : 1; /* Multibyte Registers contains *only* 3 bytes */
149 msgs[1].buf = mm2;
150 i2c_transfer(adap, msgs, 2);
152 if (fw_addr)
153 value = (mm2[2] & 0xff) | ((mm2[1] & 0xff) >> 8) | ((mm2[0] & 0xff) >> 16);
154 else
155 value = mm2[0] & 0xff;
157 v4l2_dbg(2, debug, sd, "read: reg 0x%03x=0x%08x\n", reg, value);
158 return value;
161 /* ----------------------------------------------------------------------- */
163 static u32 reg_init_initialize[] =
165 /* from linux driver */
166 0x101, 0x008, /* Increment delay */
168 0x103, 0x000, /* Analog input control 2 */
169 0x104, 0x090, /* Analog input control 3 */
170 0x105, 0x090, /* Analog input control 4 */
171 0x106, 0x0eb, /* Horizontal sync start */
172 0x107, 0x0e0, /* Horizontal sync stop */
173 0x109, 0x055, /* Luminance control */
175 0x10f, 0x02a, /* Chroma gain control */
176 0x110, 0x000, /* Chroma control 2 */
178 0x114, 0x045, /* analog/ADC */
180 0x118, 0x040, /* RAW data gain */
181 0x119, 0x080, /* RAW data offset */
183 0x044, 0x000, /* VBI horizontal input window start (L) TASK A */
184 0x045, 0x000, /* VBI horizontal input window start (H) TASK A */
185 0x046, 0x0cf, /* VBI horizontal input window stop (L) TASK A */
186 0x047, 0x002, /* VBI horizontal input window stop (H) TASK A */
188 0x049, 0x000, /* VBI vertical input window start (H) TASK A */
190 0x04c, 0x0d0, /* VBI horizontal output length (L) TASK A */
191 0x04d, 0x002, /* VBI horizontal output length (H) TASK A */
193 0x064, 0x080, /* Lumina brightness TASK A */
194 0x065, 0x040, /* Luminance contrast TASK A */
195 0x066, 0x040, /* Chroma saturation TASK A */
196 /* 067H: Reserved */
197 0x068, 0x000, /* VBI horizontal scaling increment (L) TASK A */
198 0x069, 0x004, /* VBI horizontal scaling increment (H) TASK A */
199 0x06a, 0x000, /* VBI phase offset TASK A */
201 0x06e, 0x000, /* Horizontal phase offset Luma TASK A */
202 0x06f, 0x000, /* Horizontal phase offset Chroma TASK A */
204 0x072, 0x000, /* Vertical filter mode TASK A */
206 0x084, 0x000, /* VBI horizontal input window start (L) TAKS B */
207 0x085, 0x000, /* VBI horizontal input window start (H) TAKS B */
208 0x086, 0x0cf, /* VBI horizontal input window stop (L) TAKS B */
209 0x087, 0x002, /* VBI horizontal input window stop (H) TAKS B */
211 0x089, 0x000, /* VBI vertical input window start (H) TAKS B */
213 0x08c, 0x0d0, /* VBI horizontal output length (L) TASK B */
214 0x08d, 0x002, /* VBI horizontal output length (H) TASK B */
216 0x0a4, 0x080, /* Lumina brightness TASK B */
217 0x0a5, 0x040, /* Luminance contrast TASK B */
218 0x0a6, 0x040, /* Chroma saturation TASK B */
219 /* 0A7H reserved */
220 0x0a8, 0x000, /* VBI horizontal scaling increment (L) TASK B */
221 0x0a9, 0x004, /* VBI horizontal scaling increment (H) TASK B */
222 0x0aa, 0x000, /* VBI phase offset TASK B */
224 0x0ae, 0x000, /* Horizontal phase offset Luma TASK B */
225 0x0af, 0x000, /*Horizontal phase offset Chroma TASK B */
227 0x0b2, 0x000, /* Vertical filter mode TASK B */
229 0x00c, 0x000, /* Start point GREEN path */
230 0x00d, 0x000, /* Start point BLUE path */
231 0x00e, 0x000, /* Start point RED path */
233 0x010, 0x010, /* GREEN path gamma curve --- */
234 0x011, 0x020,
235 0x012, 0x030,
236 0x013, 0x040,
237 0x014, 0x050,
238 0x015, 0x060,
239 0x016, 0x070,
240 0x017, 0x080,
241 0x018, 0x090,
242 0x019, 0x0a0,
243 0x01a, 0x0b0,
244 0x01b, 0x0c0,
245 0x01c, 0x0d0,
246 0x01d, 0x0e0,
247 0x01e, 0x0f0,
248 0x01f, 0x0ff, /* --- GREEN path gamma curve */
250 0x020, 0x010, /* BLUE path gamma curve --- */
251 0x021, 0x020,
252 0x022, 0x030,
253 0x023, 0x040,
254 0x024, 0x050,
255 0x025, 0x060,
256 0x026, 0x070,
257 0x027, 0x080,
258 0x028, 0x090,
259 0x029, 0x0a0,
260 0x02a, 0x0b0,
261 0x02b, 0x0c0,
262 0x02c, 0x0d0,
263 0x02d, 0x0e0,
264 0x02e, 0x0f0,
265 0x02f, 0x0ff, /* --- BLUE path gamma curve */
267 0x030, 0x010, /* RED path gamma curve --- */
268 0x031, 0x020,
269 0x032, 0x030,
270 0x033, 0x040,
271 0x034, 0x050,
272 0x035, 0x060,
273 0x036, 0x070,
274 0x037, 0x080,
275 0x038, 0x090,
276 0x039, 0x0a0,
277 0x03a, 0x0b0,
278 0x03b, 0x0c0,
279 0x03c, 0x0d0,
280 0x03d, 0x0e0,
281 0x03e, 0x0f0,
282 0x03f, 0x0ff, /* --- RED path gamma curve */
284 0x109, 0x085, /* Luminance control */
286 /**** from app start ****/
287 0x584, 0x000, /* AGC gain control */
288 0x585, 0x000, /* Program count */
289 0x586, 0x003, /* Status reset */
290 0x588, 0x0ff, /* Number of audio samples (L) */
291 0x589, 0x00f, /* Number of audio samples (M) */
292 0x58a, 0x000, /* Number of audio samples (H) */
293 0x58b, 0x000, /* Audio select */
294 0x58c, 0x010, /* Audio channel assign1 */
295 0x58d, 0x032, /* Audio channel assign2 */
296 0x58e, 0x054, /* Audio channel assign3 */
297 0x58f, 0x023, /* Audio format */
298 0x590, 0x000, /* SIF control */
300 0x595, 0x000, /* ?? */
301 0x596, 0x000, /* ?? */
302 0x597, 0x000, /* ?? */
304 0x464, 0x00, /* Digital input crossbar1 */
306 0x46c, 0xbbbb10, /* Digital output selection1-3 */
307 0x470, 0x101010, /* Digital output selection4-6 */
309 0x478, 0x00, /* Sound feature control */
311 0x474, 0x18, /* Softmute control */
313 0x454, 0x0425b9, /* Sound Easy programming(reset) */
314 0x454, 0x042539, /* Sound Easy programming(reset) */
317 /**** common setting( of DVD play, including scaler commands) ****/
318 0x042, 0x003, /* Data path configuration for VBI (TASK A) */
320 0x082, 0x003, /* Data path configuration for VBI (TASK B) */
322 0x108, 0x0f8, /* Sync control */
323 0x2a9, 0x0fd, /* ??? */
324 0x102, 0x089, /* select video input "mode 9" */
325 0x111, 0x000, /* Mode/delay control */
327 0x10e, 0x00a, /* Chroma control 1 */
329 0x594, 0x002, /* SIF, analog I/O select */
331 0x454, 0x0425b9, /* Sound */
332 0x454, 0x042539,
334 0x111, 0x000,
335 0x10e, 0x00a,
336 0x464, 0x000,
337 0x300, 0x000,
338 0x301, 0x006,
339 0x302, 0x000,
340 0x303, 0x006,
341 0x308, 0x040,
342 0x309, 0x000,
343 0x30a, 0x000,
344 0x30b, 0x000,
345 0x000, 0x002,
346 0x001, 0x000,
347 0x002, 0x000,
348 0x003, 0x000,
349 0x004, 0x033,
350 0x040, 0x01d,
351 0x041, 0x001,
352 0x042, 0x004,
353 0x043, 0x000,
354 0x080, 0x01e,
355 0x081, 0x001,
356 0x082, 0x004,
357 0x083, 0x000,
358 0x190, 0x018,
359 0x115, 0x000,
360 0x116, 0x012,
361 0x117, 0x018,
362 0x04a, 0x011,
363 0x08a, 0x011,
364 0x04b, 0x000,
365 0x08b, 0x000,
366 0x048, 0x000,
367 0x088, 0x000,
368 0x04e, 0x012,
369 0x08e, 0x012,
370 0x058, 0x012,
371 0x098, 0x012,
372 0x059, 0x000,
373 0x099, 0x000,
374 0x05a, 0x003,
375 0x09a, 0x003,
376 0x05b, 0x001,
377 0x09b, 0x001,
378 0x054, 0x008,
379 0x094, 0x008,
380 0x055, 0x000,
381 0x095, 0x000,
382 0x056, 0x0c7,
383 0x096, 0x0c7,
384 0x057, 0x002,
385 0x097, 0x002,
386 0x0ff, 0x0ff,
387 0x060, 0x001,
388 0x0a0, 0x001,
389 0x061, 0x000,
390 0x0a1, 0x000,
391 0x062, 0x000,
392 0x0a2, 0x000,
393 0x063, 0x000,
394 0x0a3, 0x000,
395 0x070, 0x000,
396 0x0b0, 0x000,
397 0x071, 0x004,
398 0x0b1, 0x004,
399 0x06c, 0x0e9,
400 0x0ac, 0x0e9,
401 0x06d, 0x003,
402 0x0ad, 0x003,
403 0x05c, 0x0d0,
404 0x09c, 0x0d0,
405 0x05d, 0x002,
406 0x09d, 0x002,
407 0x05e, 0x0f2,
408 0x09e, 0x0f2,
409 0x05f, 0x000,
410 0x09f, 0x000,
411 0x074, 0x000,
412 0x0b4, 0x000,
413 0x075, 0x000,
414 0x0b5, 0x000,
415 0x076, 0x000,
416 0x0b6, 0x000,
417 0x077, 0x000,
418 0x0b7, 0x000,
419 0x195, 0x008,
420 0x0ff, 0x0ff,
421 0x108, 0x0f8,
422 0x111, 0x000,
423 0x10e, 0x00a,
424 0x2a9, 0x0fd,
425 0x464, 0x001,
426 0x454, 0x042135,
427 0x598, 0x0e7,
428 0x599, 0x07d,
429 0x59a, 0x018,
430 0x59c, 0x066,
431 0x59d, 0x090,
432 0x59e, 0x001,
433 0x584, 0x000,
434 0x585, 0x000,
435 0x586, 0x003,
436 0x588, 0x0ff,
437 0x589, 0x00f,
438 0x58a, 0x000,
439 0x58b, 0x000,
440 0x58c, 0x010,
441 0x58d, 0x032,
442 0x58e, 0x054,
443 0x58f, 0x023,
444 0x590, 0x000,
445 0x595, 0x000,
446 0x596, 0x000,
447 0x597, 0x000,
448 0x464, 0x000,
449 0x46c, 0xbbbb10,
450 0x470, 0x101010,
453 0x478, 0x000,
454 0x474, 0x018,
455 0x454, 0x042135,
456 0x598, 0x0e7,
457 0x599, 0x07d,
458 0x59a, 0x018,
459 0x59c, 0x066,
460 0x59d, 0x090,
461 0x59e, 0x001,
462 0x584, 0x000,
463 0x585, 0x000,
464 0x586, 0x003,
465 0x588, 0x0ff,
466 0x589, 0x00f,
467 0x58a, 0x000,
468 0x58b, 0x000,
469 0x58c, 0x010,
470 0x58d, 0x032,
471 0x58e, 0x054,
472 0x58f, 0x023,
473 0x590, 0x000,
474 0x595, 0x000,
475 0x596, 0x000,
476 0x597, 0x000,
477 0x464, 0x000,
478 0x46c, 0xbbbb10,
479 0x470, 0x101010,
481 0x478, 0x000,
482 0x474, 0x018,
483 0x454, 0x042135,
484 0x598, 0x0e7,
485 0x599, 0x07d,
486 0x59a, 0x018,
487 0x59c, 0x066,
488 0x59d, 0x090,
489 0x59e, 0x001,
490 0x584, 0x000,
491 0x585, 0x000,
492 0x586, 0x003,
493 0x588, 0x0ff,
494 0x589, 0x00f,
495 0x58a, 0x000,
496 0x58b, 0x000,
497 0x58c, 0x010,
498 0x58d, 0x032,
499 0x58e, 0x054,
500 0x58f, 0x023,
501 0x590, 0x000,
502 0x595, 0x000,
503 0x596, 0x000,
504 0x597, 0x000,
505 0x464, 0x000,
506 0x46c, 0xbbbb10,
507 0x470, 0x101010,
508 0x478, 0x000,
509 0x474, 0x018,
510 0x454, 0x042135,
511 0x193, 0x000,
512 0x300, 0x000,
513 0x301, 0x006,
514 0x302, 0x000,
515 0x303, 0x006,
516 0x308, 0x040,
517 0x309, 0x000,
518 0x30a, 0x000,
519 0x30b, 0x000,
520 0x000, 0x002,
521 0x001, 0x000,
522 0x002, 0x000,
523 0x003, 0x000,
524 0x004, 0x033,
525 0x040, 0x01d,
526 0x041, 0x001,
527 0x042, 0x004,
528 0x043, 0x000,
529 0x080, 0x01e,
530 0x081, 0x001,
531 0x082, 0x004,
532 0x083, 0x000,
533 0x190, 0x018,
534 0x115, 0x000,
535 0x116, 0x012,
536 0x117, 0x018,
537 0x04a, 0x011,
538 0x08a, 0x011,
539 0x04b, 0x000,
540 0x08b, 0x000,
541 0x048, 0x000,
542 0x088, 0x000,
543 0x04e, 0x012,
544 0x08e, 0x012,
545 0x058, 0x012,
546 0x098, 0x012,
547 0x059, 0x000,
548 0x099, 0x000,
549 0x05a, 0x003,
550 0x09a, 0x003,
551 0x05b, 0x001,
552 0x09b, 0x001,
553 0x054, 0x008,
554 0x094, 0x008,
555 0x055, 0x000,
556 0x095, 0x000,
557 0x056, 0x0c7,
558 0x096, 0x0c7,
559 0x057, 0x002,
560 0x097, 0x002,
561 0x060, 0x001,
562 0x0a0, 0x001,
563 0x061, 0x000,
564 0x0a1, 0x000,
565 0x062, 0x000,
566 0x0a2, 0x000,
567 0x063, 0x000,
568 0x0a3, 0x000,
569 0x070, 0x000,
570 0x0b0, 0x000,
571 0x071, 0x004,
572 0x0b1, 0x004,
573 0x06c, 0x0e9,
574 0x0ac, 0x0e9,
575 0x06d, 0x003,
576 0x0ad, 0x003,
577 0x05c, 0x0d0,
578 0x09c, 0x0d0,
579 0x05d, 0x002,
580 0x09d, 0x002,
581 0x05e, 0x0f2,
582 0x09e, 0x0f2,
583 0x05f, 0x000,
584 0x09f, 0x000,
585 0x074, 0x000,
586 0x0b4, 0x000,
587 0x075, 0x000,
588 0x0b5, 0x000,
589 0x076, 0x000,
590 0x0b6, 0x000,
591 0x077, 0x000,
592 0x0b7, 0x000,
593 0x195, 0x008,
594 0x598, 0x0e7,
595 0x599, 0x07d,
596 0x59a, 0x018,
597 0x59c, 0x066,
598 0x59d, 0x090,
599 0x59e, 0x001,
600 0x584, 0x000,
601 0x585, 0x000,
602 0x586, 0x003,
603 0x588, 0x0ff,
604 0x589, 0x00f,
605 0x58a, 0x000,
606 0x58b, 0x000,
607 0x58c, 0x010,
608 0x58d, 0x032,
609 0x58e, 0x054,
610 0x58f, 0x023,
611 0x590, 0x000,
612 0x595, 0x000,
613 0x596, 0x000,
614 0x597, 0x000,
615 0x464, 0x000,
616 0x46c, 0xbbbb10,
617 0x470, 0x101010,
618 0x478, 0x000,
619 0x474, 0x018,
620 0x454, 0x042135,
621 0x193, 0x0a6,
622 0x108, 0x0f8,
623 0x042, 0x003,
624 0x082, 0x003,
625 0x454, 0x0425b9,
626 0x454, 0x042539,
627 0x193, 0x000,
628 0x193, 0x0a6,
629 0x464, 0x000,
631 0, 0
634 /* Tuner */
635 static u32 reg_init_tuner_input[] = {
636 0x108, 0x0f8, /* Sync control */
637 0x111, 0x000, /* Mode/delay control */
638 0x10e, 0x00a, /* Chroma control 1 */
639 0, 0
642 /* Composite */
643 static u32 reg_init_composite_input[] = {
644 0x108, 0x0e8, /* Sync control */
645 0x111, 0x000, /* Mode/delay control */
646 0x10e, 0x04a, /* Chroma control 1 */
647 0, 0
650 /* S-Video */
651 static u32 reg_init_svideo_input[] = {
652 0x108, 0x0e8, /* Sync control */
653 0x111, 0x000, /* Mode/delay control */
654 0x10e, 0x04a, /* Chroma control 1 */
655 0, 0
658 static u32 reg_set_audio_template[4][2] =
660 { /* for MONO
661 tadachi 6/29 DMA audio output select?
662 Register 0x46c
663 7-4: DMA2, 3-0: DMA1 ch. DMA4, DMA3 DMA2, DMA1
664 0: MAIN left, 1: MAIN right
665 2: AUX1 left, 3: AUX1 right
666 4: AUX2 left, 5: AUX2 right
667 6: DPL left, 7: DPL right
668 8: DPL center, 9: DPL surround
669 A: monitor output, B: digital sense */
670 0xbbbb00,
672 /* tadachi 6/29 DAC and I2S output select?
673 Register 0x470
674 7-4:DAC right ch. 3-0:DAC left ch.
675 I2S1 right,left I2S2 right,left */
676 0x00,
678 { /* for STEREO */
679 0xbbbb10, 0x101010,
681 { /* for LANG1 */
682 0xbbbb00, 0x00,
684 { /* for LANG2/SAP */
685 0xbbbb11, 0x111111,
690 /* Get detected audio flags (from saa7134 driver) */
691 static void get_inf_dev_status(struct v4l2_subdev *sd,
692 int *dual_flag, int *stereo_flag)
694 u32 reg_data3;
696 static char *stdres[0x20] = {
697 [0x00] = "no standard detected",
698 [0x01] = "B/G (in progress)",
699 [0x02] = "D/K (in progress)",
700 [0x03] = "M (in progress)",
702 [0x04] = "B/G A2",
703 [0x05] = "B/G NICAM",
704 [0x06] = "D/K A2 (1)",
705 [0x07] = "D/K A2 (2)",
706 [0x08] = "D/K A2 (3)",
707 [0x09] = "D/K NICAM",
708 [0x0a] = "L NICAM",
709 [0x0b] = "I NICAM",
711 [0x0c] = "M Korea",
712 [0x0d] = "M BTSC ",
713 [0x0e] = "M EIAJ",
715 [0x0f] = "FM radio / IF 10.7 / 50 deemp",
716 [0x10] = "FM radio / IF 10.7 / 75 deemp",
717 [0x11] = "FM radio / IF sel / 50 deemp",
718 [0x12] = "FM radio / IF sel / 75 deemp",
720 [0x13 ... 0x1e] = "unknown",
721 [0x1f] = "??? [in progress]",
725 *dual_flag = *stereo_flag = 0;
727 /* (demdec status: 0x528) */
729 /* read current status */
730 reg_data3 = saa717x_read(sd, 0x0528);
732 v4l2_dbg(1, debug, sd, "tvaudio thread status: 0x%x [%s%s%s]\n",
733 reg_data3, stdres[reg_data3 & 0x1f],
734 (reg_data3 & 0x000020) ? ",stereo" : "",
735 (reg_data3 & 0x000040) ? ",dual" : "");
736 v4l2_dbg(1, debug, sd, "detailed status: "
737 "%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s\n",
738 (reg_data3 & 0x000080) ? " A2/EIAJ pilot tone " : "",
739 (reg_data3 & 0x000100) ? " A2/EIAJ dual " : "",
740 (reg_data3 & 0x000200) ? " A2/EIAJ stereo " : "",
741 (reg_data3 & 0x000400) ? " A2/EIAJ noise mute " : "",
743 (reg_data3 & 0x000800) ? " BTSC/FM radio pilot " : "",
744 (reg_data3 & 0x001000) ? " SAP carrier " : "",
745 (reg_data3 & 0x002000) ? " BTSC stereo noise mute " : "",
746 (reg_data3 & 0x004000) ? " SAP noise mute " : "",
747 (reg_data3 & 0x008000) ? " VDSP " : "",
749 (reg_data3 & 0x010000) ? " NICST " : "",
750 (reg_data3 & 0x020000) ? " NICDU " : "",
751 (reg_data3 & 0x040000) ? " NICAM muted " : "",
752 (reg_data3 & 0x080000) ? " NICAM reserve sound " : "",
754 (reg_data3 & 0x100000) ? " init done " : "");
756 if (reg_data3 & 0x000220) {
757 v4l2_dbg(1, debug, sd, "ST!!!\n");
758 *stereo_flag = 1;
761 if (reg_data3 & 0x000140) {
762 v4l2_dbg(1, debug, sd, "DUAL!!!\n");
763 *dual_flag = 1;
767 /* regs write to set audio mode */
768 static void set_audio_mode(struct v4l2_subdev *sd, int audio_mode)
770 v4l2_dbg(1, debug, sd, "writing registers to set audio mode by set %d\n",
771 audio_mode);
773 saa717x_write(sd, 0x46c, reg_set_audio_template[audio_mode][0]);
774 saa717x_write(sd, 0x470, reg_set_audio_template[audio_mode][1]);
777 /* write regs to video output level (bright,contrast,hue,sat) */
778 static void set_video_output_level_regs(struct v4l2_subdev *sd,
779 struct saa717x_state *decoder)
781 /* brightness ffh (bright) - 80h (ITU level) - 00h (dark) */
782 saa717x_write(sd, 0x10a, decoder->bright);
784 /* contrast 7fh (max: 1.984) - 44h (ITU) - 40h (1.0) -
785 0h (luminance off) 40: i2c dump
786 c0h (-1.0 inverse chrominance)
787 80h (-2.0 inverse chrominance) */
788 saa717x_write(sd, 0x10b, decoder->contrast);
790 /* saturation? 7fh(max)-40h(ITU)-0h(color off)
791 c0h (-1.0 inverse chrominance)
792 80h (-2.0 inverse chrominance) */
793 saa717x_write(sd, 0x10c, decoder->sat);
795 /* color hue (phase) control
796 7fh (+178.6) - 0h (0 normal) - 80h (-180.0) */
797 saa717x_write(sd, 0x10d, decoder->hue);
800 /* write regs to set audio volume, bass and treble */
801 static int set_audio_regs(struct v4l2_subdev *sd,
802 struct saa717x_state *decoder)
804 u8 mute = 0xac; /* -84 dB */
805 u32 val;
806 unsigned int work_l, work_r;
808 /* set SIF analog I/O select */
809 saa717x_write(sd, 0x0594, decoder->audio_input);
810 v4l2_dbg(1, debug, sd, "set audio input %d\n",
811 decoder->audio_input);
813 /* normalize ( 65535 to 0 -> 24 to -40 (not -84)) */
814 work_l = (min(65536 - decoder->audio_main_balance, 32768) * decoder->audio_main_volume) / 32768;
815 work_r = (min(decoder->audio_main_balance, (u16)32768) * decoder->audio_main_volume) / 32768;
816 decoder->audio_main_vol_l = (long)work_l * (24 - (-40)) / 65535 - 40;
817 decoder->audio_main_vol_r = (long)work_r * (24 - (-40)) / 65535 - 40;
819 /* set main volume */
820 /* main volume L[7-0],R[7-0],0x00 24=24dB,-83dB, -84(mute) */
821 /* def:0dB->6dB(MPG600GR) */
822 /* if mute is on, set mute */
823 if (decoder->audio_main_mute) {
824 val = mute | (mute << 8);
825 } else {
826 val = (u8)decoder->audio_main_vol_l |
827 ((u8)decoder->audio_main_vol_r << 8);
830 saa717x_write(sd, 0x480, val);
832 /* bass and treble; go to another function */
833 /* set bass and treble */
834 val = decoder->audio_main_bass | (decoder->audio_main_treble << 8);
835 saa717x_write(sd, 0x488, val);
836 return 0;
839 /********** scaling staff ***********/
840 static void set_h_prescale(struct v4l2_subdev *sd,
841 int task, int prescale)
843 static const struct {
844 int xpsc;
845 int xacl;
846 int xc2_1;
847 int xdcg;
848 int vpfy;
849 } vals[] = {
850 /* XPSC XACL XC2_1 XDCG VPFY */
851 { 1, 0, 0, 0, 0 },
852 { 2, 2, 1, 2, 2 },
853 { 3, 4, 1, 3, 2 },
854 { 4, 8, 1, 4, 2 },
855 { 5, 8, 1, 4, 2 },
856 { 6, 8, 1, 4, 3 },
857 { 7, 8, 1, 4, 3 },
858 { 8, 15, 0, 4, 3 },
859 { 9, 15, 0, 4, 3 },
860 { 10, 16, 1, 5, 3 },
862 static const int count = ARRAY_SIZE(vals);
863 int i, task_shift;
865 task_shift = task * 0x40;
866 for (i = 0; i < count; i++)
867 if (vals[i].xpsc == prescale)
868 break;
869 if (i == count)
870 return;
872 /* horizonal prescaling */
873 saa717x_write(sd, 0x60 + task_shift, vals[i].xpsc);
874 /* accumulation length */
875 saa717x_write(sd, 0x61 + task_shift, vals[i].xacl);
876 /* level control */
877 saa717x_write(sd, 0x62 + task_shift,
878 (vals[i].xc2_1 << 3) | vals[i].xdcg);
879 /*FIR prefilter control */
880 saa717x_write(sd, 0x63 + task_shift,
881 (vals[i].vpfy << 2) | vals[i].vpfy);
884 /********** scaling staff ***********/
885 static void set_v_scale(struct v4l2_subdev *sd, int task, int yscale)
887 int task_shift;
889 task_shift = task * 0x40;
890 /* Vertical scaling ratio (LOW) */
891 saa717x_write(sd, 0x70 + task_shift, yscale & 0xff);
892 /* Vertical scaling ratio (HI) */
893 saa717x_write(sd, 0x71 + task_shift, yscale >> 8);
896 static int saa717x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
898 struct saa717x_state *state = to_state(sd);
900 switch (ctrl->id) {
901 case V4L2_CID_BRIGHTNESS:
902 if (ctrl->value < 0 || ctrl->value > 255) {
903 v4l2_err(sd, "invalid brightness setting %d\n", ctrl->value);
904 return -ERANGE;
907 state->bright = ctrl->value;
908 v4l2_dbg(1, debug, sd, "bright:%d\n", state->bright);
909 saa717x_write(sd, 0x10a, state->bright);
910 break;
912 case V4L2_CID_CONTRAST:
913 if (ctrl->value < 0 || ctrl->value > 127) {
914 v4l2_err(sd, "invalid contrast setting %d\n", ctrl->value);
915 return -ERANGE;
918 state->contrast = ctrl->value;
919 v4l2_dbg(1, debug, sd, "contrast:%d\n", state->contrast);
920 saa717x_write(sd, 0x10b, state->contrast);
921 break;
923 case V4L2_CID_SATURATION:
924 if (ctrl->value < 0 || ctrl->value > 127) {
925 v4l2_err(sd, "invalid saturation setting %d\n", ctrl->value);
926 return -ERANGE;
929 state->sat = ctrl->value;
930 v4l2_dbg(1, debug, sd, "sat:%d\n", state->sat);
931 saa717x_write(sd, 0x10c, state->sat);
932 break;
934 case V4L2_CID_HUE:
935 if (ctrl->value < -127 || ctrl->value > 127) {
936 v4l2_err(sd, "invalid hue setting %d\n", ctrl->value);
937 return -ERANGE;
940 state->hue = ctrl->value;
941 v4l2_dbg(1, debug, sd, "hue:%d\n", state->hue);
942 saa717x_write(sd, 0x10d, state->hue);
943 break;
945 case V4L2_CID_AUDIO_MUTE:
946 state->audio_main_mute = ctrl->value;
947 set_audio_regs(sd, state);
948 break;
950 case V4L2_CID_AUDIO_VOLUME:
951 state->audio_main_volume = ctrl->value;
952 set_audio_regs(sd, state);
953 break;
955 case V4L2_CID_AUDIO_BALANCE:
956 state->audio_main_balance = ctrl->value;
957 set_audio_regs(sd, state);
958 break;
960 case V4L2_CID_AUDIO_TREBLE:
961 state->audio_main_treble = ctrl->value;
962 set_audio_regs(sd, state);
963 break;
965 case V4L2_CID_AUDIO_BASS:
966 state->audio_main_bass = ctrl->value;
967 set_audio_regs(sd, state);
968 break;
970 default:
971 return -EINVAL;
974 return 0;
977 static int saa717x_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
979 struct saa717x_state *state = to_state(sd);
981 switch (ctrl->id) {
982 case V4L2_CID_BRIGHTNESS:
983 ctrl->value = state->bright;
984 break;
986 case V4L2_CID_CONTRAST:
987 ctrl->value = state->contrast;
988 break;
990 case V4L2_CID_SATURATION:
991 ctrl->value = state->sat;
992 break;
994 case V4L2_CID_HUE:
995 ctrl->value = state->hue;
996 break;
998 case V4L2_CID_AUDIO_MUTE:
999 ctrl->value = state->audio_main_mute;
1000 break;
1002 case V4L2_CID_AUDIO_VOLUME:
1003 ctrl->value = state->audio_main_volume;
1004 break;
1006 case V4L2_CID_AUDIO_BALANCE:
1007 ctrl->value = state->audio_main_balance;
1008 break;
1010 case V4L2_CID_AUDIO_TREBLE:
1011 ctrl->value = state->audio_main_treble;
1012 break;
1014 case V4L2_CID_AUDIO_BASS:
1015 ctrl->value = state->audio_main_bass;
1016 break;
1018 default:
1019 return -EINVAL;
1022 return 0;
1025 static struct v4l2_queryctrl saa717x_qctrl[] = {
1027 .id = V4L2_CID_BRIGHTNESS,
1028 .type = V4L2_CTRL_TYPE_INTEGER,
1029 .name = "Brightness",
1030 .minimum = 0,
1031 .maximum = 255,
1032 .step = 1,
1033 .default_value = 128,
1034 .flags = 0,
1035 }, {
1036 .id = V4L2_CID_CONTRAST,
1037 .type = V4L2_CTRL_TYPE_INTEGER,
1038 .name = "Contrast",
1039 .minimum = 0,
1040 .maximum = 255,
1041 .step = 1,
1042 .default_value = 64,
1043 .flags = 0,
1044 }, {
1045 .id = V4L2_CID_SATURATION,
1046 .type = V4L2_CTRL_TYPE_INTEGER,
1047 .name = "Saturation",
1048 .minimum = 0,
1049 .maximum = 255,
1050 .step = 1,
1051 .default_value = 64,
1052 .flags = 0,
1053 }, {
1054 .id = V4L2_CID_HUE,
1055 .type = V4L2_CTRL_TYPE_INTEGER,
1056 .name = "Hue",
1057 .minimum = -128,
1058 .maximum = 127,
1059 .step = 1,
1060 .default_value = 0,
1061 .flags = 0,
1062 }, {
1063 .id = V4L2_CID_AUDIO_VOLUME,
1064 .type = V4L2_CTRL_TYPE_INTEGER,
1065 .name = "Volume",
1066 .minimum = 0,
1067 .maximum = 65535,
1068 .step = 65535 / 100,
1069 .default_value = 58880,
1070 .flags = 0,
1071 }, {
1072 .id = V4L2_CID_AUDIO_BALANCE,
1073 .type = V4L2_CTRL_TYPE_INTEGER,
1074 .name = "Balance",
1075 .minimum = 0,
1076 .maximum = 65535,
1077 .step = 65535 / 100,
1078 .default_value = 32768,
1079 .flags = 0,
1080 }, {
1081 .id = V4L2_CID_AUDIO_MUTE,
1082 .type = V4L2_CTRL_TYPE_BOOLEAN,
1083 .name = "Mute",
1084 .minimum = 0,
1085 .maximum = 1,
1086 .step = 1,
1087 .default_value = 1,
1088 .flags = 0,
1089 }, {
1090 .id = V4L2_CID_AUDIO_BASS,
1091 .type = V4L2_CTRL_TYPE_INTEGER,
1092 .name = "Bass",
1093 .minimum = 0,
1094 .maximum = 65535,
1095 .step = 65535 / 100,
1096 .default_value = 32768,
1097 }, {
1098 .id = V4L2_CID_AUDIO_TREBLE,
1099 .type = V4L2_CTRL_TYPE_INTEGER,
1100 .name = "Treble",
1101 .minimum = 0,
1102 .maximum = 65535,
1103 .step = 65535 / 100,
1104 .default_value = 32768,
1108 static int saa717x_s_video_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
1110 struct saa717x_state *decoder = to_state(sd);
1111 int inp = route->input;
1112 int is_tuner = inp & 0x80; /* tuner input flag */
1114 inp &= 0x7f;
1116 v4l2_dbg(1, debug, sd, "decoder set input (%d)\n", inp);
1117 /* inputs from 0-9 are available*/
1118 /* saa717x have mode0-mode9 but mode5 is reserved. */
1119 if (inp < 0 || inp > 9 || inp == 5)
1120 return -EINVAL;
1122 if (decoder->input != inp) {
1123 int input_line = inp;
1125 decoder->input = input_line;
1126 v4l2_dbg(1, debug, sd, "now setting %s input %d\n",
1127 input_line >= 6 ? "S-Video" : "Composite",
1128 input_line);
1130 /* select mode */
1131 saa717x_write(sd, 0x102,
1132 (saa717x_read(sd, 0x102) & 0xf0) |
1133 input_line);
1135 /* bypass chrominance trap for modes 6..9 */
1136 saa717x_write(sd, 0x109,
1137 (saa717x_read(sd, 0x109) & 0x7f) |
1138 (input_line < 6 ? 0x0 : 0x80));
1140 /* change audio_mode */
1141 if (is_tuner) {
1142 /* tuner */
1143 set_audio_mode(sd, decoder->tuner_audio_mode);
1144 } else {
1145 /* Force to STEREO mode if Composite or
1146 * S-Video were chosen */
1147 set_audio_mode(sd, TUNER_AUDIO_STEREO);
1149 /* change initialize procedure (Composite/S-Video) */
1150 if (is_tuner)
1151 saa717x_write_regs(sd, reg_init_tuner_input);
1152 else if (input_line >= 6)
1153 saa717x_write_regs(sd, reg_init_svideo_input);
1154 else
1155 saa717x_write_regs(sd, reg_init_composite_input);
1158 return 0;
1161 static int saa717x_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
1163 int i;
1165 for (i = 0; i < ARRAY_SIZE(saa717x_qctrl); i++)
1166 if (qc->id && qc->id == saa717x_qctrl[i].id) {
1167 memcpy(qc, &saa717x_qctrl[i], sizeof(*qc));
1168 return 0;
1170 return -EINVAL;
1173 #ifdef CONFIG_VIDEO_ADV_DEBUG
1174 static int saa717x_g_register(struct v4l2_subdev *sd, struct v4l2_register *reg)
1176 struct i2c_client *client = v4l2_get_subdevdata(sd);
1178 if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip))
1179 return -EINVAL;
1180 if (!capable(CAP_SYS_ADMIN))
1181 return -EPERM;
1182 reg->val = saa717x_read(sd, reg->reg);
1183 return 0;
1186 static int saa717x_s_register(struct v4l2_subdev *sd, struct v4l2_register *reg)
1188 struct i2c_client *client = v4l2_get_subdevdata(sd);
1189 u16 addr = reg->reg & 0xffff;
1190 u8 val = reg->val & 0xff;
1192 if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip))
1193 return -EINVAL;
1194 if (!capable(CAP_SYS_ADMIN))
1195 return -EPERM;
1196 saa717x_write(sd, addr, val);
1197 return 0;
1199 #endif
1201 static int saa717x_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
1203 struct v4l2_pix_format *pix;
1204 int prescale, h_scale, v_scale;
1206 pix = &fmt->fmt.pix;
1207 v4l2_dbg(1, debug, sd, "decoder set size\n");
1209 /* FIXME need better bounds checking here */
1210 if (pix->width < 1 || pix->width > 1440)
1211 return -EINVAL;
1212 if (pix->height < 1 || pix->height > 960)
1213 return -EINVAL;
1215 /* scaling setting */
1216 /* NTSC and interlace only */
1217 prescale = SAA717X_NTSC_WIDTH / pix->width;
1218 if (prescale == 0)
1219 prescale = 1;
1220 h_scale = 1024 * SAA717X_NTSC_WIDTH / prescale / pix->width;
1221 /* interlace */
1222 v_scale = 512 * 2 * SAA717X_NTSC_HEIGHT / pix->height;
1224 /* Horizontal prescaling etc */
1225 set_h_prescale(sd, 0, prescale);
1226 set_h_prescale(sd, 1, prescale);
1228 /* Horizontal scaling increment */
1229 /* TASK A */
1230 saa717x_write(sd, 0x6C, (u8)(h_scale & 0xFF));
1231 saa717x_write(sd, 0x6D, (u8)((h_scale >> 8) & 0xFF));
1232 /* TASK B */
1233 saa717x_write(sd, 0xAC, (u8)(h_scale & 0xFF));
1234 saa717x_write(sd, 0xAD, (u8)((h_scale >> 8) & 0xFF));
1236 /* Vertical prescaling etc */
1237 set_v_scale(sd, 0, v_scale);
1238 set_v_scale(sd, 1, v_scale);
1240 /* set video output size */
1241 /* video number of pixels at output */
1242 /* TASK A */
1243 saa717x_write(sd, 0x5C, (u8)(pix->width & 0xFF));
1244 saa717x_write(sd, 0x5D, (u8)((pix->width >> 8) & 0xFF));
1245 /* TASK B */
1246 saa717x_write(sd, 0x9C, (u8)(pix->width & 0xFF));
1247 saa717x_write(sd, 0x9D, (u8)((pix->width >> 8) & 0xFF));
1249 /* video number of lines at output */
1250 /* TASK A */
1251 saa717x_write(sd, 0x5E, (u8)(pix->height & 0xFF));
1252 saa717x_write(sd, 0x5F, (u8)((pix->height >> 8) & 0xFF));
1253 /* TASK B */
1254 saa717x_write(sd, 0x9E, (u8)(pix->height & 0xFF));
1255 saa717x_write(sd, 0x9F, (u8)((pix->height >> 8) & 0xFF));
1256 return 0;
1259 static int saa717x_s_radio(struct v4l2_subdev *sd)
1261 struct saa717x_state *decoder = to_state(sd);
1263 decoder->radio = 1;
1264 return 0;
1267 static int saa717x_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
1269 struct saa717x_state *decoder = to_state(sd);
1271 v4l2_dbg(1, debug, sd, "decoder set norm ");
1272 v4l2_dbg(1, debug, sd, "(not yet implementd)\n");
1274 decoder->radio = 0;
1275 decoder->std = std;
1276 return 0;
1279 static int saa717x_s_audio_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
1281 struct saa717x_state *decoder = to_state(sd);
1283 if (route->input < 3) { /* FIXME! --tadachi */
1284 decoder->audio_input = route->input;
1285 v4l2_dbg(1, debug, sd,
1286 "set decoder audio input to %d\n",
1287 decoder->audio_input);
1288 set_audio_regs(sd, decoder);
1289 return 0;
1291 return -ERANGE;
1294 static int saa717x_s_stream(struct v4l2_subdev *sd, int enable)
1296 struct saa717x_state *decoder = to_state(sd);
1298 v4l2_dbg(1, debug, sd, "decoder %s output\n",
1299 enable ? "enable" : "disable");
1300 decoder->enable = enable;
1301 saa717x_write(sd, 0x193, enable ? 0xa6 : 0x26);
1302 return 0;
1305 /* change audio mode */
1306 static int saa717x_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
1308 struct saa717x_state *decoder = to_state(sd);
1309 int audio_mode;
1310 char *mes[4] = {
1311 "MONO", "STEREO", "LANG1", "LANG2/SAP"
1314 audio_mode = V4L2_TUNER_MODE_STEREO;
1316 switch (vt->audmode) {
1317 case V4L2_TUNER_MODE_MONO:
1318 audio_mode = TUNER_AUDIO_MONO;
1319 break;
1320 case V4L2_TUNER_MODE_STEREO:
1321 audio_mode = TUNER_AUDIO_STEREO;
1322 break;
1323 case V4L2_TUNER_MODE_LANG2:
1324 audio_mode = TUNER_AUDIO_LANG2;
1325 break;
1326 case V4L2_TUNER_MODE_LANG1:
1327 audio_mode = TUNER_AUDIO_LANG1;
1328 break;
1331 v4l2_dbg(1, debug, sd, "change audio mode to %s\n",
1332 mes[audio_mode]);
1333 decoder->tuner_audio_mode = audio_mode;
1334 /* The registers are not changed here. */
1335 /* See DECODER_ENABLE_OUTPUT section. */
1336 set_audio_mode(sd, decoder->tuner_audio_mode);
1337 return 0;
1340 static int saa717x_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
1342 struct saa717x_state *decoder = to_state(sd);
1343 int dual_f, stereo_f;
1345 if (decoder->radio)
1346 return 0;
1347 get_inf_dev_status(sd, &dual_f, &stereo_f);
1349 v4l2_dbg(1, debug, sd, "DETECT==st:%d dual:%d\n",
1350 stereo_f, dual_f);
1352 /* mono */
1353 if ((dual_f == 0) && (stereo_f == 0)) {
1354 vt->rxsubchans = V4L2_TUNER_SUB_MONO;
1355 v4l2_dbg(1, debug, sd, "DETECT==MONO\n");
1358 /* stereo */
1359 if (stereo_f == 1) {
1360 if (vt->audmode == V4L2_TUNER_MODE_STEREO ||
1361 vt->audmode == V4L2_TUNER_MODE_LANG1) {
1362 vt->rxsubchans = V4L2_TUNER_SUB_STEREO;
1363 v4l2_dbg(1, debug, sd, "DETECT==ST(ST)\n");
1364 } else {
1365 vt->rxsubchans = V4L2_TUNER_SUB_MONO;
1366 v4l2_dbg(1, debug, sd, "DETECT==ST(MONO)\n");
1370 /* dual */
1371 if (dual_f == 1) {
1372 if (vt->audmode == V4L2_TUNER_MODE_LANG2) {
1373 vt->rxsubchans = V4L2_TUNER_SUB_LANG2 | V4L2_TUNER_SUB_MONO;
1374 v4l2_dbg(1, debug, sd, "DETECT==DUAL1\n");
1375 } else {
1376 vt->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_MONO;
1377 v4l2_dbg(1, debug, sd, "DETECT==DUAL2\n");
1380 return 0;
1383 static int saa717x_command(struct i2c_client *client, unsigned cmd, void *arg)
1385 return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
1388 /* ----------------------------------------------------------------------- */
1390 static const struct v4l2_subdev_core_ops saa717x_core_ops = {
1391 #ifdef CONFIG_VIDEO_ADV_DEBUG
1392 .g_register = saa717x_g_register,
1393 .s_register = saa717x_s_register,
1394 #endif
1395 .queryctrl = saa717x_queryctrl,
1396 .g_ctrl = saa717x_g_ctrl,
1397 .s_ctrl = saa717x_s_ctrl,
1400 static const struct v4l2_subdev_tuner_ops saa717x_tuner_ops = {
1401 .g_tuner = saa717x_g_tuner,
1402 .s_tuner = saa717x_s_tuner,
1403 .s_std = saa717x_s_std,
1404 .s_radio = saa717x_s_radio,
1407 static const struct v4l2_subdev_video_ops saa717x_video_ops = {
1408 .s_routing = saa717x_s_video_routing,
1409 .s_fmt = saa717x_s_fmt,
1410 .s_stream = saa717x_s_stream,
1413 static const struct v4l2_subdev_audio_ops saa717x_audio_ops = {
1414 .s_routing = saa717x_s_audio_routing,
1417 static const struct v4l2_subdev_ops saa717x_ops = {
1418 .core = &saa717x_core_ops,
1419 .tuner = &saa717x_tuner_ops,
1420 .audio = &saa717x_audio_ops,
1421 .video = &saa717x_video_ops,
1424 /* ----------------------------------------------------------------------- */
1427 /* i2c implementation */
1429 /* ----------------------------------------------------------------------- */
1430 static int saa717x_probe(struct i2c_client *client,
1431 const struct i2c_device_id *did)
1433 struct saa717x_state *decoder;
1434 struct v4l2_subdev *sd;
1435 u8 id = 0;
1436 char *p = "";
1438 /* Check if the adapter supports the needed features */
1439 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
1440 return -EIO;
1442 decoder = kzalloc(sizeof(struct saa717x_state), GFP_KERNEL);
1443 if (decoder == NULL)
1444 return -ENOMEM;
1446 sd = &decoder->sd;
1447 v4l2_i2c_subdev_init(sd, client, &saa717x_ops);
1449 if (saa717x_write(sd, 0x5a4, 0xfe) &&
1450 saa717x_write(sd, 0x5a5, 0x0f) &&
1451 saa717x_write(sd, 0x5a6, 0x00) &&
1452 saa717x_write(sd, 0x5a7, 0x01))
1453 id = saa717x_read(sd, 0x5a0);
1454 if (id != 0xc2 && id != 0x32 && id != 0xf2 && id != 0x6c) {
1455 v4l2_dbg(1, debug, sd, "saa717x not found (id=%02x)\n", id);
1456 kfree(decoder);
1457 return -ENODEV;
1459 if (id == 0xc2)
1460 p = "saa7173";
1461 else if (id == 0x32)
1462 p = "saa7174A";
1463 else if (id == 0x6c)
1464 p = "saa7174HL";
1465 else
1466 p = "saa7171";
1467 v4l2_info(sd, "%s found @ 0x%x (%s)\n", p,
1468 client->addr << 1, client->adapter->name);
1469 decoder->std = V4L2_STD_NTSC;
1470 decoder->input = -1;
1471 decoder->enable = 1;
1473 /* tune these parameters */
1474 decoder->bright = 0x80;
1475 decoder->contrast = 0x44;
1476 decoder->sat = 0x40;
1477 decoder->hue = 0x00;
1479 /* FIXME!! */
1480 decoder->playback = 0; /* initially capture mode used */
1481 decoder->audio = 1; /* DECODER_AUDIO_48_KHZ */
1483 decoder->audio_input = 2; /* FIXME!! */
1485 decoder->tuner_audio_mode = TUNER_AUDIO_STEREO;
1486 /* set volume, bass and treble */
1487 decoder->audio_main_vol_l = 6;
1488 decoder->audio_main_vol_r = 6;
1489 decoder->audio_main_bass = 0;
1490 decoder->audio_main_treble = 0;
1491 decoder->audio_main_mute = 0;
1492 decoder->audio_main_balance = 32768;
1493 /* normalize (24 to -40 (not -84) -> 65535 to 0) */
1494 decoder->audio_main_volume =
1495 (decoder->audio_main_vol_r + 41) * 65535 / (24 - (-40));
1497 v4l2_dbg(1, debug, sd, "writing init values\n");
1499 /* FIXME!! */
1500 saa717x_write_regs(sd, reg_init_initialize);
1501 set_video_output_level_regs(sd, decoder);
1502 /* set bass,treble to 0db 20041101 K.Ohta */
1503 decoder->audio_main_bass = 0;
1504 decoder->audio_main_treble = 0;
1505 set_audio_regs(sd, decoder);
1507 set_current_state(TASK_INTERRUPTIBLE);
1508 schedule_timeout(2*HZ);
1509 return 0;
1512 static int saa717x_remove(struct i2c_client *client)
1514 struct v4l2_subdev *sd = i2c_get_clientdata(client);
1516 v4l2_device_unregister_subdev(sd);
1517 kfree(to_state(sd));
1518 return 0;
1521 /* ----------------------------------------------------------------------- */
1523 static const struct i2c_device_id saa717x_id[] = {
1524 { "saa717x", 0 },
1527 MODULE_DEVICE_TABLE(i2c, saa717x_id);
1529 static struct v4l2_i2c_driver_data v4l2_i2c_data = {
1530 .name = "saa717x",
1531 .driverid = I2C_DRIVERID_SAA717X,
1532 .command = saa717x_command,
1533 .probe = saa717x_probe,
1534 .remove = saa717x_remove,
1535 .legacy_class = I2C_CLASS_TV_ANALOG | I2C_CLASS_TV_DIGITAL,
1536 .id_table = saa717x_id,