blob: 490b9049b9874c3bf5763d84bb2e4d42199def32 [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
Hans Verkuilfb7b37c2008-04-09 06:26:17 -030033#include <linux/module.h>
34#include <linux/kernel.h>
35#include <linux/sched.h>
36
Hans Verkuilfb7b37c2008-04-09 06:26:17 -030037#include <linux/videodev2.h>
38#include <linux/i2c.h>
Hans Verkuil27760fc2008-11-29 12:57:44 -030039#include <media/v4l2-device.h>
Hans Verkuilfb7b37c2008-04-09 06:26:17 -030040#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 {
Hans Verkuil27760fc2008-11-29 12:57:44 -030056 struct v4l2_subdev sd;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -030057 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
Hans Verkuil27760fc2008-11-29 12:57:44 -030078static inline struct saa717x_state *to_state(struct v4l2_subdev *sd)
79{
80 return container_of(sd, struct saa717x_state, sd);
81}
82
Hans Verkuilfb7b37c2008-04-09 06:26:17 -030083/* ----------------------------------------------------------------------- */
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
Hans Verkuil27760fc2008-11-29 12:57:44 -030096static int saa717x_write(struct v4l2_subdev *sd, u32 reg, u32 value)
Hans Verkuilfb7b37c2008-04-09 06:26:17 -030097{
Hans Verkuil27760fc2008-11-29 12:57:44 -030098 struct i2c_client *client = v4l2_get_subdevdata(sd);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -030099 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;
Hans Verkuil27760fc2008-11-29 12:57:44 -0300118 v4l2_dbg(2, debug, sd, "wrote: reg 0x%03x=%08x\n", reg, value);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300119 return i2c_transfer(adap, &msg, 1) == 1;
120}
121
Hans Verkuil27760fc2008-11-29 12:57:44 -0300122static void saa717x_write_regs(struct v4l2_subdev *sd, u32 *data)
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300123{
124 while (data[0] || data[1]) {
Hans Verkuil27760fc2008-11-29 12:57:44 -0300125 saa717x_write(sd, data[0], data[1]);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300126 data += 2;
127 }
128}
129
Hans Verkuil27760fc2008-11-29 12:57:44 -0300130static u32 saa717x_read(struct v4l2_subdev *sd, u32 reg)
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300131{
Hans Verkuil27760fc2008-11-29 12:57:44 -0300132 struct i2c_client *client = v4l2_get_subdevdata(sd);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300133 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
Hans Verkuil27760fc2008-11-29 12:57:44 -0300156 v4l2_dbg(2, debug, sd, "read: reg 0x%03x=0x%08x\n", reg, value);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300157 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) */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300690static void get_inf_dev_status(struct v4l2_subdev *sd,
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300691 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 */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300729 reg_data3 = saa717x_read(sd, 0x0528);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300730
Hans Verkuil27760fc2008-11-29 12:57:44 -0300731 v4l2_dbg(1, debug, sd, "tvaudio thread status: 0x%x [%s%s%s]\n",
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300732 reg_data3, stdres[reg_data3 & 0x1f],
733 (reg_data3 & 0x000020) ? ",stereo" : "",
734 (reg_data3 & 0x000040) ? ",dual" : "");
Hans Verkuil27760fc2008-11-29 12:57:44 -0300735 v4l2_dbg(1, debug, sd, "detailed status: "
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300736 "%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) {
Hans Verkuil27760fc2008-11-29 12:57:44 -0300756 v4l2_dbg(1, debug, sd, "ST!!!\n");
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300757 *stereo_flag = 1;
758 }
759
760 if (reg_data3 & 0x000140) {
Hans Verkuil27760fc2008-11-29 12:57:44 -0300761 v4l2_dbg(1, debug, sd, "DUAL!!!\n");
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300762 *dual_flag = 1;
763 }
764}
765
766/* regs write to set audio mode */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300767static void set_audio_mode(struct v4l2_subdev *sd, int audio_mode)
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300768{
Hans Verkuil27760fc2008-11-29 12:57:44 -0300769 v4l2_dbg(1, debug, sd, "writing registers to set audio mode by set %d\n",
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300770 audio_mode);
771
Hans Verkuil27760fc2008-11-29 12:57:44 -0300772 saa717x_write(sd, 0x46c, reg_set_audio_template[audio_mode][0]);
773 saa717x_write(sd, 0x470, reg_set_audio_template[audio_mode][1]);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300774}
775
776/* write regs to video output level (bright,contrast,hue,sat) */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300777static void set_video_output_level_regs(struct v4l2_subdev *sd,
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300778 struct saa717x_state *decoder)
779{
780 /* brightness ffh (bright) - 80h (ITU level) - 00h (dark) */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300781 saa717x_write(sd, 0x10a, decoder->bright);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300782
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) */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300787 saa717x_write(sd, 0x10b, decoder->contrast);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300788
789 /* saturation? 7fh(max)-40h(ITU)-0h(color off)
790 c0h (-1.0 inverse chrominance)
791 80h (-2.0 inverse chrominance) */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300792 saa717x_write(sd, 0x10c, decoder->sat);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300793
794 /* color hue (phase) control
795 7fh (+178.6) - 0h (0 normal) - 80h (-180.0) */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300796 saa717x_write(sd, 0x10d, decoder->hue);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300797}
798
799/* write regs to set audio volume, bass and treble */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300800static int set_audio_regs(struct v4l2_subdev *sd,
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300801 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 */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300808 saa717x_write(sd, 0x0594, decoder->audio_input);
809 v4l2_dbg(1, debug, sd, "set audio input %d\n",
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300810 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
Hans Verkuil27760fc2008-11-29 12:57:44 -0300829 saa717x_write(sd, 0x480, val);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300830
831 /* bass and treble; go to another function */
832 /* set bass and treble */
833 val = decoder->audio_main_bass | (decoder->audio_main_treble << 8);
Hans Verkuil27760fc2008-11-29 12:57:44 -0300834 saa717x_write(sd, 0x488, val);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300835 return 0;
836}
837
838/********** scaling staff ***********/
Hans Verkuil27760fc2008-11-29 12:57:44 -0300839static void set_h_prescale(struct v4l2_subdev *sd,
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300840 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 */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300872 saa717x_write(sd, 0x60 + task_shift, vals[i].xpsc);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300873 /* accumulation length */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300874 saa717x_write(sd, 0x61 + task_shift, vals[i].xacl);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300875 /* level control */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300876 saa717x_write(sd, 0x62 + task_shift,
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300877 (vals[i].xc2_1 << 3) | vals[i].xdcg);
878 /*FIR prefilter control */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300879 saa717x_write(sd, 0x63 + task_shift,
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300880 (vals[i].vpfy << 2) | vals[i].vpfy);
881}
882
883/********** scaling staff ***********/
Hans Verkuil27760fc2008-11-29 12:57:44 -0300884static void set_v_scale(struct v4l2_subdev *sd, int task, int yscale)
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300885{
886 int task_shift;
887
888 task_shift = task * 0x40;
889 /* Vertical scaling ratio (LOW) */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300890 saa717x_write(sd, 0x70 + task_shift, yscale & 0xff);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300891 /* Vertical scaling ratio (HI) */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300892 saa717x_write(sd, 0x71 + task_shift, yscale >> 8);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300893}
894
Hans Verkuil27760fc2008-11-29 12:57:44 -0300895static int saa717x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300896{
Hans Verkuil27760fc2008-11-29 12:57:44 -0300897 struct saa717x_state *state = to_state(sd);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300898
899 switch (ctrl->id) {
900 case V4L2_CID_BRIGHTNESS:
901 if (ctrl->value < 0 || ctrl->value > 255) {
Hans Verkuil27760fc2008-11-29 12:57:44 -0300902 v4l2_err(sd, "invalid brightness setting %d\n", ctrl->value);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300903 return -ERANGE;
904 }
905
906 state->bright = ctrl->value;
Hans Verkuil27760fc2008-11-29 12:57:44 -0300907 v4l2_dbg(1, debug, sd, "bright:%d\n", state->bright);
908 saa717x_write(sd, 0x10a, state->bright);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300909 break;
910
911 case V4L2_CID_CONTRAST:
912 if (ctrl->value < 0 || ctrl->value > 127) {
Hans Verkuil27760fc2008-11-29 12:57:44 -0300913 v4l2_err(sd, "invalid contrast setting %d\n", ctrl->value);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300914 return -ERANGE;
915 }
916
917 state->contrast = ctrl->value;
Hans Verkuil27760fc2008-11-29 12:57:44 -0300918 v4l2_dbg(1, debug, sd, "contrast:%d\n", state->contrast);
919 saa717x_write(sd, 0x10b, state->contrast);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300920 break;
921
922 case V4L2_CID_SATURATION:
923 if (ctrl->value < 0 || ctrl->value > 127) {
Hans Verkuil27760fc2008-11-29 12:57:44 -0300924 v4l2_err(sd, "invalid saturation setting %d\n", ctrl->value);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300925 return -ERANGE;
926 }
927
928 state->sat = ctrl->value;
Hans Verkuil27760fc2008-11-29 12:57:44 -0300929 v4l2_dbg(1, debug, sd, "sat:%d\n", state->sat);
930 saa717x_write(sd, 0x10c, state->sat);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300931 break;
932
933 case V4L2_CID_HUE:
Hans Verkuilde6476f52009-01-29 16:09:13 -0300934 if (ctrl->value < -128 || ctrl->value > 127) {
Hans Verkuil27760fc2008-11-29 12:57:44 -0300935 v4l2_err(sd, "invalid hue setting %d\n", ctrl->value);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300936 return -ERANGE;
937 }
938
939 state->hue = ctrl->value;
Hans Verkuil27760fc2008-11-29 12:57:44 -0300940 v4l2_dbg(1, debug, sd, "hue:%d\n", state->hue);
941 saa717x_write(sd, 0x10d, state->hue);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300942 break;
943
944 case V4L2_CID_AUDIO_MUTE:
945 state->audio_main_mute = ctrl->value;
Hans Verkuil27760fc2008-11-29 12:57:44 -0300946 set_audio_regs(sd, state);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300947 break;
948
949 case V4L2_CID_AUDIO_VOLUME:
950 state->audio_main_volume = ctrl->value;
Hans Verkuil27760fc2008-11-29 12:57:44 -0300951 set_audio_regs(sd, state);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300952 break;
953
954 case V4L2_CID_AUDIO_BALANCE:
955 state->audio_main_balance = ctrl->value;
Hans Verkuil27760fc2008-11-29 12:57:44 -0300956 set_audio_regs(sd, state);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300957 break;
958
959 case V4L2_CID_AUDIO_TREBLE:
960 state->audio_main_treble = ctrl->value;
Hans Verkuil27760fc2008-11-29 12:57:44 -0300961 set_audio_regs(sd, state);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300962 break;
963
964 case V4L2_CID_AUDIO_BASS:
965 state->audio_main_bass = ctrl->value;
Hans Verkuil27760fc2008-11-29 12:57:44 -0300966 set_audio_regs(sd, state);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300967 break;
968
969 default:
970 return -EINVAL;
971 }
972
973 return 0;
974}
975
Hans Verkuil27760fc2008-11-29 12:57:44 -0300976static int saa717x_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300977{
Hans Verkuil27760fc2008-11-29 12:57:44 -0300978 struct saa717x_state *state = to_state(sd);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300979
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
Hans Verkuil27760fc2008-11-29 12:57:44 -03001107static int saa717x_s_video_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001108{
Hans Verkuil27760fc2008-11-29 12:57:44 -03001109 struct saa717x_state *decoder = to_state(sd);
1110 int inp = route->input;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001111 int is_tuner = inp & 0x80; /* tuner input flag */
1112
1113 inp &= 0x7f;
1114
Hans Verkuil27760fc2008-11-29 12:57:44 -03001115 v4l2_dbg(1, debug, sd, "decoder set input (%d)\n", inp);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001116 /* inputs from 0-9 are available*/
1117 /* saa717x have mode0-mode9 but mode5 is reserved. */
1118 if (inp < 0 || inp > 9 || inp == 5)
1119 return -EINVAL;
1120
1121 if (decoder->input != inp) {
1122 int input_line = inp;
1123
1124 decoder->input = input_line;
Hans Verkuil27760fc2008-11-29 12:57:44 -03001125 v4l2_dbg(1, debug, sd, "now setting %s input %d\n",
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001126 input_line >= 6 ? "S-Video" : "Composite",
1127 input_line);
1128
1129 /* select mode */
Hans Verkuil27760fc2008-11-29 12:57:44 -03001130 saa717x_write(sd, 0x102,
1131 (saa717x_read(sd, 0x102) & 0xf0) |
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001132 input_line);
1133
1134 /* bypass chrominance trap for modes 6..9 */
Hans Verkuil27760fc2008-11-29 12:57:44 -03001135 saa717x_write(sd, 0x109,
1136 (saa717x_read(sd, 0x109) & 0x7f) |
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001137 (input_line < 6 ? 0x0 : 0x80));
1138
1139 /* change audio_mode */
1140 if (is_tuner) {
1141 /* tuner */
Hans Verkuil27760fc2008-11-29 12:57:44 -03001142 set_audio_mode(sd, decoder->tuner_audio_mode);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001143 } else {
1144 /* Force to STEREO mode if Composite or
1145 * S-Video were chosen */
Hans Verkuil27760fc2008-11-29 12:57:44 -03001146 set_audio_mode(sd, TUNER_AUDIO_STEREO);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001147 }
1148 /* change initialize procedure (Composite/S-Video) */
1149 if (is_tuner)
Hans Verkuil27760fc2008-11-29 12:57:44 -03001150 saa717x_write_regs(sd, reg_init_tuner_input);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001151 else if (input_line >= 6)
Hans Verkuil27760fc2008-11-29 12:57:44 -03001152 saa717x_write_regs(sd, reg_init_svideo_input);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001153 else
Hans Verkuil27760fc2008-11-29 12:57:44 -03001154 saa717x_write_regs(sd, reg_init_composite_input);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001155 }
1156
1157 return 0;
1158}
1159
Hans Verkuil27760fc2008-11-29 12:57:44 -03001160static int saa717x_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001161{
Hans Verkuil27760fc2008-11-29 12:57:44 -03001162 int i;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001163
Hans Verkuil27760fc2008-11-29 12:57:44 -03001164 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}
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001171
1172#ifdef CONFIG_VIDEO_ADV_DEBUG
Hans Verkuilaecde8b2008-12-30 07:14:19 -03001173static int saa717x_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
Hans Verkuil27760fc2008-11-29 12:57:44 -03001174{
1175 struct i2c_client *client = v4l2_get_subdevdata(sd);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001176
Hans Verkuilaecde8b2008-12-30 07:14:19 -03001177 if (!v4l2_chip_match_i2c_client(client, &reg->match))
Hans Verkuil27760fc2008-11-29 12:57:44 -03001178 return -EINVAL;
1179 if (!capable(CAP_SYS_ADMIN))
1180 return -EPERM;
1181 reg->val = saa717x_read(sd, reg->reg);
Hans Verkuilaecde8b2008-12-30 07:14:19 -03001182 reg->size = 1;
Hans Verkuil27760fc2008-11-29 12:57:44 -03001183 return 0;
1184}
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001185
Hans Verkuilaecde8b2008-12-30 07:14:19 -03001186static int saa717x_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
Hans Verkuil27760fc2008-11-29 12:57:44 -03001187{
1188 struct i2c_client *client = v4l2_get_subdevdata(sd);
1189 u16 addr = reg->reg & 0xffff;
1190 u8 val = reg->val & 0xff;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001191
Hans Verkuilaecde8b2008-12-30 07:14:19 -03001192 if (!v4l2_chip_match_i2c_client(client, &reg->match))
Hans Verkuil27760fc2008-11-29 12:57:44 -03001193 return -EINVAL;
1194 if (!capable(CAP_SYS_ADMIN))
1195 return -EPERM;
1196 saa717x_write(sd, addr, val);
1197 return 0;
1198}
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001199#endif
1200
Hans Verkuil27760fc2008-11-29 12:57:44 -03001201static 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;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001205
Hans Verkuil27760fc2008-11-29 12:57:44 -03001206 pix = &fmt->fmt.pix;
1207 v4l2_dbg(1, debug, sd, "decoder set size\n");
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001208
Hans Verkuil27760fc2008-11-29 12:57:44 -03001209 /* 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;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001214
Hans Verkuil27760fc2008-11-29 12:57:44 -03001215 /* 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;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001223
Hans Verkuil27760fc2008-11-29 12:57:44 -03001224 /* Horizontal prescaling etc */
1225 set_h_prescale(sd, 0, prescale);
1226 set_h_prescale(sd, 1, prescale);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001227
Hans Verkuil27760fc2008-11-29 12:57:44 -03001228 /* 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));
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001235
Hans Verkuil27760fc2008-11-29 12:57:44 -03001236 /* Vertical prescaling etc */
1237 set_v_scale(sd, 0, v_scale);
1238 set_v_scale(sd, 1, v_scale);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001239
Hans Verkuil27760fc2008-11-29 12:57:44 -03001240 /* 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));
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001248
Hans Verkuil27760fc2008-11-29 12:57:44 -03001249 /* 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}
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001258
Hans Verkuil27760fc2008-11-29 12:57:44 -03001259static int saa717x_s_radio(struct v4l2_subdev *sd)
1260{
1261 struct saa717x_state *decoder = to_state(sd);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001262
Hans Verkuil27760fc2008-11-29 12:57:44 -03001263 decoder->radio = 1;
1264 return 0;
1265}
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001266
Hans Verkuil27760fc2008-11-29 12:57:44 -03001267static int saa717x_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
1268{
1269 struct saa717x_state *decoder = to_state(sd);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001270
Hans Verkuil27760fc2008-11-29 12:57:44 -03001271 v4l2_dbg(1, debug, sd, "decoder set norm ");
1272 v4l2_dbg(1, debug, sd, "(not yet implementd)\n");
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001273
Hans Verkuil27760fc2008-11-29 12:57:44 -03001274 decoder->radio = 0;
1275 decoder->std = std;
1276 return 0;
1277}
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001278
Hans Verkuil27760fc2008-11-29 12:57:44 -03001279static int saa717x_s_audio_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
1280{
1281 struct saa717x_state *decoder = to_state(sd);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001282
Hans Verkuil27760fc2008-11-29 12:57:44 -03001283 if (route->input < 3) { /* FIXME! --tadachi */
1284 decoder->audio_input = route->input;
1285 v4l2_dbg(1, debug, sd,
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001286 "set decoder audio input to %d\n",
1287 decoder->audio_input);
Hans Verkuil27760fc2008-11-29 12:57:44 -03001288 set_audio_regs(sd, decoder);
1289 return 0;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001290 }
Hans Verkuil27760fc2008-11-29 12:57:44 -03001291 return -ERANGE;
1292}
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001293
Hans Verkuil27760fc2008-11-29 12:57:44 -03001294static int saa717x_s_stream(struct v4l2_subdev *sd, int enable)
1295{
1296 struct saa717x_state *decoder = to_state(sd);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001297
Hans Verkuil27760fc2008-11-29 12:57:44 -03001298 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;
1303}
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001304
Hans Verkuil27760fc2008-11-29 12:57:44 -03001305/* change audio mode */
1306static int saa717x_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
1307{
1308 struct saa717x_state *decoder = to_state(sd);
1309 int audio_mode;
1310 char *mes[4] = {
1311 "MONO", "STEREO", "LANG1", "LANG2/SAP"
1312 };
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001313
Hans Verkuil27760fc2008-11-29 12:57:44 -03001314 audio_mode = V4L2_TUNER_MODE_STEREO;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001315
Hans Verkuil27760fc2008-11-29 12:57:44 -03001316 switch (vt->audmode) {
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001317 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;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001329 }
1330
Hans Verkuil27760fc2008-11-29 12:57:44 -03001331 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);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001337 return 0;
1338}
1339
Hans Verkuil27760fc2008-11-29 12:57:44 -03001340static int saa717x_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
1341{
1342 struct saa717x_state *decoder = to_state(sd);
1343 int dual_f, stereo_f;
1344
1345 if (decoder->radio)
1346 return 0;
1347 get_inf_dev_status(sd, &dual_f, &stereo_f);
1348
1349 v4l2_dbg(1, debug, sd, "DETECT==st:%d dual:%d\n",
1350 stereo_f, dual_f);
1351
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");
1356 }
1357
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");
1367 }
1368 }
1369
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");
1378 }
1379 }
1380 return 0;
1381}
1382
1383static int saa717x_command(struct i2c_client *client, unsigned cmd, void *arg)
1384{
1385 return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
1386}
1387
1388/* ----------------------------------------------------------------------- */
1389
1390static 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,
1398};
1399
1400static 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,
1405};
1406
1407static 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,
1411};
1412
1413static const struct v4l2_subdev_audio_ops saa717x_audio_ops = {
1414 .s_routing = saa717x_s_audio_routing,
1415};
1416
1417static 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,
1422};
1423
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001424/* ----------------------------------------------------------------------- */
1425
1426
1427/* i2c implementation */
1428
1429/* ----------------------------------------------------------------------- */
Jean Delvared2653e92008-04-29 23:11:39 +02001430static int saa717x_probe(struct i2c_client *client,
1431 const struct i2c_device_id *did)
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001432{
1433 struct saa717x_state *decoder;
Hans Verkuil27760fc2008-11-29 12:57:44 -03001434 struct v4l2_subdev *sd;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001435 u8 id = 0;
1436 char *p = "";
1437
1438 /* Check if the adapter supports the needed features */
1439 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
1440 return -EIO;
1441
Hans Verkuil27760fc2008-11-29 12:57:44 -03001442 decoder = kzalloc(sizeof(struct saa717x_state), GFP_KERNEL);
1443 if (decoder == NULL)
1444 return -ENOMEM;
1445
1446 sd = &decoder->sd;
1447 v4l2_i2c_subdev_init(sd, client, &saa717x_ops);
1448
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);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001454 if (id != 0xc2 && id != 0x32 && id != 0xf2 && id != 0x6c) {
Hans Verkuil27760fc2008-11-29 12:57:44 -03001455 v4l2_dbg(1, debug, sd, "saa717x not found (id=%02x)\n", id);
1456 kfree(decoder);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001457 return -ENODEV;
1458 }
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";
Hans Verkuil27760fc2008-11-29 12:57:44 -03001467 v4l2_info(sd, "%s found @ 0x%x (%s)\n", p,
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001468 client->addr << 1, client->adapter->name);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001469 decoder->std = V4L2_STD_NTSC;
1470 decoder->input = -1;
1471 decoder->enable = 1;
1472
1473 /* tune these parameters */
1474 decoder->bright = 0x80;
1475 decoder->contrast = 0x44;
1476 decoder->sat = 0x40;
1477 decoder->hue = 0x00;
1478
1479 /* FIXME!! */
1480 decoder->playback = 0; /* initially capture mode used */
1481 decoder->audio = 1; /* DECODER_AUDIO_48_KHZ */
1482
1483 decoder->audio_input = 2; /* FIXME!! */
1484
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));
1496
Hans Verkuil27760fc2008-11-29 12:57:44 -03001497 v4l2_dbg(1, debug, sd, "writing init values\n");
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001498
1499 /* FIXME!! */
Hans Verkuil27760fc2008-11-29 12:57:44 -03001500 saa717x_write_regs(sd, reg_init_initialize);
1501 set_video_output_level_regs(sd, decoder);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001502 /* set bass,treble to 0db 20041101 K.Ohta */
1503 decoder->audio_main_bass = 0;
1504 decoder->audio_main_treble = 0;
Hans Verkuil27760fc2008-11-29 12:57:44 -03001505 set_audio_regs(sd, decoder);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001506
1507 set_current_state(TASK_INTERRUPTIBLE);
1508 schedule_timeout(2*HZ);
1509 return 0;
1510}
1511
1512static int saa717x_remove(struct i2c_client *client)
1513{
Hans Verkuil27760fc2008-11-29 12:57:44 -03001514 struct v4l2_subdev *sd = i2c_get_clientdata(client);
1515
1516 v4l2_device_unregister_subdev(sd);
1517 kfree(to_state(sd));
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001518 return 0;
1519}
1520
1521/* ----------------------------------------------------------------------- */
1522
Jean Delvareaf294862008-05-18 20:49:40 +02001523static const struct i2c_device_id saa717x_id[] = {
1524 { "saa717x", 0 },
1525 { }
1526};
1527MODULE_DEVICE_TABLE(i2c, saa717x_id);
1528
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001529static 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,
Jean Delvareaf294862008-05-18 20:49:40 +02001536 .id_table = saa717x_id,
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001537};