blob: 454ad1dd7507a5f523b8513ef10988cd06d6b81f [file] [log] [blame]
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001/*
2 * saa717x - Philips SAA717xHL video decoder driver
3 *
4 * Based on the saa7115 driver
5 *
6 * Changes by Ohta Kyuma <alpha292@bremen.or.jp>
7 * - Apply to SAA717x,NEC uPD64031,uPD64083. (1/31/2004)
8 *
9 * Changes by T.Adachi (tadachi@tadachi-net.com)
10 * - support audio, video scaler etc, and checked the initialize sequence.
11 *
12 * Cleaned up by Hans Verkuil <hverkuil@xs4all.nl>
13 *
14 * Note: this is a reversed engineered driver based on captures from
15 * the I2C bus under Windows. This chip is very similar to the saa7134,
16 * though. Unfortunately, this driver is currently only working for NTSC.
17 *
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
22 *
23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
27 *
28 * You should have received a copy of the GNU General Public License
29 * along with this program; if not, write to the Free Software
30 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
31 */
32
33#include <linux/version.h>
34#include <linux/module.h>
35#include <linux/kernel.h>
36#include <linux/sched.h>
37
Hans Verkuilfb7b37c2008-04-09 06:26:17 -030038#include <linux/videodev2.h>
39#include <linux/i2c.h>
Hans Verkuil27760fc2008-11-29 12:57:44 -030040#include <media/v4l2-device.h>
Hans Verkuilfb7b37c2008-04-09 06:26:17 -030041#include <media/v4l2-i2c-drv.h>
42
43MODULE_DESCRIPTION("Philips SAA717x audio/video decoder driver");
44MODULE_AUTHOR("K. Ohta, T. Adachi, Hans Verkuil");
45MODULE_LICENSE("GPL");
46
47static int debug;
48module_param(debug, int, 0644);
49MODULE_PARM_DESC(debug, "Debug level (0-1)");
50
51/*
52 * Generic i2c probe
53 * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
54 */
55
56struct saa717x_state {
Hans Verkuil27760fc2008-11-29 12:57:44 -030057 struct v4l2_subdev sd;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -030058 v4l2_std_id std;
59 int input;
60 int enable;
61 int radio;
62 int bright;
63 int contrast;
64 int hue;
65 int sat;
66 int playback;
67 int audio;
68 int tuner_audio_mode;
69 int audio_main_mute;
70 int audio_main_vol_r;
71 int audio_main_vol_l;
72 u16 audio_main_bass;
73 u16 audio_main_treble;
74 u16 audio_main_volume;
75 u16 audio_main_balance;
76 int audio_input;
77};
78
Hans Verkuil27760fc2008-11-29 12:57:44 -030079static inline struct saa717x_state *to_state(struct v4l2_subdev *sd)
80{
81 return container_of(sd, struct saa717x_state, sd);
82}
83
Hans Verkuilfb7b37c2008-04-09 06:26:17 -030084/* ----------------------------------------------------------------------- */
85
86/* for audio mode */
87#define TUNER_AUDIO_MONO 0 /* LL */
88#define TUNER_AUDIO_STEREO 1 /* LR */
89#define TUNER_AUDIO_LANG1 2 /* LL */
90#define TUNER_AUDIO_LANG2 3 /* RR */
91
92#define SAA717X_NTSC_WIDTH (704)
93#define SAA717X_NTSC_HEIGHT (480)
94
95/* ----------------------------------------------------------------------- */
96
Hans Verkuil27760fc2008-11-29 12:57:44 -030097static int saa717x_write(struct v4l2_subdev *sd, u32 reg, u32 value)
Hans Verkuilfb7b37c2008-04-09 06:26:17 -030098{
Hans Verkuil27760fc2008-11-29 12:57:44 -030099 struct i2c_client *client = v4l2_get_subdevdata(sd);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300100 struct i2c_adapter *adap = client->adapter;
101 int fw_addr = reg == 0x454 || (reg >= 0x464 && reg <= 0x478) || reg == 0x480 || reg == 0x488;
102 unsigned char mm1[6];
103 struct i2c_msg msg;
104
105 msg.flags = 0;
106 msg.addr = client->addr;
107 mm1[0] = (reg >> 8) & 0xff;
108 mm1[1] = reg & 0xff;
109
110 if (fw_addr) {
111 mm1[4] = (value >> 16) & 0xff;
112 mm1[3] = (value >> 8) & 0xff;
113 mm1[2] = value & 0xff;
114 } else {
115 mm1[2] = value & 0xff;
116 }
117 msg.len = fw_addr ? 5 : 3; /* Long Registers have *only* three bytes! */
118 msg.buf = mm1;
Hans Verkuil27760fc2008-11-29 12:57:44 -0300119 v4l2_dbg(2, debug, sd, "wrote: reg 0x%03x=%08x\n", reg, value);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300120 return i2c_transfer(adap, &msg, 1) == 1;
121}
122
Hans Verkuil27760fc2008-11-29 12:57:44 -0300123static void saa717x_write_regs(struct v4l2_subdev *sd, u32 *data)
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300124{
125 while (data[0] || data[1]) {
Hans Verkuil27760fc2008-11-29 12:57:44 -0300126 saa717x_write(sd, data[0], data[1]);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300127 data += 2;
128 }
129}
130
Hans Verkuil27760fc2008-11-29 12:57:44 -0300131static u32 saa717x_read(struct v4l2_subdev *sd, u32 reg)
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300132{
Hans Verkuil27760fc2008-11-29 12:57:44 -0300133 struct i2c_client *client = v4l2_get_subdevdata(sd);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300134 struct i2c_adapter *adap = client->adapter;
135 int fw_addr = (reg >= 0x404 && reg <= 0x4b8) || reg == 0x528;
136 unsigned char mm1[2];
137 unsigned char mm2[4] = { 0, 0, 0, 0 };
138 struct i2c_msg msgs[2];
139 u32 value;
140
141 msgs[0].flags = 0;
142 msgs[1].flags = I2C_M_RD;
143 msgs[0].addr = msgs[1].addr = client->addr;
144 mm1[0] = (reg >> 8) & 0xff;
145 mm1[1] = reg & 0xff;
146 msgs[0].len = 2;
147 msgs[0].buf = mm1;
148 msgs[1].len = fw_addr ? 3 : 1; /* Multibyte Registers contains *only* 3 bytes */
149 msgs[1].buf = mm2;
150 i2c_transfer(adap, msgs, 2);
151
152 if (fw_addr)
153 value = (mm2[2] & 0xff) | ((mm2[1] & 0xff) >> 8) | ((mm2[0] & 0xff) >> 16);
154 else
155 value = mm2[0] & 0xff;
156
Hans Verkuil27760fc2008-11-29 12:57:44 -0300157 v4l2_dbg(2, debug, sd, "read: reg 0x%03x=0x%08x\n", reg, value);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300158 return value;
159}
160
161/* ----------------------------------------------------------------------- */
162
163static u32 reg_init_initialize[] =
164{
165 /* from linux driver */
166 0x101, 0x008, /* Increment delay */
167
168 0x103, 0x000, /* Analog input control 2 */
169 0x104, 0x090, /* Analog input control 3 */
170 0x105, 0x090, /* Analog input control 4 */
171 0x106, 0x0eb, /* Horizontal sync start */
172 0x107, 0x0e0, /* Horizontal sync stop */
173 0x109, 0x055, /* Luminance control */
174
175 0x10f, 0x02a, /* Chroma gain control */
176 0x110, 0x000, /* Chroma control 2 */
177
178 0x114, 0x045, /* analog/ADC */
179
180 0x118, 0x040, /* RAW data gain */
181 0x119, 0x080, /* RAW data offset */
182
183 0x044, 0x000, /* VBI horizontal input window start (L) TASK A */
184 0x045, 0x000, /* VBI horizontal input window start (H) TASK A */
185 0x046, 0x0cf, /* VBI horizontal input window stop (L) TASK A */
186 0x047, 0x002, /* VBI horizontal input window stop (H) TASK A */
187
188 0x049, 0x000, /* VBI vertical input window start (H) TASK A */
189
190 0x04c, 0x0d0, /* VBI horizontal output length (L) TASK A */
191 0x04d, 0x002, /* VBI horizontal output length (H) TASK A */
192
193 0x064, 0x080, /* Lumina brightness TASK A */
194 0x065, 0x040, /* Luminance contrast TASK A */
195 0x066, 0x040, /* Chroma saturation TASK A */
196 /* 067H: Reserved */
197 0x068, 0x000, /* VBI horizontal scaling increment (L) TASK A */
198 0x069, 0x004, /* VBI horizontal scaling increment (H) TASK A */
199 0x06a, 0x000, /* VBI phase offset TASK A */
200
201 0x06e, 0x000, /* Horizontal phase offset Luma TASK A */
202 0x06f, 0x000, /* Horizontal phase offset Chroma TASK A */
203
204 0x072, 0x000, /* Vertical filter mode TASK A */
205
206 0x084, 0x000, /* VBI horizontal input window start (L) TAKS B */
207 0x085, 0x000, /* VBI horizontal input window start (H) TAKS B */
208 0x086, 0x0cf, /* VBI horizontal input window stop (L) TAKS B */
209 0x087, 0x002, /* VBI horizontal input window stop (H) TAKS B */
210
211 0x089, 0x000, /* VBI vertical input window start (H) TAKS B */
212
213 0x08c, 0x0d0, /* VBI horizontal output length (L) TASK B */
214 0x08d, 0x002, /* VBI horizontal output length (H) TASK B */
215
216 0x0a4, 0x080, /* Lumina brightness TASK B */
217 0x0a5, 0x040, /* Luminance contrast TASK B */
218 0x0a6, 0x040, /* Chroma saturation TASK B */
219 /* 0A7H reserved */
220 0x0a8, 0x000, /* VBI horizontal scaling increment (L) TASK B */
221 0x0a9, 0x004, /* VBI horizontal scaling increment (H) TASK B */
222 0x0aa, 0x000, /* VBI phase offset TASK B */
223
224 0x0ae, 0x000, /* Horizontal phase offset Luma TASK B */
225 0x0af, 0x000, /*Horizontal phase offset Chroma TASK B */
226
227 0x0b2, 0x000, /* Vertical filter mode TASK B */
228
229 0x00c, 0x000, /* Start point GREEN path */
230 0x00d, 0x000, /* Start point BLUE path */
231 0x00e, 0x000, /* Start point RED path */
232
233 0x010, 0x010, /* GREEN path gamma curve --- */
234 0x011, 0x020,
235 0x012, 0x030,
236 0x013, 0x040,
237 0x014, 0x050,
238 0x015, 0x060,
239 0x016, 0x070,
240 0x017, 0x080,
241 0x018, 0x090,
242 0x019, 0x0a0,
243 0x01a, 0x0b0,
244 0x01b, 0x0c0,
245 0x01c, 0x0d0,
246 0x01d, 0x0e0,
247 0x01e, 0x0f0,
248 0x01f, 0x0ff, /* --- GREEN path gamma curve */
249
250 0x020, 0x010, /* BLUE path gamma curve --- */
251 0x021, 0x020,
252 0x022, 0x030,
253 0x023, 0x040,
254 0x024, 0x050,
255 0x025, 0x060,
256 0x026, 0x070,
257 0x027, 0x080,
258 0x028, 0x090,
259 0x029, 0x0a0,
260 0x02a, 0x0b0,
261 0x02b, 0x0c0,
262 0x02c, 0x0d0,
263 0x02d, 0x0e0,
264 0x02e, 0x0f0,
265 0x02f, 0x0ff, /* --- BLUE path gamma curve */
266
267 0x030, 0x010, /* RED path gamma curve --- */
268 0x031, 0x020,
269 0x032, 0x030,
270 0x033, 0x040,
271 0x034, 0x050,
272 0x035, 0x060,
273 0x036, 0x070,
274 0x037, 0x080,
275 0x038, 0x090,
276 0x039, 0x0a0,
277 0x03a, 0x0b0,
278 0x03b, 0x0c0,
279 0x03c, 0x0d0,
280 0x03d, 0x0e0,
281 0x03e, 0x0f0,
282 0x03f, 0x0ff, /* --- RED path gamma curve */
283
284 0x109, 0x085, /* Luminance control */
285
286 /**** from app start ****/
287 0x584, 0x000, /* AGC gain control */
288 0x585, 0x000, /* Program count */
289 0x586, 0x003, /* Status reset */
290 0x588, 0x0ff, /* Number of audio samples (L) */
291 0x589, 0x00f, /* Number of audio samples (M) */
292 0x58a, 0x000, /* Number of audio samples (H) */
293 0x58b, 0x000, /* Audio select */
294 0x58c, 0x010, /* Audio channel assign1 */
295 0x58d, 0x032, /* Audio channel assign2 */
296 0x58e, 0x054, /* Audio channel assign3 */
297 0x58f, 0x023, /* Audio format */
298 0x590, 0x000, /* SIF control */
299
300 0x595, 0x000, /* ?? */
301 0x596, 0x000, /* ?? */
302 0x597, 0x000, /* ?? */
303
304 0x464, 0x00, /* Digital input crossbar1 */
305
306 0x46c, 0xbbbb10, /* Digital output selection1-3 */
307 0x470, 0x101010, /* Digital output selection4-6 */
308
309 0x478, 0x00, /* Sound feature control */
310
311 0x474, 0x18, /* Softmute control */
312
313 0x454, 0x0425b9, /* Sound Easy programming(reset) */
314 0x454, 0x042539, /* Sound Easy programming(reset) */
315
316
317 /**** common setting( of DVD play, including scaler commands) ****/
318 0x042, 0x003, /* Data path configuration for VBI (TASK A) */
319
320 0x082, 0x003, /* Data path configuration for VBI (TASK B) */
321
322 0x108, 0x0f8, /* Sync control */
323 0x2a9, 0x0fd, /* ??? */
324 0x102, 0x089, /* select video input "mode 9" */
325 0x111, 0x000, /* Mode/delay control */
326
327 0x10e, 0x00a, /* Chroma control 1 */
328
329 0x594, 0x002, /* SIF, analog I/O select */
330
331 0x454, 0x0425b9, /* Sound */
332 0x454, 0x042539,
333
334 0x111, 0x000,
335 0x10e, 0x00a,
336 0x464, 0x000,
337 0x300, 0x000,
338 0x301, 0x006,
339 0x302, 0x000,
340 0x303, 0x006,
341 0x308, 0x040,
342 0x309, 0x000,
343 0x30a, 0x000,
344 0x30b, 0x000,
345 0x000, 0x002,
346 0x001, 0x000,
347 0x002, 0x000,
348 0x003, 0x000,
349 0x004, 0x033,
350 0x040, 0x01d,
351 0x041, 0x001,
352 0x042, 0x004,
353 0x043, 0x000,
354 0x080, 0x01e,
355 0x081, 0x001,
356 0x082, 0x004,
357 0x083, 0x000,
358 0x190, 0x018,
359 0x115, 0x000,
360 0x116, 0x012,
361 0x117, 0x018,
362 0x04a, 0x011,
363 0x08a, 0x011,
364 0x04b, 0x000,
365 0x08b, 0x000,
366 0x048, 0x000,
367 0x088, 0x000,
368 0x04e, 0x012,
369 0x08e, 0x012,
370 0x058, 0x012,
371 0x098, 0x012,
372 0x059, 0x000,
373 0x099, 0x000,
374 0x05a, 0x003,
375 0x09a, 0x003,
376 0x05b, 0x001,
377 0x09b, 0x001,
378 0x054, 0x008,
379 0x094, 0x008,
380 0x055, 0x000,
381 0x095, 0x000,
382 0x056, 0x0c7,
383 0x096, 0x0c7,
384 0x057, 0x002,
385 0x097, 0x002,
386 0x0ff, 0x0ff,
387 0x060, 0x001,
388 0x0a0, 0x001,
389 0x061, 0x000,
390 0x0a1, 0x000,
391 0x062, 0x000,
392 0x0a2, 0x000,
393 0x063, 0x000,
394 0x0a3, 0x000,
395 0x070, 0x000,
396 0x0b0, 0x000,
397 0x071, 0x004,
398 0x0b1, 0x004,
399 0x06c, 0x0e9,
400 0x0ac, 0x0e9,
401 0x06d, 0x003,
402 0x0ad, 0x003,
403 0x05c, 0x0d0,
404 0x09c, 0x0d0,
405 0x05d, 0x002,
406 0x09d, 0x002,
407 0x05e, 0x0f2,
408 0x09e, 0x0f2,
409 0x05f, 0x000,
410 0x09f, 0x000,
411 0x074, 0x000,
412 0x0b4, 0x000,
413 0x075, 0x000,
414 0x0b5, 0x000,
415 0x076, 0x000,
416 0x0b6, 0x000,
417 0x077, 0x000,
418 0x0b7, 0x000,
419 0x195, 0x008,
420 0x0ff, 0x0ff,
421 0x108, 0x0f8,
422 0x111, 0x000,
423 0x10e, 0x00a,
424 0x2a9, 0x0fd,
425 0x464, 0x001,
426 0x454, 0x042135,
427 0x598, 0x0e7,
428 0x599, 0x07d,
429 0x59a, 0x018,
430 0x59c, 0x066,
431 0x59d, 0x090,
432 0x59e, 0x001,
433 0x584, 0x000,
434 0x585, 0x000,
435 0x586, 0x003,
436 0x588, 0x0ff,
437 0x589, 0x00f,
438 0x58a, 0x000,
439 0x58b, 0x000,
440 0x58c, 0x010,
441 0x58d, 0x032,
442 0x58e, 0x054,
443 0x58f, 0x023,
444 0x590, 0x000,
445 0x595, 0x000,
446 0x596, 0x000,
447 0x597, 0x000,
448 0x464, 0x000,
449 0x46c, 0xbbbb10,
450 0x470, 0x101010,
451
452
453 0x478, 0x000,
454 0x474, 0x018,
455 0x454, 0x042135,
456 0x598, 0x0e7,
457 0x599, 0x07d,
458 0x59a, 0x018,
459 0x59c, 0x066,
460 0x59d, 0x090,
461 0x59e, 0x001,
462 0x584, 0x000,
463 0x585, 0x000,
464 0x586, 0x003,
465 0x588, 0x0ff,
466 0x589, 0x00f,
467 0x58a, 0x000,
468 0x58b, 0x000,
469 0x58c, 0x010,
470 0x58d, 0x032,
471 0x58e, 0x054,
472 0x58f, 0x023,
473 0x590, 0x000,
474 0x595, 0x000,
475 0x596, 0x000,
476 0x597, 0x000,
477 0x464, 0x000,
478 0x46c, 0xbbbb10,
479 0x470, 0x101010,
480
481 0x478, 0x000,
482 0x474, 0x018,
483 0x454, 0x042135,
484 0x598, 0x0e7,
485 0x599, 0x07d,
486 0x59a, 0x018,
487 0x59c, 0x066,
488 0x59d, 0x090,
489 0x59e, 0x001,
490 0x584, 0x000,
491 0x585, 0x000,
492 0x586, 0x003,
493 0x588, 0x0ff,
494 0x589, 0x00f,
495 0x58a, 0x000,
496 0x58b, 0x000,
497 0x58c, 0x010,
498 0x58d, 0x032,
499 0x58e, 0x054,
500 0x58f, 0x023,
501 0x590, 0x000,
502 0x595, 0x000,
503 0x596, 0x000,
504 0x597, 0x000,
505 0x464, 0x000,
506 0x46c, 0xbbbb10,
507 0x470, 0x101010,
508 0x478, 0x000,
509 0x474, 0x018,
510 0x454, 0x042135,
511 0x193, 0x000,
512 0x300, 0x000,
513 0x301, 0x006,
514 0x302, 0x000,
515 0x303, 0x006,
516 0x308, 0x040,
517 0x309, 0x000,
518 0x30a, 0x000,
519 0x30b, 0x000,
520 0x000, 0x002,
521 0x001, 0x000,
522 0x002, 0x000,
523 0x003, 0x000,
524 0x004, 0x033,
525 0x040, 0x01d,
526 0x041, 0x001,
527 0x042, 0x004,
528 0x043, 0x000,
529 0x080, 0x01e,
530 0x081, 0x001,
531 0x082, 0x004,
532 0x083, 0x000,
533 0x190, 0x018,
534 0x115, 0x000,
535 0x116, 0x012,
536 0x117, 0x018,
537 0x04a, 0x011,
538 0x08a, 0x011,
539 0x04b, 0x000,
540 0x08b, 0x000,
541 0x048, 0x000,
542 0x088, 0x000,
543 0x04e, 0x012,
544 0x08e, 0x012,
545 0x058, 0x012,
546 0x098, 0x012,
547 0x059, 0x000,
548 0x099, 0x000,
549 0x05a, 0x003,
550 0x09a, 0x003,
551 0x05b, 0x001,
552 0x09b, 0x001,
553 0x054, 0x008,
554 0x094, 0x008,
555 0x055, 0x000,
556 0x095, 0x000,
557 0x056, 0x0c7,
558 0x096, 0x0c7,
559 0x057, 0x002,
560 0x097, 0x002,
561 0x060, 0x001,
562 0x0a0, 0x001,
563 0x061, 0x000,
564 0x0a1, 0x000,
565 0x062, 0x000,
566 0x0a2, 0x000,
567 0x063, 0x000,
568 0x0a3, 0x000,
569 0x070, 0x000,
570 0x0b0, 0x000,
571 0x071, 0x004,
572 0x0b1, 0x004,
573 0x06c, 0x0e9,
574 0x0ac, 0x0e9,
575 0x06d, 0x003,
576 0x0ad, 0x003,
577 0x05c, 0x0d0,
578 0x09c, 0x0d0,
579 0x05d, 0x002,
580 0x09d, 0x002,
581 0x05e, 0x0f2,
582 0x09e, 0x0f2,
583 0x05f, 0x000,
584 0x09f, 0x000,
585 0x074, 0x000,
586 0x0b4, 0x000,
587 0x075, 0x000,
588 0x0b5, 0x000,
589 0x076, 0x000,
590 0x0b6, 0x000,
591 0x077, 0x000,
592 0x0b7, 0x000,
593 0x195, 0x008,
594 0x598, 0x0e7,
595 0x599, 0x07d,
596 0x59a, 0x018,
597 0x59c, 0x066,
598 0x59d, 0x090,
599 0x59e, 0x001,
600 0x584, 0x000,
601 0x585, 0x000,
602 0x586, 0x003,
603 0x588, 0x0ff,
604 0x589, 0x00f,
605 0x58a, 0x000,
606 0x58b, 0x000,
607 0x58c, 0x010,
608 0x58d, 0x032,
609 0x58e, 0x054,
610 0x58f, 0x023,
611 0x590, 0x000,
612 0x595, 0x000,
613 0x596, 0x000,
614 0x597, 0x000,
615 0x464, 0x000,
616 0x46c, 0xbbbb10,
617 0x470, 0x101010,
618 0x478, 0x000,
619 0x474, 0x018,
620 0x454, 0x042135,
621 0x193, 0x0a6,
622 0x108, 0x0f8,
623 0x042, 0x003,
624 0x082, 0x003,
625 0x454, 0x0425b9,
626 0x454, 0x042539,
627 0x193, 0x000,
628 0x193, 0x0a6,
629 0x464, 0x000,
630
631 0, 0
632};
633
634/* Tuner */
635static u32 reg_init_tuner_input[] = {
636 0x108, 0x0f8, /* Sync control */
637 0x111, 0x000, /* Mode/delay control */
638 0x10e, 0x00a, /* Chroma control 1 */
639 0, 0
640};
641
642/* Composite */
643static u32 reg_init_composite_input[] = {
644 0x108, 0x0e8, /* Sync control */
645 0x111, 0x000, /* Mode/delay control */
646 0x10e, 0x04a, /* Chroma control 1 */
647 0, 0
648};
649
650/* S-Video */
651static u32 reg_init_svideo_input[] = {
652 0x108, 0x0e8, /* Sync control */
653 0x111, 0x000, /* Mode/delay control */
654 0x10e, 0x04a, /* Chroma control 1 */
655 0, 0
656};
657
658static u32 reg_set_audio_template[4][2] =
659{
660 { /* for MONO
661 tadachi 6/29 DMA audio output select?
662 Register 0x46c
663 7-4: DMA2, 3-0: DMA1 ch. DMA4, DMA3 DMA2, DMA1
664 0: MAIN left, 1: MAIN right
665 2: AUX1 left, 3: AUX1 right
666 4: AUX2 left, 5: AUX2 right
667 6: DPL left, 7: DPL right
668 8: DPL center, 9: DPL surround
669 A: monitor output, B: digital sense */
670 0xbbbb00,
671
672 /* tadachi 6/29 DAC and I2S output select?
673 Register 0x470
674 7-4:DAC right ch. 3-0:DAC left ch.
675 I2S1 right,left I2S2 right,left */
676 0x00,
677 },
678 { /* for STEREO */
679 0xbbbb10, 0x101010,
680 },
681 { /* for LANG1 */
682 0xbbbb00, 0x00,
683 },
684 { /* for LANG2/SAP */
685 0xbbbb11, 0x111111,
686 }
687};
688
689
690/* Get detected audio flags (from saa7134 driver) */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300691static void get_inf_dev_status(struct v4l2_subdev *sd,
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300692 int *dual_flag, int *stereo_flag)
693{
694 u32 reg_data3;
695
696 static char *stdres[0x20] = {
697 [0x00] = "no standard detected",
698 [0x01] = "B/G (in progress)",
699 [0x02] = "D/K (in progress)",
700 [0x03] = "M (in progress)",
701
702 [0x04] = "B/G A2",
703 [0x05] = "B/G NICAM",
704 [0x06] = "D/K A2 (1)",
705 [0x07] = "D/K A2 (2)",
706 [0x08] = "D/K A2 (3)",
707 [0x09] = "D/K NICAM",
708 [0x0a] = "L NICAM",
709 [0x0b] = "I NICAM",
710
711 [0x0c] = "M Korea",
712 [0x0d] = "M BTSC ",
713 [0x0e] = "M EIAJ",
714
715 [0x0f] = "FM radio / IF 10.7 / 50 deemp",
716 [0x10] = "FM radio / IF 10.7 / 75 deemp",
717 [0x11] = "FM radio / IF sel / 50 deemp",
718 [0x12] = "FM radio / IF sel / 75 deemp",
719
720 [0x13 ... 0x1e] = "unknown",
721 [0x1f] = "??? [in progress]",
722 };
723
724
725 *dual_flag = *stereo_flag = 0;
726
727 /* (demdec status: 0x528) */
728
729 /* read current status */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300730 reg_data3 = saa717x_read(sd, 0x0528);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300731
Hans Verkuil27760fc2008-11-29 12:57:44 -0300732 v4l2_dbg(1, debug, sd, "tvaudio thread status: 0x%x [%s%s%s]\n",
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300733 reg_data3, stdres[reg_data3 & 0x1f],
734 (reg_data3 & 0x000020) ? ",stereo" : "",
735 (reg_data3 & 0x000040) ? ",dual" : "");
Hans Verkuil27760fc2008-11-29 12:57:44 -0300736 v4l2_dbg(1, debug, sd, "detailed status: "
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300737 "%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s\n",
738 (reg_data3 & 0x000080) ? " A2/EIAJ pilot tone " : "",
739 (reg_data3 & 0x000100) ? " A2/EIAJ dual " : "",
740 (reg_data3 & 0x000200) ? " A2/EIAJ stereo " : "",
741 (reg_data3 & 0x000400) ? " A2/EIAJ noise mute " : "",
742
743 (reg_data3 & 0x000800) ? " BTSC/FM radio pilot " : "",
744 (reg_data3 & 0x001000) ? " SAP carrier " : "",
745 (reg_data3 & 0x002000) ? " BTSC stereo noise mute " : "",
746 (reg_data3 & 0x004000) ? " SAP noise mute " : "",
747 (reg_data3 & 0x008000) ? " VDSP " : "",
748
749 (reg_data3 & 0x010000) ? " NICST " : "",
750 (reg_data3 & 0x020000) ? " NICDU " : "",
751 (reg_data3 & 0x040000) ? " NICAM muted " : "",
752 (reg_data3 & 0x080000) ? " NICAM reserve sound " : "",
753
754 (reg_data3 & 0x100000) ? " init done " : "");
755
756 if (reg_data3 & 0x000220) {
Hans Verkuil27760fc2008-11-29 12:57:44 -0300757 v4l2_dbg(1, debug, sd, "ST!!!\n");
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300758 *stereo_flag = 1;
759 }
760
761 if (reg_data3 & 0x000140) {
Hans Verkuil27760fc2008-11-29 12:57:44 -0300762 v4l2_dbg(1, debug, sd, "DUAL!!!\n");
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300763 *dual_flag = 1;
764 }
765}
766
767/* regs write to set audio mode */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300768static void set_audio_mode(struct v4l2_subdev *sd, int audio_mode)
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300769{
Hans Verkuil27760fc2008-11-29 12:57:44 -0300770 v4l2_dbg(1, debug, sd, "writing registers to set audio mode by set %d\n",
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300771 audio_mode);
772
Hans Verkuil27760fc2008-11-29 12:57:44 -0300773 saa717x_write(sd, 0x46c, reg_set_audio_template[audio_mode][0]);
774 saa717x_write(sd, 0x470, reg_set_audio_template[audio_mode][1]);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300775}
776
777/* write regs to video output level (bright,contrast,hue,sat) */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300778static void set_video_output_level_regs(struct v4l2_subdev *sd,
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300779 struct saa717x_state *decoder)
780{
781 /* brightness ffh (bright) - 80h (ITU level) - 00h (dark) */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300782 saa717x_write(sd, 0x10a, decoder->bright);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300783
784 /* contrast 7fh (max: 1.984) - 44h (ITU) - 40h (1.0) -
785 0h (luminance off) 40: i2c dump
786 c0h (-1.0 inverse chrominance)
787 80h (-2.0 inverse chrominance) */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300788 saa717x_write(sd, 0x10b, decoder->contrast);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300789
790 /* saturation? 7fh(max)-40h(ITU)-0h(color off)
791 c0h (-1.0 inverse chrominance)
792 80h (-2.0 inverse chrominance) */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300793 saa717x_write(sd, 0x10c, decoder->sat);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300794
795 /* color hue (phase) control
796 7fh (+178.6) - 0h (0 normal) - 80h (-180.0) */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300797 saa717x_write(sd, 0x10d, decoder->hue);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300798}
799
800/* write regs to set audio volume, bass and treble */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300801static int set_audio_regs(struct v4l2_subdev *sd,
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300802 struct saa717x_state *decoder)
803{
804 u8 mute = 0xac; /* -84 dB */
805 u32 val;
806 unsigned int work_l, work_r;
807
808 /* set SIF analog I/O select */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300809 saa717x_write(sd, 0x0594, decoder->audio_input);
810 v4l2_dbg(1, debug, sd, "set audio input %d\n",
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300811 decoder->audio_input);
812
813 /* normalize ( 65535 to 0 -> 24 to -40 (not -84)) */
814 work_l = (min(65536 - decoder->audio_main_balance, 32768) * decoder->audio_main_volume) / 32768;
815 work_r = (min(decoder->audio_main_balance, (u16)32768) * decoder->audio_main_volume) / 32768;
816 decoder->audio_main_vol_l = (long)work_l * (24 - (-40)) / 65535 - 40;
817 decoder->audio_main_vol_r = (long)work_r * (24 - (-40)) / 65535 - 40;
818
819 /* set main volume */
820 /* main volume L[7-0],R[7-0],0x00 24=24dB,-83dB, -84(mute) */
821 /* def:0dB->6dB(MPG600GR) */
822 /* if mute is on, set mute */
823 if (decoder->audio_main_mute) {
824 val = mute | (mute << 8);
825 } else {
826 val = (u8)decoder->audio_main_vol_l |
827 ((u8)decoder->audio_main_vol_r << 8);
828 }
829
Hans Verkuil27760fc2008-11-29 12:57:44 -0300830 saa717x_write(sd, 0x480, val);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300831
832 /* bass and treble; go to another function */
833 /* set bass and treble */
834 val = decoder->audio_main_bass | (decoder->audio_main_treble << 8);
Hans Verkuil27760fc2008-11-29 12:57:44 -0300835 saa717x_write(sd, 0x488, val);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300836 return 0;
837}
838
839/********** scaling staff ***********/
Hans Verkuil27760fc2008-11-29 12:57:44 -0300840static void set_h_prescale(struct v4l2_subdev *sd,
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300841 int task, int prescale)
842{
843 static const struct {
844 int xpsc;
845 int xacl;
846 int xc2_1;
847 int xdcg;
848 int vpfy;
849 } vals[] = {
850 /* XPSC XACL XC2_1 XDCG VPFY */
851 { 1, 0, 0, 0, 0 },
852 { 2, 2, 1, 2, 2 },
853 { 3, 4, 1, 3, 2 },
854 { 4, 8, 1, 4, 2 },
855 { 5, 8, 1, 4, 2 },
856 { 6, 8, 1, 4, 3 },
857 { 7, 8, 1, 4, 3 },
858 { 8, 15, 0, 4, 3 },
859 { 9, 15, 0, 4, 3 },
860 { 10, 16, 1, 5, 3 },
861 };
862 static const int count = ARRAY_SIZE(vals);
863 int i, task_shift;
864
865 task_shift = task * 0x40;
866 for (i = 0; i < count; i++)
867 if (vals[i].xpsc == prescale)
868 break;
869 if (i == count)
870 return;
871
872 /* horizonal prescaling */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300873 saa717x_write(sd, 0x60 + task_shift, vals[i].xpsc);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300874 /* accumulation length */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300875 saa717x_write(sd, 0x61 + task_shift, vals[i].xacl);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300876 /* level control */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300877 saa717x_write(sd, 0x62 + task_shift,
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300878 (vals[i].xc2_1 << 3) | vals[i].xdcg);
879 /*FIR prefilter control */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300880 saa717x_write(sd, 0x63 + task_shift,
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300881 (vals[i].vpfy << 2) | vals[i].vpfy);
882}
883
884/********** scaling staff ***********/
Hans Verkuil27760fc2008-11-29 12:57:44 -0300885static void set_v_scale(struct v4l2_subdev *sd, int task, int yscale)
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300886{
887 int task_shift;
888
889 task_shift = task * 0x40;
890 /* Vertical scaling ratio (LOW) */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300891 saa717x_write(sd, 0x70 + task_shift, yscale & 0xff);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300892 /* Vertical scaling ratio (HI) */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300893 saa717x_write(sd, 0x71 + task_shift, yscale >> 8);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300894}
895
Hans Verkuil27760fc2008-11-29 12:57:44 -0300896static int saa717x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300897{
Hans Verkuil27760fc2008-11-29 12:57:44 -0300898 struct saa717x_state *state = to_state(sd);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300899
900 switch (ctrl->id) {
901 case V4L2_CID_BRIGHTNESS:
902 if (ctrl->value < 0 || ctrl->value > 255) {
Hans Verkuil27760fc2008-11-29 12:57:44 -0300903 v4l2_err(sd, "invalid brightness setting %d\n", ctrl->value);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300904 return -ERANGE;
905 }
906
907 state->bright = ctrl->value;
Hans Verkuil27760fc2008-11-29 12:57:44 -0300908 v4l2_dbg(1, debug, sd, "bright:%d\n", state->bright);
909 saa717x_write(sd, 0x10a, state->bright);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300910 break;
911
912 case V4L2_CID_CONTRAST:
913 if (ctrl->value < 0 || ctrl->value > 127) {
Hans Verkuil27760fc2008-11-29 12:57:44 -0300914 v4l2_err(sd, "invalid contrast setting %d\n", ctrl->value);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300915 return -ERANGE;
916 }
917
918 state->contrast = ctrl->value;
Hans Verkuil27760fc2008-11-29 12:57:44 -0300919 v4l2_dbg(1, debug, sd, "contrast:%d\n", state->contrast);
920 saa717x_write(sd, 0x10b, state->contrast);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300921 break;
922
923 case V4L2_CID_SATURATION:
924 if (ctrl->value < 0 || ctrl->value > 127) {
Hans Verkuil27760fc2008-11-29 12:57:44 -0300925 v4l2_err(sd, "invalid saturation setting %d\n", ctrl->value);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300926 return -ERANGE;
927 }
928
929 state->sat = ctrl->value;
Hans Verkuil27760fc2008-11-29 12:57:44 -0300930 v4l2_dbg(1, debug, sd, "sat:%d\n", state->sat);
931 saa717x_write(sd, 0x10c, state->sat);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300932 break;
933
934 case V4L2_CID_HUE:
935 if (ctrl->value < -127 || ctrl->value > 127) {
Hans Verkuil27760fc2008-11-29 12:57:44 -0300936 v4l2_err(sd, "invalid hue setting %d\n", ctrl->value);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300937 return -ERANGE;
938 }
939
940 state->hue = ctrl->value;
Hans Verkuil27760fc2008-11-29 12:57:44 -0300941 v4l2_dbg(1, debug, sd, "hue:%d\n", state->hue);
942 saa717x_write(sd, 0x10d, state->hue);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300943 break;
944
945 case V4L2_CID_AUDIO_MUTE:
946 state->audio_main_mute = ctrl->value;
Hans Verkuil27760fc2008-11-29 12:57:44 -0300947 set_audio_regs(sd, state);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300948 break;
949
950 case V4L2_CID_AUDIO_VOLUME:
951 state->audio_main_volume = ctrl->value;
Hans Verkuil27760fc2008-11-29 12:57:44 -0300952 set_audio_regs(sd, state);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300953 break;
954
955 case V4L2_CID_AUDIO_BALANCE:
956 state->audio_main_balance = ctrl->value;
Hans Verkuil27760fc2008-11-29 12:57:44 -0300957 set_audio_regs(sd, state);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300958 break;
959
960 case V4L2_CID_AUDIO_TREBLE:
961 state->audio_main_treble = ctrl->value;
Hans Verkuil27760fc2008-11-29 12:57:44 -0300962 set_audio_regs(sd, state);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300963 break;
964
965 case V4L2_CID_AUDIO_BASS:
966 state->audio_main_bass = ctrl->value;
Hans Verkuil27760fc2008-11-29 12:57:44 -0300967 set_audio_regs(sd, state);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300968 break;
969
970 default:
971 return -EINVAL;
972 }
973
974 return 0;
975}
976
Hans Verkuil27760fc2008-11-29 12:57:44 -0300977static int saa717x_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300978{
Hans Verkuil27760fc2008-11-29 12:57:44 -0300979 struct saa717x_state *state = to_state(sd);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300980
981 switch (ctrl->id) {
982 case V4L2_CID_BRIGHTNESS:
983 ctrl->value = state->bright;
984 break;
985
986 case V4L2_CID_CONTRAST:
987 ctrl->value = state->contrast;
988 break;
989
990 case V4L2_CID_SATURATION:
991 ctrl->value = state->sat;
992 break;
993
994 case V4L2_CID_HUE:
995 ctrl->value = state->hue;
996 break;
997
998 case V4L2_CID_AUDIO_MUTE:
999 ctrl->value = state->audio_main_mute;
1000 break;
1001
1002 case V4L2_CID_AUDIO_VOLUME:
1003 ctrl->value = state->audio_main_volume;
1004 break;
1005
1006 case V4L2_CID_AUDIO_BALANCE:
1007 ctrl->value = state->audio_main_balance;
1008 break;
1009
1010 case V4L2_CID_AUDIO_TREBLE:
1011 ctrl->value = state->audio_main_treble;
1012 break;
1013
1014 case V4L2_CID_AUDIO_BASS:
1015 ctrl->value = state->audio_main_bass;
1016 break;
1017
1018 default:
1019 return -EINVAL;
1020 }
1021
1022 return 0;
1023}
1024
1025static struct v4l2_queryctrl saa717x_qctrl[] = {
1026 {
1027 .id = V4L2_CID_BRIGHTNESS,
1028 .type = V4L2_CTRL_TYPE_INTEGER,
1029 .name = "Brightness",
1030 .minimum = 0,
1031 .maximum = 255,
1032 .step = 1,
1033 .default_value = 128,
1034 .flags = 0,
1035 }, {
1036 .id = V4L2_CID_CONTRAST,
1037 .type = V4L2_CTRL_TYPE_INTEGER,
1038 .name = "Contrast",
1039 .minimum = 0,
1040 .maximum = 255,
1041 .step = 1,
1042 .default_value = 64,
1043 .flags = 0,
1044 }, {
1045 .id = V4L2_CID_SATURATION,
1046 .type = V4L2_CTRL_TYPE_INTEGER,
1047 .name = "Saturation",
1048 .minimum = 0,
1049 .maximum = 255,
1050 .step = 1,
1051 .default_value = 64,
1052 .flags = 0,
1053 }, {
1054 .id = V4L2_CID_HUE,
1055 .type = V4L2_CTRL_TYPE_INTEGER,
1056 .name = "Hue",
1057 .minimum = -128,
1058 .maximum = 127,
1059 .step = 1,
1060 .default_value = 0,
1061 .flags = 0,
1062 }, {
1063 .id = V4L2_CID_AUDIO_VOLUME,
1064 .type = V4L2_CTRL_TYPE_INTEGER,
1065 .name = "Volume",
1066 .minimum = 0,
1067 .maximum = 65535,
1068 .step = 65535 / 100,
1069 .default_value = 58880,
1070 .flags = 0,
1071 }, {
1072 .id = V4L2_CID_AUDIO_BALANCE,
1073 .type = V4L2_CTRL_TYPE_INTEGER,
1074 .name = "Balance",
1075 .minimum = 0,
1076 .maximum = 65535,
1077 .step = 65535 / 100,
1078 .default_value = 32768,
1079 .flags = 0,
1080 }, {
1081 .id = V4L2_CID_AUDIO_MUTE,
1082 .type = V4L2_CTRL_TYPE_BOOLEAN,
1083 .name = "Mute",
1084 .minimum = 0,
1085 .maximum = 1,
1086 .step = 1,
1087 .default_value = 1,
1088 .flags = 0,
1089 }, {
1090 .id = V4L2_CID_AUDIO_BASS,
1091 .type = V4L2_CTRL_TYPE_INTEGER,
1092 .name = "Bass",
1093 .minimum = 0,
1094 .maximum = 65535,
1095 .step = 65535 / 100,
1096 .default_value = 32768,
1097 }, {
1098 .id = V4L2_CID_AUDIO_TREBLE,
1099 .type = V4L2_CTRL_TYPE_INTEGER,
1100 .name = "Treble",
1101 .minimum = 0,
1102 .maximum = 65535,
1103 .step = 65535 / 100,
1104 .default_value = 32768,
1105 },
1106};
1107
Hans Verkuil27760fc2008-11-29 12:57:44 -03001108static int saa717x_s_video_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001109{
Hans Verkuil27760fc2008-11-29 12:57:44 -03001110 struct saa717x_state *decoder = to_state(sd);
1111 int inp = route->input;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001112 int is_tuner = inp & 0x80; /* tuner input flag */
1113
1114 inp &= 0x7f;
1115
Hans Verkuil27760fc2008-11-29 12:57:44 -03001116 v4l2_dbg(1, debug, sd, "decoder set input (%d)\n", inp);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001117 /* inputs from 0-9 are available*/
1118 /* saa717x have mode0-mode9 but mode5 is reserved. */
1119 if (inp < 0 || inp > 9 || inp == 5)
1120 return -EINVAL;
1121
1122 if (decoder->input != inp) {
1123 int input_line = inp;
1124
1125 decoder->input = input_line;
Hans Verkuil27760fc2008-11-29 12:57:44 -03001126 v4l2_dbg(1, debug, sd, "now setting %s input %d\n",
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001127 input_line >= 6 ? "S-Video" : "Composite",
1128 input_line);
1129
1130 /* select mode */
Hans Verkuil27760fc2008-11-29 12:57:44 -03001131 saa717x_write(sd, 0x102,
1132 (saa717x_read(sd, 0x102) & 0xf0) |
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001133 input_line);
1134
1135 /* bypass chrominance trap for modes 6..9 */
Hans Verkuil27760fc2008-11-29 12:57:44 -03001136 saa717x_write(sd, 0x109,
1137 (saa717x_read(sd, 0x109) & 0x7f) |
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001138 (input_line < 6 ? 0x0 : 0x80));
1139
1140 /* change audio_mode */
1141 if (is_tuner) {
1142 /* tuner */
Hans Verkuil27760fc2008-11-29 12:57:44 -03001143 set_audio_mode(sd, decoder->tuner_audio_mode);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001144 } else {
1145 /* Force to STEREO mode if Composite or
1146 * S-Video were chosen */
Hans Verkuil27760fc2008-11-29 12:57:44 -03001147 set_audio_mode(sd, TUNER_AUDIO_STEREO);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001148 }
1149 /* change initialize procedure (Composite/S-Video) */
1150 if (is_tuner)
Hans Verkuil27760fc2008-11-29 12:57:44 -03001151 saa717x_write_regs(sd, reg_init_tuner_input);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001152 else if (input_line >= 6)
Hans Verkuil27760fc2008-11-29 12:57:44 -03001153 saa717x_write_regs(sd, reg_init_svideo_input);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001154 else
Hans Verkuil27760fc2008-11-29 12:57:44 -03001155 saa717x_write_regs(sd, reg_init_composite_input);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001156 }
1157
1158 return 0;
1159}
1160
Hans Verkuil27760fc2008-11-29 12:57:44 -03001161static int saa717x_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001162{
Hans Verkuil27760fc2008-11-29 12:57:44 -03001163 int i;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001164
Hans Verkuil27760fc2008-11-29 12:57:44 -03001165 for (i = 0; i < ARRAY_SIZE(saa717x_qctrl); i++)
1166 if (qc->id && qc->id == saa717x_qctrl[i].id) {
1167 memcpy(qc, &saa717x_qctrl[i], sizeof(*qc));
1168 return 0;
1169 }
1170 return -EINVAL;
1171}
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001172
1173#ifdef CONFIG_VIDEO_ADV_DEBUG
Hans Verkuilaecde8b2008-12-30 07:14:19 -03001174static int saa717x_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
Hans Verkuil27760fc2008-11-29 12:57:44 -03001175{
1176 struct i2c_client *client = v4l2_get_subdevdata(sd);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001177
Hans Verkuilaecde8b2008-12-30 07:14:19 -03001178 if (!v4l2_chip_match_i2c_client(client, &reg->match))
Hans Verkuil27760fc2008-11-29 12:57:44 -03001179 return -EINVAL;
1180 if (!capable(CAP_SYS_ADMIN))
1181 return -EPERM;
1182 reg->val = saa717x_read(sd, reg->reg);
Hans Verkuilaecde8b2008-12-30 07:14:19 -03001183 reg->size = 1;
Hans Verkuil27760fc2008-11-29 12:57:44 -03001184 return 0;
1185}
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001186
Hans Verkuilaecde8b2008-12-30 07:14:19 -03001187static int saa717x_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
Hans Verkuil27760fc2008-11-29 12:57:44 -03001188{
1189 struct i2c_client *client = v4l2_get_subdevdata(sd);
1190 u16 addr = reg->reg & 0xffff;
1191 u8 val = reg->val & 0xff;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001192
Hans Verkuilaecde8b2008-12-30 07:14:19 -03001193 if (!v4l2_chip_match_i2c_client(client, &reg->match))
Hans Verkuil27760fc2008-11-29 12:57:44 -03001194 return -EINVAL;
1195 if (!capable(CAP_SYS_ADMIN))
1196 return -EPERM;
1197 saa717x_write(sd, addr, val);
1198 return 0;
1199}
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001200#endif
1201
Hans Verkuil27760fc2008-11-29 12:57:44 -03001202static int saa717x_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
1203{
1204 struct v4l2_pix_format *pix;
1205 int prescale, h_scale, v_scale;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001206
Hans Verkuil27760fc2008-11-29 12:57:44 -03001207 pix = &fmt->fmt.pix;
1208 v4l2_dbg(1, debug, sd, "decoder set size\n");
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001209
Hans Verkuil27760fc2008-11-29 12:57:44 -03001210 /* FIXME need better bounds checking here */
1211 if (pix->width < 1 || pix->width > 1440)
1212 return -EINVAL;
1213 if (pix->height < 1 || pix->height > 960)
1214 return -EINVAL;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001215
Hans Verkuil27760fc2008-11-29 12:57:44 -03001216 /* scaling setting */
1217 /* NTSC and interlace only */
1218 prescale = SAA717X_NTSC_WIDTH / pix->width;
1219 if (prescale == 0)
1220 prescale = 1;
1221 h_scale = 1024 * SAA717X_NTSC_WIDTH / prescale / pix->width;
1222 /* interlace */
1223 v_scale = 512 * 2 * SAA717X_NTSC_HEIGHT / pix->height;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001224
Hans Verkuil27760fc2008-11-29 12:57:44 -03001225 /* Horizontal prescaling etc */
1226 set_h_prescale(sd, 0, prescale);
1227 set_h_prescale(sd, 1, prescale);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001228
Hans Verkuil27760fc2008-11-29 12:57:44 -03001229 /* Horizontal scaling increment */
1230 /* TASK A */
1231 saa717x_write(sd, 0x6C, (u8)(h_scale & 0xFF));
1232 saa717x_write(sd, 0x6D, (u8)((h_scale >> 8) & 0xFF));
1233 /* TASK B */
1234 saa717x_write(sd, 0xAC, (u8)(h_scale & 0xFF));
1235 saa717x_write(sd, 0xAD, (u8)((h_scale >> 8) & 0xFF));
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001236
Hans Verkuil27760fc2008-11-29 12:57:44 -03001237 /* Vertical prescaling etc */
1238 set_v_scale(sd, 0, v_scale);
1239 set_v_scale(sd, 1, v_scale);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001240
Hans Verkuil27760fc2008-11-29 12:57:44 -03001241 /* set video output size */
1242 /* video number of pixels at output */
1243 /* TASK A */
1244 saa717x_write(sd, 0x5C, (u8)(pix->width & 0xFF));
1245 saa717x_write(sd, 0x5D, (u8)((pix->width >> 8) & 0xFF));
1246 /* TASK B */
1247 saa717x_write(sd, 0x9C, (u8)(pix->width & 0xFF));
1248 saa717x_write(sd, 0x9D, (u8)((pix->width >> 8) & 0xFF));
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001249
Hans Verkuil27760fc2008-11-29 12:57:44 -03001250 /* video number of lines at output */
1251 /* TASK A */
1252 saa717x_write(sd, 0x5E, (u8)(pix->height & 0xFF));
1253 saa717x_write(sd, 0x5F, (u8)((pix->height >> 8) & 0xFF));
1254 /* TASK B */
1255 saa717x_write(sd, 0x9E, (u8)(pix->height & 0xFF));
1256 saa717x_write(sd, 0x9F, (u8)((pix->height >> 8) & 0xFF));
1257 return 0;
1258}
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001259
Hans Verkuil27760fc2008-11-29 12:57:44 -03001260static int saa717x_s_radio(struct v4l2_subdev *sd)
1261{
1262 struct saa717x_state *decoder = to_state(sd);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001263
Hans Verkuil27760fc2008-11-29 12:57:44 -03001264 decoder->radio = 1;
1265 return 0;
1266}
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001267
Hans Verkuil27760fc2008-11-29 12:57:44 -03001268static int saa717x_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
1269{
1270 struct saa717x_state *decoder = to_state(sd);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001271
Hans Verkuil27760fc2008-11-29 12:57:44 -03001272 v4l2_dbg(1, debug, sd, "decoder set norm ");
1273 v4l2_dbg(1, debug, sd, "(not yet implementd)\n");
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001274
Hans Verkuil27760fc2008-11-29 12:57:44 -03001275 decoder->radio = 0;
1276 decoder->std = std;
1277 return 0;
1278}
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001279
Hans Verkuil27760fc2008-11-29 12:57:44 -03001280static int saa717x_s_audio_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
1281{
1282 struct saa717x_state *decoder = to_state(sd);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001283
Hans Verkuil27760fc2008-11-29 12:57:44 -03001284 if (route->input < 3) { /* FIXME! --tadachi */
1285 decoder->audio_input = route->input;
1286 v4l2_dbg(1, debug, sd,
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001287 "set decoder audio input to %d\n",
1288 decoder->audio_input);
Hans Verkuil27760fc2008-11-29 12:57:44 -03001289 set_audio_regs(sd, decoder);
1290 return 0;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001291 }
Hans Verkuil27760fc2008-11-29 12:57:44 -03001292 return -ERANGE;
1293}
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001294
Hans Verkuil27760fc2008-11-29 12:57:44 -03001295static int saa717x_s_stream(struct v4l2_subdev *sd, int enable)
1296{
1297 struct saa717x_state *decoder = to_state(sd);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001298
Hans Verkuil27760fc2008-11-29 12:57:44 -03001299 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}
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001305
Hans Verkuil27760fc2008-11-29 12:57:44 -03001306/* 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 };
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001314
Hans Verkuil27760fc2008-11-29 12:57:44 -03001315 audio_mode = V4L2_TUNER_MODE_STEREO;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001316
Hans Verkuil27760fc2008-11-29 12:57:44 -03001317 switch (vt->audmode) {
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001318 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;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001330 }
1331
Hans Verkuil27760fc2008-11-29 12:57:44 -03001332 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);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001338 return 0;
1339}
1340
Hans Verkuil27760fc2008-11-29 12:57:44 -03001341static 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;
1345
1346 if (decoder->radio)
1347 return 0;
1348 get_inf_dev_status(sd, &dual_f, &stereo_f);
1349
1350 v4l2_dbg(1, debug, sd, "DETECT==st:%d dual:%d\n",
1351 stereo_f, dual_f);
1352
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 }
1358
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");
1368 }
1369 }
1370
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 }
1380 }
1381 return 0;
1382}
1383
1384static int saa717x_command(struct i2c_client *client, unsigned cmd, void *arg)
1385{
1386 return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
1387}
1388
1389/* ----------------------------------------------------------------------- */
1390
1391static const struct v4l2_subdev_core_ops saa717x_core_ops = {
1392#ifdef CONFIG_VIDEO_ADV_DEBUG
1393 .g_register = saa717x_g_register,
1394 .s_register = saa717x_s_register,
1395#endif
1396 .queryctrl = saa717x_queryctrl,
1397 .g_ctrl = saa717x_g_ctrl,
1398 .s_ctrl = saa717x_s_ctrl,
1399};
1400
1401static const struct v4l2_subdev_tuner_ops saa717x_tuner_ops = {
1402 .g_tuner = saa717x_g_tuner,
1403 .s_tuner = saa717x_s_tuner,
1404 .s_std = saa717x_s_std,
1405 .s_radio = saa717x_s_radio,
1406};
1407
1408static const struct v4l2_subdev_video_ops saa717x_video_ops = {
1409 .s_routing = saa717x_s_video_routing,
1410 .s_fmt = saa717x_s_fmt,
1411 .s_stream = saa717x_s_stream,
1412};
1413
1414static const struct v4l2_subdev_audio_ops saa717x_audio_ops = {
1415 .s_routing = saa717x_s_audio_routing,
1416};
1417
1418static const struct v4l2_subdev_ops saa717x_ops = {
1419 .core = &saa717x_core_ops,
1420 .tuner = &saa717x_tuner_ops,
1421 .audio = &saa717x_audio_ops,
1422 .video = &saa717x_video_ops,
1423};
1424
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001425/* ----------------------------------------------------------------------- */
1426
1427
1428/* i2c implementation */
1429
1430/* ----------------------------------------------------------------------- */
Jean Delvared2653e92008-04-29 23:11:39 +02001431static int saa717x_probe(struct i2c_client *client,
1432 const struct i2c_device_id *did)
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001433{
1434 struct saa717x_state *decoder;
Hans Verkuil27760fc2008-11-29 12:57:44 -03001435 struct v4l2_subdev *sd;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001436 u8 id = 0;
1437 char *p = "";
1438
1439 /* Check if the adapter supports the needed features */
1440 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
1441 return -EIO;
1442
Hans Verkuil27760fc2008-11-29 12:57:44 -03001443 decoder = kzalloc(sizeof(struct saa717x_state), GFP_KERNEL);
1444 if (decoder == NULL)
1445 return -ENOMEM;
1446
1447 sd = &decoder->sd;
1448 v4l2_i2c_subdev_init(sd, client, &saa717x_ops);
1449
1450 if (saa717x_write(sd, 0x5a4, 0xfe) &&
1451 saa717x_write(sd, 0x5a5, 0x0f) &&
1452 saa717x_write(sd, 0x5a6, 0x00) &&
1453 saa717x_write(sd, 0x5a7, 0x01))
1454 id = saa717x_read(sd, 0x5a0);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001455 if (id != 0xc2 && id != 0x32 && id != 0xf2 && id != 0x6c) {
Hans Verkuil27760fc2008-11-29 12:57:44 -03001456 v4l2_dbg(1, debug, sd, "saa717x not found (id=%02x)\n", id);
1457 kfree(decoder);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001458 return -ENODEV;
1459 }
1460 if (id == 0xc2)
1461 p = "saa7173";
1462 else if (id == 0x32)
1463 p = "saa7174A";
1464 else if (id == 0x6c)
1465 p = "saa7174HL";
1466 else
1467 p = "saa7171";
Hans Verkuil27760fc2008-11-29 12:57:44 -03001468 v4l2_info(sd, "%s found @ 0x%x (%s)\n", p,
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001469 client->addr << 1, client->adapter->name);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001470 decoder->std = V4L2_STD_NTSC;
1471 decoder->input = -1;
1472 decoder->enable = 1;
1473
1474 /* tune these parameters */
1475 decoder->bright = 0x80;
1476 decoder->contrast = 0x44;
1477 decoder->sat = 0x40;
1478 decoder->hue = 0x00;
1479
1480 /* FIXME!! */
1481 decoder->playback = 0; /* initially capture mode used */
1482 decoder->audio = 1; /* DECODER_AUDIO_48_KHZ */
1483
1484 decoder->audio_input = 2; /* FIXME!! */
1485
1486 decoder->tuner_audio_mode = TUNER_AUDIO_STEREO;
1487 /* set volume, bass and treble */
1488 decoder->audio_main_vol_l = 6;
1489 decoder->audio_main_vol_r = 6;
1490 decoder->audio_main_bass = 0;
1491 decoder->audio_main_treble = 0;
1492 decoder->audio_main_mute = 0;
1493 decoder->audio_main_balance = 32768;
1494 /* normalize (24 to -40 (not -84) -> 65535 to 0) */
1495 decoder->audio_main_volume =
1496 (decoder->audio_main_vol_r + 41) * 65535 / (24 - (-40));
1497
Hans Verkuil27760fc2008-11-29 12:57:44 -03001498 v4l2_dbg(1, debug, sd, "writing init values\n");
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001499
1500 /* FIXME!! */
Hans Verkuil27760fc2008-11-29 12:57:44 -03001501 saa717x_write_regs(sd, reg_init_initialize);
1502 set_video_output_level_regs(sd, decoder);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001503 /* set bass,treble to 0db 20041101 K.Ohta */
1504 decoder->audio_main_bass = 0;
1505 decoder->audio_main_treble = 0;
Hans Verkuil27760fc2008-11-29 12:57:44 -03001506 set_audio_regs(sd, decoder);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001507
1508 set_current_state(TASK_INTERRUPTIBLE);
1509 schedule_timeout(2*HZ);
1510 return 0;
1511}
1512
1513static int saa717x_remove(struct i2c_client *client)
1514{
Hans Verkuil27760fc2008-11-29 12:57:44 -03001515 struct v4l2_subdev *sd = i2c_get_clientdata(client);
1516
1517 v4l2_device_unregister_subdev(sd);
1518 kfree(to_state(sd));
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001519 return 0;
1520}
1521
1522/* ----------------------------------------------------------------------- */
1523
Jean Delvareaf294862008-05-18 20:49:40 +02001524static const struct i2c_device_id saa717x_id[] = {
1525 { "saa717x", 0 },
1526 { }
1527};
1528MODULE_DEVICE_TABLE(i2c, saa717x_id);
1529
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001530static struct v4l2_i2c_driver_data v4l2_i2c_data = {
1531 .name = "saa717x",
1532 .driverid = I2C_DRIVERID_SAA717X,
1533 .command = saa717x_command,
1534 .probe = saa717x_probe,
1535 .remove = saa717x_remove,
1536 .legacy_class = I2C_CLASS_TV_ANALOG | I2C_CLASS_TV_DIGITAL,
Jean Delvareaf294862008-05-18 20:49:40 +02001537 .id_table = saa717x_id,
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001538};