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