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