blob: 45f8bfc1342e331d13adae8c2a11ba357b1d4c5c [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>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090035#include <linux/slab.h>
Hans Verkuilfb7b37c2008-04-09 06:26:17 -030036#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 Verkuil59b83112010-04-23 09:04:48 -030041#include <media/v4l2-ctrls.h>
Hans Verkuilfb7b37c2008-04-09 06:26:17 -030042#include <media/v4l2-i2c-drv.h>
43
44MODULE_DESCRIPTION("Philips SAA717x audio/video decoder driver");
45MODULE_AUTHOR("K. Ohta, T. Adachi, Hans Verkuil");
46MODULE_LICENSE("GPL");
47
48static int debug;
49module_param(debug, int, 0644);
50MODULE_PARM_DESC(debug, "Debug level (0-1)");
51
52/*
53 * Generic i2c probe
54 * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
55 */
56
57struct saa717x_state {
Hans Verkuil27760fc2008-11-29 12:57:44 -030058 struct v4l2_subdev sd;
Hans Verkuil59b83112010-04-23 09:04:48 -030059 struct v4l2_ctrl_handler hdl;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -030060 v4l2_std_id std;
61 int input;
62 int enable;
63 int radio;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -030064 int playback;
65 int audio;
66 int tuner_audio_mode;
67 int audio_main_mute;
68 int audio_main_vol_r;
69 int audio_main_vol_l;
70 u16 audio_main_bass;
71 u16 audio_main_treble;
72 u16 audio_main_volume;
73 u16 audio_main_balance;
74 int audio_input;
75};
76
Hans Verkuil27760fc2008-11-29 12:57:44 -030077static inline struct saa717x_state *to_state(struct v4l2_subdev *sd)
78{
79 return container_of(sd, struct saa717x_state, sd);
80}
81
Hans Verkuil59b83112010-04-23 09:04:48 -030082static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
83{
84 return &container_of(ctrl->handler, struct saa717x_state, hdl)->sd;
85}
86
Hans Verkuilfb7b37c2008-04-09 06:26:17 -030087/* ----------------------------------------------------------------------- */
88
89/* for audio mode */
90#define TUNER_AUDIO_MONO 0 /* LL */
91#define TUNER_AUDIO_STEREO 1 /* LR */
92#define TUNER_AUDIO_LANG1 2 /* LL */
93#define TUNER_AUDIO_LANG2 3 /* RR */
94
95#define SAA717X_NTSC_WIDTH (704)
96#define SAA717X_NTSC_HEIGHT (480)
97
98/* ----------------------------------------------------------------------- */
99
Hans Verkuil27760fc2008-11-29 12:57:44 -0300100static int saa717x_write(struct v4l2_subdev *sd, u32 reg, u32 value)
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300101{
Hans Verkuil27760fc2008-11-29 12:57:44 -0300102 struct i2c_client *client = v4l2_get_subdevdata(sd);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300103 struct i2c_adapter *adap = client->adapter;
104 int fw_addr = reg == 0x454 || (reg >= 0x464 && reg <= 0x478) || reg == 0x480 || reg == 0x488;
105 unsigned char mm1[6];
106 struct i2c_msg msg;
107
108 msg.flags = 0;
109 msg.addr = client->addr;
110 mm1[0] = (reg >> 8) & 0xff;
111 mm1[1] = reg & 0xff;
112
113 if (fw_addr) {
114 mm1[4] = (value >> 16) & 0xff;
115 mm1[3] = (value >> 8) & 0xff;
116 mm1[2] = value & 0xff;
117 } else {
118 mm1[2] = value & 0xff;
119 }
120 msg.len = fw_addr ? 5 : 3; /* Long Registers have *only* three bytes! */
121 msg.buf = mm1;
Hans Verkuil27760fc2008-11-29 12:57:44 -0300122 v4l2_dbg(2, debug, sd, "wrote: reg 0x%03x=%08x\n", reg, value);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300123 return i2c_transfer(adap, &msg, 1) == 1;
124}
125
Hans Verkuil27760fc2008-11-29 12:57:44 -0300126static void saa717x_write_regs(struct v4l2_subdev *sd, u32 *data)
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300127{
128 while (data[0] || data[1]) {
Hans Verkuil27760fc2008-11-29 12:57:44 -0300129 saa717x_write(sd, data[0], data[1]);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300130 data += 2;
131 }
132}
133
Hans Verkuil27760fc2008-11-29 12:57:44 -0300134static u32 saa717x_read(struct v4l2_subdev *sd, u32 reg)
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300135{
Hans Verkuil27760fc2008-11-29 12:57:44 -0300136 struct i2c_client *client = v4l2_get_subdevdata(sd);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300137 struct i2c_adapter *adap = client->adapter;
138 int fw_addr = (reg >= 0x404 && reg <= 0x4b8) || reg == 0x528;
139 unsigned char mm1[2];
140 unsigned char mm2[4] = { 0, 0, 0, 0 };
141 struct i2c_msg msgs[2];
142 u32 value;
143
144 msgs[0].flags = 0;
145 msgs[1].flags = I2C_M_RD;
146 msgs[0].addr = msgs[1].addr = client->addr;
147 mm1[0] = (reg >> 8) & 0xff;
148 mm1[1] = reg & 0xff;
149 msgs[0].len = 2;
150 msgs[0].buf = mm1;
151 msgs[1].len = fw_addr ? 3 : 1; /* Multibyte Registers contains *only* 3 bytes */
152 msgs[1].buf = mm2;
153 i2c_transfer(adap, msgs, 2);
154
155 if (fw_addr)
156 value = (mm2[2] & 0xff) | ((mm2[1] & 0xff) >> 8) | ((mm2[0] & 0xff) >> 16);
157 else
158 value = mm2[0] & 0xff;
159
Hans Verkuil27760fc2008-11-29 12:57:44 -0300160 v4l2_dbg(2, debug, sd, "read: reg 0x%03x=0x%08x\n", reg, value);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300161 return value;
162}
163
164/* ----------------------------------------------------------------------- */
165
166static u32 reg_init_initialize[] =
167{
168 /* from linux driver */
169 0x101, 0x008, /* Increment delay */
170
171 0x103, 0x000, /* Analog input control 2 */
172 0x104, 0x090, /* Analog input control 3 */
173 0x105, 0x090, /* Analog input control 4 */
174 0x106, 0x0eb, /* Horizontal sync start */
175 0x107, 0x0e0, /* Horizontal sync stop */
176 0x109, 0x055, /* Luminance control */
177
178 0x10f, 0x02a, /* Chroma gain control */
179 0x110, 0x000, /* Chroma control 2 */
180
181 0x114, 0x045, /* analog/ADC */
182
183 0x118, 0x040, /* RAW data gain */
184 0x119, 0x080, /* RAW data offset */
185
186 0x044, 0x000, /* VBI horizontal input window start (L) TASK A */
187 0x045, 0x000, /* VBI horizontal input window start (H) TASK A */
188 0x046, 0x0cf, /* VBI horizontal input window stop (L) TASK A */
189 0x047, 0x002, /* VBI horizontal input window stop (H) TASK A */
190
191 0x049, 0x000, /* VBI vertical input window start (H) TASK A */
192
193 0x04c, 0x0d0, /* VBI horizontal output length (L) TASK A */
194 0x04d, 0x002, /* VBI horizontal output length (H) TASK A */
195
196 0x064, 0x080, /* Lumina brightness TASK A */
197 0x065, 0x040, /* Luminance contrast TASK A */
198 0x066, 0x040, /* Chroma saturation TASK A */
199 /* 067H: Reserved */
200 0x068, 0x000, /* VBI horizontal scaling increment (L) TASK A */
201 0x069, 0x004, /* VBI horizontal scaling increment (H) TASK A */
202 0x06a, 0x000, /* VBI phase offset TASK A */
203
204 0x06e, 0x000, /* Horizontal phase offset Luma TASK A */
205 0x06f, 0x000, /* Horizontal phase offset Chroma TASK A */
206
207 0x072, 0x000, /* Vertical filter mode TASK A */
208
209 0x084, 0x000, /* VBI horizontal input window start (L) TAKS B */
210 0x085, 0x000, /* VBI horizontal input window start (H) TAKS B */
211 0x086, 0x0cf, /* VBI horizontal input window stop (L) TAKS B */
212 0x087, 0x002, /* VBI horizontal input window stop (H) TAKS B */
213
214 0x089, 0x000, /* VBI vertical input window start (H) TAKS B */
215
216 0x08c, 0x0d0, /* VBI horizontal output length (L) TASK B */
217 0x08d, 0x002, /* VBI horizontal output length (H) TASK B */
218
219 0x0a4, 0x080, /* Lumina brightness TASK B */
220 0x0a5, 0x040, /* Luminance contrast TASK B */
221 0x0a6, 0x040, /* Chroma saturation TASK B */
222 /* 0A7H reserved */
223 0x0a8, 0x000, /* VBI horizontal scaling increment (L) TASK B */
224 0x0a9, 0x004, /* VBI horizontal scaling increment (H) TASK B */
225 0x0aa, 0x000, /* VBI phase offset TASK B */
226
227 0x0ae, 0x000, /* Horizontal phase offset Luma TASK B */
228 0x0af, 0x000, /*Horizontal phase offset Chroma TASK B */
229
230 0x0b2, 0x000, /* Vertical filter mode TASK B */
231
232 0x00c, 0x000, /* Start point GREEN path */
233 0x00d, 0x000, /* Start point BLUE path */
234 0x00e, 0x000, /* Start point RED path */
235
236 0x010, 0x010, /* GREEN path gamma curve --- */
237 0x011, 0x020,
238 0x012, 0x030,
239 0x013, 0x040,
240 0x014, 0x050,
241 0x015, 0x060,
242 0x016, 0x070,
243 0x017, 0x080,
244 0x018, 0x090,
245 0x019, 0x0a0,
246 0x01a, 0x0b0,
247 0x01b, 0x0c0,
248 0x01c, 0x0d0,
249 0x01d, 0x0e0,
250 0x01e, 0x0f0,
251 0x01f, 0x0ff, /* --- GREEN path gamma curve */
252
253 0x020, 0x010, /* BLUE path gamma curve --- */
254 0x021, 0x020,
255 0x022, 0x030,
256 0x023, 0x040,
257 0x024, 0x050,
258 0x025, 0x060,
259 0x026, 0x070,
260 0x027, 0x080,
261 0x028, 0x090,
262 0x029, 0x0a0,
263 0x02a, 0x0b0,
264 0x02b, 0x0c0,
265 0x02c, 0x0d0,
266 0x02d, 0x0e0,
267 0x02e, 0x0f0,
268 0x02f, 0x0ff, /* --- BLUE path gamma curve */
269
270 0x030, 0x010, /* RED path gamma curve --- */
271 0x031, 0x020,
272 0x032, 0x030,
273 0x033, 0x040,
274 0x034, 0x050,
275 0x035, 0x060,
276 0x036, 0x070,
277 0x037, 0x080,
278 0x038, 0x090,
279 0x039, 0x0a0,
280 0x03a, 0x0b0,
281 0x03b, 0x0c0,
282 0x03c, 0x0d0,
283 0x03d, 0x0e0,
284 0x03e, 0x0f0,
285 0x03f, 0x0ff, /* --- RED path gamma curve */
286
287 0x109, 0x085, /* Luminance control */
288
289 /**** from app start ****/
290 0x584, 0x000, /* AGC gain control */
291 0x585, 0x000, /* Program count */
292 0x586, 0x003, /* Status reset */
293 0x588, 0x0ff, /* Number of audio samples (L) */
294 0x589, 0x00f, /* Number of audio samples (M) */
295 0x58a, 0x000, /* Number of audio samples (H) */
296 0x58b, 0x000, /* Audio select */
297 0x58c, 0x010, /* Audio channel assign1 */
298 0x58d, 0x032, /* Audio channel assign2 */
299 0x58e, 0x054, /* Audio channel assign3 */
300 0x58f, 0x023, /* Audio format */
301 0x590, 0x000, /* SIF control */
302
303 0x595, 0x000, /* ?? */
304 0x596, 0x000, /* ?? */
305 0x597, 0x000, /* ?? */
306
307 0x464, 0x00, /* Digital input crossbar1 */
308
309 0x46c, 0xbbbb10, /* Digital output selection1-3 */
310 0x470, 0x101010, /* Digital output selection4-6 */
311
312 0x478, 0x00, /* Sound feature control */
313
314 0x474, 0x18, /* Softmute control */
315
316 0x454, 0x0425b9, /* Sound Easy programming(reset) */
317 0x454, 0x042539, /* Sound Easy programming(reset) */
318
319
320 /**** common setting( of DVD play, including scaler commands) ****/
321 0x042, 0x003, /* Data path configuration for VBI (TASK A) */
322
323 0x082, 0x003, /* Data path configuration for VBI (TASK B) */
324
325 0x108, 0x0f8, /* Sync control */
326 0x2a9, 0x0fd, /* ??? */
327 0x102, 0x089, /* select video input "mode 9" */
328 0x111, 0x000, /* Mode/delay control */
329
330 0x10e, 0x00a, /* Chroma control 1 */
331
332 0x594, 0x002, /* SIF, analog I/O select */
333
334 0x454, 0x0425b9, /* Sound */
335 0x454, 0x042539,
336
337 0x111, 0x000,
338 0x10e, 0x00a,
339 0x464, 0x000,
340 0x300, 0x000,
341 0x301, 0x006,
342 0x302, 0x000,
343 0x303, 0x006,
344 0x308, 0x040,
345 0x309, 0x000,
346 0x30a, 0x000,
347 0x30b, 0x000,
348 0x000, 0x002,
349 0x001, 0x000,
350 0x002, 0x000,
351 0x003, 0x000,
352 0x004, 0x033,
353 0x040, 0x01d,
354 0x041, 0x001,
355 0x042, 0x004,
356 0x043, 0x000,
357 0x080, 0x01e,
358 0x081, 0x001,
359 0x082, 0x004,
360 0x083, 0x000,
361 0x190, 0x018,
362 0x115, 0x000,
363 0x116, 0x012,
364 0x117, 0x018,
365 0x04a, 0x011,
366 0x08a, 0x011,
367 0x04b, 0x000,
368 0x08b, 0x000,
369 0x048, 0x000,
370 0x088, 0x000,
371 0x04e, 0x012,
372 0x08e, 0x012,
373 0x058, 0x012,
374 0x098, 0x012,
375 0x059, 0x000,
376 0x099, 0x000,
377 0x05a, 0x003,
378 0x09a, 0x003,
379 0x05b, 0x001,
380 0x09b, 0x001,
381 0x054, 0x008,
382 0x094, 0x008,
383 0x055, 0x000,
384 0x095, 0x000,
385 0x056, 0x0c7,
386 0x096, 0x0c7,
387 0x057, 0x002,
388 0x097, 0x002,
389 0x0ff, 0x0ff,
390 0x060, 0x001,
391 0x0a0, 0x001,
392 0x061, 0x000,
393 0x0a1, 0x000,
394 0x062, 0x000,
395 0x0a2, 0x000,
396 0x063, 0x000,
397 0x0a3, 0x000,
398 0x070, 0x000,
399 0x0b0, 0x000,
400 0x071, 0x004,
401 0x0b1, 0x004,
402 0x06c, 0x0e9,
403 0x0ac, 0x0e9,
404 0x06d, 0x003,
405 0x0ad, 0x003,
406 0x05c, 0x0d0,
407 0x09c, 0x0d0,
408 0x05d, 0x002,
409 0x09d, 0x002,
410 0x05e, 0x0f2,
411 0x09e, 0x0f2,
412 0x05f, 0x000,
413 0x09f, 0x000,
414 0x074, 0x000,
415 0x0b4, 0x000,
416 0x075, 0x000,
417 0x0b5, 0x000,
418 0x076, 0x000,
419 0x0b6, 0x000,
420 0x077, 0x000,
421 0x0b7, 0x000,
422 0x195, 0x008,
423 0x0ff, 0x0ff,
424 0x108, 0x0f8,
425 0x111, 0x000,
426 0x10e, 0x00a,
427 0x2a9, 0x0fd,
428 0x464, 0x001,
429 0x454, 0x042135,
430 0x598, 0x0e7,
431 0x599, 0x07d,
432 0x59a, 0x018,
433 0x59c, 0x066,
434 0x59d, 0x090,
435 0x59e, 0x001,
436 0x584, 0x000,
437 0x585, 0x000,
438 0x586, 0x003,
439 0x588, 0x0ff,
440 0x589, 0x00f,
441 0x58a, 0x000,
442 0x58b, 0x000,
443 0x58c, 0x010,
444 0x58d, 0x032,
445 0x58e, 0x054,
446 0x58f, 0x023,
447 0x590, 0x000,
448 0x595, 0x000,
449 0x596, 0x000,
450 0x597, 0x000,
451 0x464, 0x000,
452 0x46c, 0xbbbb10,
453 0x470, 0x101010,
454
455
456 0x478, 0x000,
457 0x474, 0x018,
458 0x454, 0x042135,
459 0x598, 0x0e7,
460 0x599, 0x07d,
461 0x59a, 0x018,
462 0x59c, 0x066,
463 0x59d, 0x090,
464 0x59e, 0x001,
465 0x584, 0x000,
466 0x585, 0x000,
467 0x586, 0x003,
468 0x588, 0x0ff,
469 0x589, 0x00f,
470 0x58a, 0x000,
471 0x58b, 0x000,
472 0x58c, 0x010,
473 0x58d, 0x032,
474 0x58e, 0x054,
475 0x58f, 0x023,
476 0x590, 0x000,
477 0x595, 0x000,
478 0x596, 0x000,
479 0x597, 0x000,
480 0x464, 0x000,
481 0x46c, 0xbbbb10,
482 0x470, 0x101010,
483
484 0x478, 0x000,
485 0x474, 0x018,
486 0x454, 0x042135,
487 0x598, 0x0e7,
488 0x599, 0x07d,
489 0x59a, 0x018,
490 0x59c, 0x066,
491 0x59d, 0x090,
492 0x59e, 0x001,
493 0x584, 0x000,
494 0x585, 0x000,
495 0x586, 0x003,
496 0x588, 0x0ff,
497 0x589, 0x00f,
498 0x58a, 0x000,
499 0x58b, 0x000,
500 0x58c, 0x010,
501 0x58d, 0x032,
502 0x58e, 0x054,
503 0x58f, 0x023,
504 0x590, 0x000,
505 0x595, 0x000,
506 0x596, 0x000,
507 0x597, 0x000,
508 0x464, 0x000,
509 0x46c, 0xbbbb10,
510 0x470, 0x101010,
511 0x478, 0x000,
512 0x474, 0x018,
513 0x454, 0x042135,
514 0x193, 0x000,
515 0x300, 0x000,
516 0x301, 0x006,
517 0x302, 0x000,
518 0x303, 0x006,
519 0x308, 0x040,
520 0x309, 0x000,
521 0x30a, 0x000,
522 0x30b, 0x000,
523 0x000, 0x002,
524 0x001, 0x000,
525 0x002, 0x000,
526 0x003, 0x000,
527 0x004, 0x033,
528 0x040, 0x01d,
529 0x041, 0x001,
530 0x042, 0x004,
531 0x043, 0x000,
532 0x080, 0x01e,
533 0x081, 0x001,
534 0x082, 0x004,
535 0x083, 0x000,
536 0x190, 0x018,
537 0x115, 0x000,
538 0x116, 0x012,
539 0x117, 0x018,
540 0x04a, 0x011,
541 0x08a, 0x011,
542 0x04b, 0x000,
543 0x08b, 0x000,
544 0x048, 0x000,
545 0x088, 0x000,
546 0x04e, 0x012,
547 0x08e, 0x012,
548 0x058, 0x012,
549 0x098, 0x012,
550 0x059, 0x000,
551 0x099, 0x000,
552 0x05a, 0x003,
553 0x09a, 0x003,
554 0x05b, 0x001,
555 0x09b, 0x001,
556 0x054, 0x008,
557 0x094, 0x008,
558 0x055, 0x000,
559 0x095, 0x000,
560 0x056, 0x0c7,
561 0x096, 0x0c7,
562 0x057, 0x002,
563 0x097, 0x002,
564 0x060, 0x001,
565 0x0a0, 0x001,
566 0x061, 0x000,
567 0x0a1, 0x000,
568 0x062, 0x000,
569 0x0a2, 0x000,
570 0x063, 0x000,
571 0x0a3, 0x000,
572 0x070, 0x000,
573 0x0b0, 0x000,
574 0x071, 0x004,
575 0x0b1, 0x004,
576 0x06c, 0x0e9,
577 0x0ac, 0x0e9,
578 0x06d, 0x003,
579 0x0ad, 0x003,
580 0x05c, 0x0d0,
581 0x09c, 0x0d0,
582 0x05d, 0x002,
583 0x09d, 0x002,
584 0x05e, 0x0f2,
585 0x09e, 0x0f2,
586 0x05f, 0x000,
587 0x09f, 0x000,
588 0x074, 0x000,
589 0x0b4, 0x000,
590 0x075, 0x000,
591 0x0b5, 0x000,
592 0x076, 0x000,
593 0x0b6, 0x000,
594 0x077, 0x000,
595 0x0b7, 0x000,
596 0x195, 0x008,
597 0x598, 0x0e7,
598 0x599, 0x07d,
599 0x59a, 0x018,
600 0x59c, 0x066,
601 0x59d, 0x090,
602 0x59e, 0x001,
603 0x584, 0x000,
604 0x585, 0x000,
605 0x586, 0x003,
606 0x588, 0x0ff,
607 0x589, 0x00f,
608 0x58a, 0x000,
609 0x58b, 0x000,
610 0x58c, 0x010,
611 0x58d, 0x032,
612 0x58e, 0x054,
613 0x58f, 0x023,
614 0x590, 0x000,
615 0x595, 0x000,
616 0x596, 0x000,
617 0x597, 0x000,
618 0x464, 0x000,
619 0x46c, 0xbbbb10,
620 0x470, 0x101010,
621 0x478, 0x000,
622 0x474, 0x018,
623 0x454, 0x042135,
624 0x193, 0x0a6,
625 0x108, 0x0f8,
626 0x042, 0x003,
627 0x082, 0x003,
628 0x454, 0x0425b9,
629 0x454, 0x042539,
630 0x193, 0x000,
631 0x193, 0x0a6,
632 0x464, 0x000,
633
634 0, 0
635};
636
637/* Tuner */
638static u32 reg_init_tuner_input[] = {
639 0x108, 0x0f8, /* Sync control */
640 0x111, 0x000, /* Mode/delay control */
641 0x10e, 0x00a, /* Chroma control 1 */
642 0, 0
643};
644
645/* Composite */
646static u32 reg_init_composite_input[] = {
647 0x108, 0x0e8, /* Sync control */
648 0x111, 0x000, /* Mode/delay control */
649 0x10e, 0x04a, /* Chroma control 1 */
650 0, 0
651};
652
653/* S-Video */
654static u32 reg_init_svideo_input[] = {
655 0x108, 0x0e8, /* Sync control */
656 0x111, 0x000, /* Mode/delay control */
657 0x10e, 0x04a, /* Chroma control 1 */
658 0, 0
659};
660
661static u32 reg_set_audio_template[4][2] =
662{
663 { /* for MONO
664 tadachi 6/29 DMA audio output select?
665 Register 0x46c
666 7-4: DMA2, 3-0: DMA1 ch. DMA4, DMA3 DMA2, DMA1
667 0: MAIN left, 1: MAIN right
668 2: AUX1 left, 3: AUX1 right
669 4: AUX2 left, 5: AUX2 right
670 6: DPL left, 7: DPL right
671 8: DPL center, 9: DPL surround
672 A: monitor output, B: digital sense */
673 0xbbbb00,
674
675 /* tadachi 6/29 DAC and I2S output select?
676 Register 0x470
677 7-4:DAC right ch. 3-0:DAC left ch.
678 I2S1 right,left I2S2 right,left */
679 0x00,
680 },
681 { /* for STEREO */
682 0xbbbb10, 0x101010,
683 },
684 { /* for LANG1 */
685 0xbbbb00, 0x00,
686 },
687 { /* for LANG2/SAP */
688 0xbbbb11, 0x111111,
689 }
690};
691
692
693/* Get detected audio flags (from saa7134 driver) */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300694static void get_inf_dev_status(struct v4l2_subdev *sd,
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300695 int *dual_flag, int *stereo_flag)
696{
697 u32 reg_data3;
698
699 static char *stdres[0x20] = {
700 [0x00] = "no standard detected",
701 [0x01] = "B/G (in progress)",
702 [0x02] = "D/K (in progress)",
703 [0x03] = "M (in progress)",
704
705 [0x04] = "B/G A2",
706 [0x05] = "B/G NICAM",
707 [0x06] = "D/K A2 (1)",
708 [0x07] = "D/K A2 (2)",
709 [0x08] = "D/K A2 (3)",
710 [0x09] = "D/K NICAM",
711 [0x0a] = "L NICAM",
712 [0x0b] = "I NICAM",
713
714 [0x0c] = "M Korea",
715 [0x0d] = "M BTSC ",
716 [0x0e] = "M EIAJ",
717
718 [0x0f] = "FM radio / IF 10.7 / 50 deemp",
719 [0x10] = "FM radio / IF 10.7 / 75 deemp",
720 [0x11] = "FM radio / IF sel / 50 deemp",
721 [0x12] = "FM radio / IF sel / 75 deemp",
722
723 [0x13 ... 0x1e] = "unknown",
724 [0x1f] = "??? [in progress]",
725 };
726
727
728 *dual_flag = *stereo_flag = 0;
729
730 /* (demdec status: 0x528) */
731
732 /* read current status */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300733 reg_data3 = saa717x_read(sd, 0x0528);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300734
Hans Verkuil27760fc2008-11-29 12:57:44 -0300735 v4l2_dbg(1, debug, sd, "tvaudio thread status: 0x%x [%s%s%s]\n",
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300736 reg_data3, stdres[reg_data3 & 0x1f],
737 (reg_data3 & 0x000020) ? ",stereo" : "",
738 (reg_data3 & 0x000040) ? ",dual" : "");
Hans Verkuil27760fc2008-11-29 12:57:44 -0300739 v4l2_dbg(1, debug, sd, "detailed status: "
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300740 "%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s\n",
741 (reg_data3 & 0x000080) ? " A2/EIAJ pilot tone " : "",
742 (reg_data3 & 0x000100) ? " A2/EIAJ dual " : "",
743 (reg_data3 & 0x000200) ? " A2/EIAJ stereo " : "",
744 (reg_data3 & 0x000400) ? " A2/EIAJ noise mute " : "",
745
746 (reg_data3 & 0x000800) ? " BTSC/FM radio pilot " : "",
747 (reg_data3 & 0x001000) ? " SAP carrier " : "",
748 (reg_data3 & 0x002000) ? " BTSC stereo noise mute " : "",
749 (reg_data3 & 0x004000) ? " SAP noise mute " : "",
750 (reg_data3 & 0x008000) ? " VDSP " : "",
751
752 (reg_data3 & 0x010000) ? " NICST " : "",
753 (reg_data3 & 0x020000) ? " NICDU " : "",
754 (reg_data3 & 0x040000) ? " NICAM muted " : "",
755 (reg_data3 & 0x080000) ? " NICAM reserve sound " : "",
756
757 (reg_data3 & 0x100000) ? " init done " : "");
758
759 if (reg_data3 & 0x000220) {
Hans Verkuil27760fc2008-11-29 12:57:44 -0300760 v4l2_dbg(1, debug, sd, "ST!!!\n");
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300761 *stereo_flag = 1;
762 }
763
764 if (reg_data3 & 0x000140) {
Hans Verkuil27760fc2008-11-29 12:57:44 -0300765 v4l2_dbg(1, debug, sd, "DUAL!!!\n");
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300766 *dual_flag = 1;
767 }
768}
769
770/* regs write to set audio mode */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300771static void set_audio_mode(struct v4l2_subdev *sd, int audio_mode)
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300772{
Hans Verkuil27760fc2008-11-29 12:57:44 -0300773 v4l2_dbg(1, debug, sd, "writing registers to set audio mode by set %d\n",
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300774 audio_mode);
775
Hans Verkuil27760fc2008-11-29 12:57:44 -0300776 saa717x_write(sd, 0x46c, reg_set_audio_template[audio_mode][0]);
777 saa717x_write(sd, 0x470, reg_set_audio_template[audio_mode][1]);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300778}
779
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300780/* write regs to set audio volume, bass and treble */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300781static int set_audio_regs(struct v4l2_subdev *sd,
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300782 struct saa717x_state *decoder)
783{
784 u8 mute = 0xac; /* -84 dB */
785 u32 val;
786 unsigned int work_l, work_r;
787
788 /* set SIF analog I/O select */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300789 saa717x_write(sd, 0x0594, decoder->audio_input);
790 v4l2_dbg(1, debug, sd, "set audio input %d\n",
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300791 decoder->audio_input);
792
793 /* normalize ( 65535 to 0 -> 24 to -40 (not -84)) */
794 work_l = (min(65536 - decoder->audio_main_balance, 32768) * decoder->audio_main_volume) / 32768;
795 work_r = (min(decoder->audio_main_balance, (u16)32768) * decoder->audio_main_volume) / 32768;
796 decoder->audio_main_vol_l = (long)work_l * (24 - (-40)) / 65535 - 40;
797 decoder->audio_main_vol_r = (long)work_r * (24 - (-40)) / 65535 - 40;
798
799 /* set main volume */
800 /* main volume L[7-0],R[7-0],0x00 24=24dB,-83dB, -84(mute) */
801 /* def:0dB->6dB(MPG600GR) */
802 /* if mute is on, set mute */
803 if (decoder->audio_main_mute) {
804 val = mute | (mute << 8);
805 } else {
806 val = (u8)decoder->audio_main_vol_l |
807 ((u8)decoder->audio_main_vol_r << 8);
808 }
809
Hans Verkuil27760fc2008-11-29 12:57:44 -0300810 saa717x_write(sd, 0x480, val);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300811
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300812 /* set bass and treble */
Hans Verkuil59b83112010-04-23 09:04:48 -0300813 val = decoder->audio_main_bass & 0x1f;
814 val |= (decoder->audio_main_treble & 0x1f) << 5;
Hans Verkuil27760fc2008-11-29 12:57:44 -0300815 saa717x_write(sd, 0x488, val);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300816 return 0;
817}
818
819/********** scaling staff ***********/
Hans Verkuil27760fc2008-11-29 12:57:44 -0300820static void set_h_prescale(struct v4l2_subdev *sd,
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300821 int task, int prescale)
822{
823 static const struct {
824 int xpsc;
825 int xacl;
826 int xc2_1;
827 int xdcg;
828 int vpfy;
829 } vals[] = {
830 /* XPSC XACL XC2_1 XDCG VPFY */
831 { 1, 0, 0, 0, 0 },
832 { 2, 2, 1, 2, 2 },
833 { 3, 4, 1, 3, 2 },
834 { 4, 8, 1, 4, 2 },
835 { 5, 8, 1, 4, 2 },
836 { 6, 8, 1, 4, 3 },
837 { 7, 8, 1, 4, 3 },
838 { 8, 15, 0, 4, 3 },
839 { 9, 15, 0, 4, 3 },
840 { 10, 16, 1, 5, 3 },
841 };
842 static const int count = ARRAY_SIZE(vals);
843 int i, task_shift;
844
845 task_shift = task * 0x40;
846 for (i = 0; i < count; i++)
847 if (vals[i].xpsc == prescale)
848 break;
849 if (i == count)
850 return;
851
852 /* horizonal prescaling */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300853 saa717x_write(sd, 0x60 + task_shift, vals[i].xpsc);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300854 /* accumulation length */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300855 saa717x_write(sd, 0x61 + task_shift, vals[i].xacl);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300856 /* level control */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300857 saa717x_write(sd, 0x62 + task_shift,
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300858 (vals[i].xc2_1 << 3) | vals[i].xdcg);
859 /*FIR prefilter control */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300860 saa717x_write(sd, 0x63 + task_shift,
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300861 (vals[i].vpfy << 2) | vals[i].vpfy);
862}
863
864/********** scaling staff ***********/
Hans Verkuil27760fc2008-11-29 12:57:44 -0300865static void set_v_scale(struct v4l2_subdev *sd, int task, int yscale)
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300866{
867 int task_shift;
868
869 task_shift = task * 0x40;
870 /* Vertical scaling ratio (LOW) */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300871 saa717x_write(sd, 0x70 + task_shift, yscale & 0xff);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300872 /* Vertical scaling ratio (HI) */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300873 saa717x_write(sd, 0x71 + task_shift, yscale >> 8);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300874}
875
Hans Verkuil59b83112010-04-23 09:04:48 -0300876static int saa717x_s_ctrl(struct v4l2_ctrl *ctrl)
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300877{
Hans Verkuil59b83112010-04-23 09:04:48 -0300878 struct v4l2_subdev *sd = to_sd(ctrl);
Hans Verkuil27760fc2008-11-29 12:57:44 -0300879 struct saa717x_state *state = to_state(sd);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300880
881 switch (ctrl->id) {
882 case V4L2_CID_BRIGHTNESS:
Hans Verkuil59b83112010-04-23 09:04:48 -0300883 saa717x_write(sd, 0x10a, ctrl->val);
884 return 0;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300885
886 case V4L2_CID_CONTRAST:
Hans Verkuil59b83112010-04-23 09:04:48 -0300887 saa717x_write(sd, 0x10b, ctrl->val);
888 return 0;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300889
890 case V4L2_CID_SATURATION:
Hans Verkuil59b83112010-04-23 09:04:48 -0300891 saa717x_write(sd, 0x10c, ctrl->val);
892 return 0;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300893
894 case V4L2_CID_HUE:
Hans Verkuil59b83112010-04-23 09:04:48 -0300895 saa717x_write(sd, 0x10d, ctrl->val);
896 return 0;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300897
898 case V4L2_CID_AUDIO_MUTE:
Hans Verkuil59b83112010-04-23 09:04:48 -0300899 state->audio_main_mute = ctrl->val;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300900 break;
901
902 case V4L2_CID_AUDIO_VOLUME:
Hans Verkuil59b83112010-04-23 09:04:48 -0300903 state->audio_main_volume = ctrl->val;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300904 break;
905
906 case V4L2_CID_AUDIO_BALANCE:
Hans Verkuil59b83112010-04-23 09:04:48 -0300907 state->audio_main_balance = ctrl->val;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300908 break;
909
910 case V4L2_CID_AUDIO_TREBLE:
Hans Verkuil59b83112010-04-23 09:04:48 -0300911 state->audio_main_treble = ctrl->val;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300912 break;
913
914 case V4L2_CID_AUDIO_BASS:
Hans Verkuil59b83112010-04-23 09:04:48 -0300915 state->audio_main_bass = ctrl->val;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300916 break;
917
918 default:
Hans Verkuil59b83112010-04-23 09:04:48 -0300919 return 0;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300920 }
Hans Verkuil59b83112010-04-23 09:04:48 -0300921 set_audio_regs(sd, state);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300922 return 0;
923}
924
Hans Verkuil5325b422009-04-02 11:26:22 -0300925static int saa717x_s_video_routing(struct v4l2_subdev *sd,
926 u32 input, u32 output, u32 config)
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300927{
Hans Verkuil27760fc2008-11-29 12:57:44 -0300928 struct saa717x_state *decoder = to_state(sd);
Hans Verkuil5325b422009-04-02 11:26:22 -0300929 int is_tuner = input & 0x80; /* tuner input flag */
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300930
Hans Verkuil5325b422009-04-02 11:26:22 -0300931 input &= 0x7f;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300932
Hans Verkuil5325b422009-04-02 11:26:22 -0300933 v4l2_dbg(1, debug, sd, "decoder set input (%d)\n", input);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300934 /* inputs from 0-9 are available*/
935 /* saa717x have mode0-mode9 but mode5 is reserved. */
Roel Kluinf14a2972009-10-23 07:59:42 -0300936 if (input > 9 || input == 5)
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300937 return -EINVAL;
938
Hans Verkuil5325b422009-04-02 11:26:22 -0300939 if (decoder->input != input) {
940 int input_line = input;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300941
942 decoder->input = input_line;
Hans Verkuil27760fc2008-11-29 12:57:44 -0300943 v4l2_dbg(1, debug, sd, "now setting %s input %d\n",
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300944 input_line >= 6 ? "S-Video" : "Composite",
945 input_line);
946
947 /* select mode */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300948 saa717x_write(sd, 0x102,
949 (saa717x_read(sd, 0x102) & 0xf0) |
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300950 input_line);
951
952 /* bypass chrominance trap for modes 6..9 */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300953 saa717x_write(sd, 0x109,
954 (saa717x_read(sd, 0x109) & 0x7f) |
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300955 (input_line < 6 ? 0x0 : 0x80));
956
957 /* change audio_mode */
958 if (is_tuner) {
959 /* tuner */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300960 set_audio_mode(sd, decoder->tuner_audio_mode);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300961 } else {
962 /* Force to STEREO mode if Composite or
963 * S-Video were chosen */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300964 set_audio_mode(sd, TUNER_AUDIO_STEREO);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300965 }
966 /* change initialize procedure (Composite/S-Video) */
967 if (is_tuner)
Hans Verkuil27760fc2008-11-29 12:57:44 -0300968 saa717x_write_regs(sd, reg_init_tuner_input);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300969 else if (input_line >= 6)
Hans Verkuil27760fc2008-11-29 12:57:44 -0300970 saa717x_write_regs(sd, reg_init_svideo_input);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300971 else
Hans Verkuil27760fc2008-11-29 12:57:44 -0300972 saa717x_write_regs(sd, reg_init_composite_input);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300973 }
974
975 return 0;
976}
977
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300978#ifdef CONFIG_VIDEO_ADV_DEBUG
Hans Verkuilaecde8b52008-12-30 07:14:19 -0300979static int saa717x_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
Hans Verkuil27760fc2008-11-29 12:57:44 -0300980{
981 struct i2c_client *client = v4l2_get_subdevdata(sd);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300982
Hans Verkuilaecde8b52008-12-30 07:14:19 -0300983 if (!v4l2_chip_match_i2c_client(client, &reg->match))
Hans Verkuil27760fc2008-11-29 12:57:44 -0300984 return -EINVAL;
985 if (!capable(CAP_SYS_ADMIN))
986 return -EPERM;
987 reg->val = saa717x_read(sd, reg->reg);
Hans Verkuilaecde8b52008-12-30 07:14:19 -0300988 reg->size = 1;
Hans Verkuil27760fc2008-11-29 12:57:44 -0300989 return 0;
990}
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300991
Hans Verkuilaecde8b52008-12-30 07:14:19 -0300992static int saa717x_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
Hans Verkuil27760fc2008-11-29 12:57:44 -0300993{
994 struct i2c_client *client = v4l2_get_subdevdata(sd);
995 u16 addr = reg->reg & 0xffff;
996 u8 val = reg->val & 0xff;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300997
Hans Verkuilaecde8b52008-12-30 07:14:19 -0300998 if (!v4l2_chip_match_i2c_client(client, &reg->match))
Hans Verkuil27760fc2008-11-29 12:57:44 -0300999 return -EINVAL;
1000 if (!capable(CAP_SYS_ADMIN))
1001 return -EPERM;
1002 saa717x_write(sd, addr, val);
1003 return 0;
1004}
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001005#endif
1006
Hans Verkuil6c69db92010-05-09 09:50:34 -03001007static int saa717x_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt)
Hans Verkuil27760fc2008-11-29 12:57:44 -03001008{
Hans Verkuil27760fc2008-11-29 12:57:44 -03001009 int prescale, h_scale, v_scale;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001010
Hans Verkuil27760fc2008-11-29 12:57:44 -03001011 v4l2_dbg(1, debug, sd, "decoder set size\n");
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001012
Hans Verkuil6c69db92010-05-09 09:50:34 -03001013 if (fmt->code != V4L2_MBUS_FMT_FIXED)
1014 return -EINVAL;
1015
Hans Verkuil27760fc2008-11-29 12:57:44 -03001016 /* FIXME need better bounds checking here */
Hans Verkuil6c69db92010-05-09 09:50:34 -03001017 if (fmt->width < 1 || fmt->width > 1440)
Hans Verkuil27760fc2008-11-29 12:57:44 -03001018 return -EINVAL;
Hans Verkuil6c69db92010-05-09 09:50:34 -03001019 if (fmt->height < 1 || fmt->height > 960)
Hans Verkuil27760fc2008-11-29 12:57:44 -03001020 return -EINVAL;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001021
Hans Verkuil6c69db92010-05-09 09:50:34 -03001022 fmt->field = V4L2_FIELD_INTERLACED;
1023 fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
1024
Hans Verkuil27760fc2008-11-29 12:57:44 -03001025 /* scaling setting */
1026 /* NTSC and interlace only */
Hans Verkuil6c69db92010-05-09 09:50:34 -03001027 prescale = SAA717X_NTSC_WIDTH / fmt->width;
Hans Verkuil27760fc2008-11-29 12:57:44 -03001028 if (prescale == 0)
1029 prescale = 1;
Hans Verkuil6c69db92010-05-09 09:50:34 -03001030 h_scale = 1024 * SAA717X_NTSC_WIDTH / prescale / fmt->width;
Hans Verkuil27760fc2008-11-29 12:57:44 -03001031 /* interlace */
Hans Verkuil6c69db92010-05-09 09:50:34 -03001032 v_scale = 512 * 2 * SAA717X_NTSC_HEIGHT / fmt->height;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001033
Hans Verkuil27760fc2008-11-29 12:57:44 -03001034 /* Horizontal prescaling etc */
1035 set_h_prescale(sd, 0, prescale);
1036 set_h_prescale(sd, 1, prescale);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001037
Hans Verkuil27760fc2008-11-29 12:57:44 -03001038 /* Horizontal scaling increment */
1039 /* TASK A */
1040 saa717x_write(sd, 0x6C, (u8)(h_scale & 0xFF));
1041 saa717x_write(sd, 0x6D, (u8)((h_scale >> 8) & 0xFF));
1042 /* TASK B */
1043 saa717x_write(sd, 0xAC, (u8)(h_scale & 0xFF));
1044 saa717x_write(sd, 0xAD, (u8)((h_scale >> 8) & 0xFF));
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001045
Hans Verkuil27760fc2008-11-29 12:57:44 -03001046 /* Vertical prescaling etc */
1047 set_v_scale(sd, 0, v_scale);
1048 set_v_scale(sd, 1, v_scale);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001049
Hans Verkuil27760fc2008-11-29 12:57:44 -03001050 /* set video output size */
1051 /* video number of pixels at output */
1052 /* TASK A */
Hans Verkuil6c69db92010-05-09 09:50:34 -03001053 saa717x_write(sd, 0x5C, (u8)(fmt->width & 0xFF));
1054 saa717x_write(sd, 0x5D, (u8)((fmt->width >> 8) & 0xFF));
Hans Verkuil27760fc2008-11-29 12:57:44 -03001055 /* TASK B */
Hans Verkuil6c69db92010-05-09 09:50:34 -03001056 saa717x_write(sd, 0x9C, (u8)(fmt->width & 0xFF));
1057 saa717x_write(sd, 0x9D, (u8)((fmt->width >> 8) & 0xFF));
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001058
Hans Verkuil27760fc2008-11-29 12:57:44 -03001059 /* video number of lines at output */
1060 /* TASK A */
Hans Verkuil6c69db92010-05-09 09:50:34 -03001061 saa717x_write(sd, 0x5E, (u8)(fmt->height & 0xFF));
1062 saa717x_write(sd, 0x5F, (u8)((fmt->height >> 8) & 0xFF));
Hans Verkuil27760fc2008-11-29 12:57:44 -03001063 /* TASK B */
Hans Verkuil6c69db92010-05-09 09:50:34 -03001064 saa717x_write(sd, 0x9E, (u8)(fmt->height & 0xFF));
1065 saa717x_write(sd, 0x9F, (u8)((fmt->height >> 8) & 0xFF));
Hans Verkuil27760fc2008-11-29 12:57:44 -03001066 return 0;
1067}
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001068
Hans Verkuil27760fc2008-11-29 12:57:44 -03001069static int saa717x_s_radio(struct v4l2_subdev *sd)
1070{
1071 struct saa717x_state *decoder = to_state(sd);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001072
Hans Verkuil27760fc2008-11-29 12:57:44 -03001073 decoder->radio = 1;
1074 return 0;
1075}
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001076
Hans Verkuil27760fc2008-11-29 12:57:44 -03001077static int saa717x_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
1078{
1079 struct saa717x_state *decoder = to_state(sd);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001080
Hans Verkuil27760fc2008-11-29 12:57:44 -03001081 v4l2_dbg(1, debug, sd, "decoder set norm ");
1082 v4l2_dbg(1, debug, sd, "(not yet implementd)\n");
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001083
Hans Verkuil27760fc2008-11-29 12:57:44 -03001084 decoder->radio = 0;
1085 decoder->std = std;
1086 return 0;
1087}
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001088
Hans Verkuil5325b422009-04-02 11:26:22 -03001089static int saa717x_s_audio_routing(struct v4l2_subdev *sd,
1090 u32 input, u32 output, u32 config)
Hans Verkuil27760fc2008-11-29 12:57:44 -03001091{
1092 struct saa717x_state *decoder = to_state(sd);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001093
Hans Verkuil5325b422009-04-02 11:26:22 -03001094 if (input < 3) { /* FIXME! --tadachi */
1095 decoder->audio_input = input;
Hans Verkuil27760fc2008-11-29 12:57:44 -03001096 v4l2_dbg(1, debug, sd,
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001097 "set decoder audio input to %d\n",
1098 decoder->audio_input);
Hans Verkuil27760fc2008-11-29 12:57:44 -03001099 set_audio_regs(sd, decoder);
1100 return 0;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001101 }
Hans Verkuil27760fc2008-11-29 12:57:44 -03001102 return -ERANGE;
1103}
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001104
Hans Verkuil27760fc2008-11-29 12:57:44 -03001105static int saa717x_s_stream(struct v4l2_subdev *sd, int enable)
1106{
1107 struct saa717x_state *decoder = to_state(sd);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001108
Hans Verkuil27760fc2008-11-29 12:57:44 -03001109 v4l2_dbg(1, debug, sd, "decoder %s output\n",
1110 enable ? "enable" : "disable");
1111 decoder->enable = enable;
1112 saa717x_write(sd, 0x193, enable ? 0xa6 : 0x26);
1113 return 0;
1114}
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001115
Hans Verkuil27760fc2008-11-29 12:57:44 -03001116/* change audio mode */
1117static int saa717x_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
1118{
1119 struct saa717x_state *decoder = to_state(sd);
1120 int audio_mode;
1121 char *mes[4] = {
1122 "MONO", "STEREO", "LANG1", "LANG2/SAP"
1123 };
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001124
Julia Lawallb921d922009-11-08 14:49:05 -03001125 audio_mode = TUNER_AUDIO_STEREO;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001126
Hans Verkuil27760fc2008-11-29 12:57:44 -03001127 switch (vt->audmode) {
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001128 case V4L2_TUNER_MODE_MONO:
1129 audio_mode = TUNER_AUDIO_MONO;
1130 break;
1131 case V4L2_TUNER_MODE_STEREO:
1132 audio_mode = TUNER_AUDIO_STEREO;
1133 break;
1134 case V4L2_TUNER_MODE_LANG2:
1135 audio_mode = TUNER_AUDIO_LANG2;
1136 break;
1137 case V4L2_TUNER_MODE_LANG1:
1138 audio_mode = TUNER_AUDIO_LANG1;
1139 break;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001140 }
1141
Hans Verkuil27760fc2008-11-29 12:57:44 -03001142 v4l2_dbg(1, debug, sd, "change audio mode to %s\n",
1143 mes[audio_mode]);
1144 decoder->tuner_audio_mode = audio_mode;
1145 /* The registers are not changed here. */
1146 /* See DECODER_ENABLE_OUTPUT section. */
1147 set_audio_mode(sd, decoder->tuner_audio_mode);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001148 return 0;
1149}
1150
Hans Verkuil27760fc2008-11-29 12:57:44 -03001151static int saa717x_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
1152{
1153 struct saa717x_state *decoder = to_state(sd);
1154 int dual_f, stereo_f;
1155
1156 if (decoder->radio)
1157 return 0;
1158 get_inf_dev_status(sd, &dual_f, &stereo_f);
1159
1160 v4l2_dbg(1, debug, sd, "DETECT==st:%d dual:%d\n",
1161 stereo_f, dual_f);
1162
1163 /* mono */
1164 if ((dual_f == 0) && (stereo_f == 0)) {
1165 vt->rxsubchans = V4L2_TUNER_SUB_MONO;
1166 v4l2_dbg(1, debug, sd, "DETECT==MONO\n");
1167 }
1168
1169 /* stereo */
1170 if (stereo_f == 1) {
1171 if (vt->audmode == V4L2_TUNER_MODE_STEREO ||
1172 vt->audmode == V4L2_TUNER_MODE_LANG1) {
1173 vt->rxsubchans = V4L2_TUNER_SUB_STEREO;
1174 v4l2_dbg(1, debug, sd, "DETECT==ST(ST)\n");
1175 } else {
1176 vt->rxsubchans = V4L2_TUNER_SUB_MONO;
1177 v4l2_dbg(1, debug, sd, "DETECT==ST(MONO)\n");
1178 }
1179 }
1180
1181 /* dual */
1182 if (dual_f == 1) {
1183 if (vt->audmode == V4L2_TUNER_MODE_LANG2) {
1184 vt->rxsubchans = V4L2_TUNER_SUB_LANG2 | V4L2_TUNER_SUB_MONO;
1185 v4l2_dbg(1, debug, sd, "DETECT==DUAL1\n");
1186 } else {
1187 vt->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_MONO;
1188 v4l2_dbg(1, debug, sd, "DETECT==DUAL2\n");
1189 }
1190 }
1191 return 0;
1192}
1193
Hans Verkuil59b83112010-04-23 09:04:48 -03001194static int saa717x_log_status(struct v4l2_subdev *sd)
1195{
1196 struct saa717x_state *state = to_state(sd);
1197
1198 v4l2_ctrl_handler_log_status(&state->hdl, sd->name);
1199 return 0;
1200}
1201
Hans Verkuil27760fc2008-11-29 12:57:44 -03001202/* ----------------------------------------------------------------------- */
1203
Hans Verkuil59b83112010-04-23 09:04:48 -03001204static const struct v4l2_ctrl_ops saa717x_ctrl_ops = {
1205 .s_ctrl = saa717x_s_ctrl,
1206};
1207
Hans Verkuil27760fc2008-11-29 12:57:44 -03001208static const struct v4l2_subdev_core_ops saa717x_core_ops = {
1209#ifdef CONFIG_VIDEO_ADV_DEBUG
1210 .g_register = saa717x_g_register,
1211 .s_register = saa717x_s_register,
1212#endif
Hans Verkuilf41737e2009-04-01 03:52:39 -03001213 .s_std = saa717x_s_std,
Hans Verkuil59b83112010-04-23 09:04:48 -03001214 .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
1215 .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
1216 .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
1217 .g_ctrl = v4l2_subdev_g_ctrl,
1218 .s_ctrl = v4l2_subdev_s_ctrl,
1219 .queryctrl = v4l2_subdev_queryctrl,
1220 .querymenu = v4l2_subdev_querymenu,
1221 .log_status = saa717x_log_status,
Hans Verkuil27760fc2008-11-29 12:57:44 -03001222};
1223
1224static const struct v4l2_subdev_tuner_ops saa717x_tuner_ops = {
1225 .g_tuner = saa717x_g_tuner,
1226 .s_tuner = saa717x_s_tuner,
Hans Verkuil27760fc2008-11-29 12:57:44 -03001227 .s_radio = saa717x_s_radio,
1228};
1229
1230static const struct v4l2_subdev_video_ops saa717x_video_ops = {
1231 .s_routing = saa717x_s_video_routing,
Hans Verkuil6c69db92010-05-09 09:50:34 -03001232 .s_mbus_fmt = saa717x_s_mbus_fmt,
Hans Verkuil27760fc2008-11-29 12:57:44 -03001233 .s_stream = saa717x_s_stream,
1234};
1235
1236static const struct v4l2_subdev_audio_ops saa717x_audio_ops = {
1237 .s_routing = saa717x_s_audio_routing,
1238};
1239
1240static const struct v4l2_subdev_ops saa717x_ops = {
1241 .core = &saa717x_core_ops,
1242 .tuner = &saa717x_tuner_ops,
1243 .audio = &saa717x_audio_ops,
1244 .video = &saa717x_video_ops,
1245};
1246
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001247/* ----------------------------------------------------------------------- */
1248
1249
1250/* i2c implementation */
1251
1252/* ----------------------------------------------------------------------- */
Jean Delvared2653e92008-04-29 23:11:39 +02001253static int saa717x_probe(struct i2c_client *client,
1254 const struct i2c_device_id *did)
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001255{
1256 struct saa717x_state *decoder;
Hans Verkuil59b83112010-04-23 09:04:48 -03001257 struct v4l2_ctrl_handler *hdl;
Hans Verkuil27760fc2008-11-29 12:57:44 -03001258 struct v4l2_subdev *sd;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001259 u8 id = 0;
1260 char *p = "";
1261
1262 /* Check if the adapter supports the needed features */
1263 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
1264 return -EIO;
1265
Hans Verkuil27760fc2008-11-29 12:57:44 -03001266 decoder = kzalloc(sizeof(struct saa717x_state), GFP_KERNEL);
1267 if (decoder == NULL)
1268 return -ENOMEM;
1269
1270 sd = &decoder->sd;
1271 v4l2_i2c_subdev_init(sd, client, &saa717x_ops);
1272
1273 if (saa717x_write(sd, 0x5a4, 0xfe) &&
1274 saa717x_write(sd, 0x5a5, 0x0f) &&
1275 saa717x_write(sd, 0x5a6, 0x00) &&
1276 saa717x_write(sd, 0x5a7, 0x01))
1277 id = saa717x_read(sd, 0x5a0);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001278 if (id != 0xc2 && id != 0x32 && id != 0xf2 && id != 0x6c) {
Hans Verkuil27760fc2008-11-29 12:57:44 -03001279 v4l2_dbg(1, debug, sd, "saa717x not found (id=%02x)\n", id);
1280 kfree(decoder);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001281 return -ENODEV;
1282 }
1283 if (id == 0xc2)
1284 p = "saa7173";
1285 else if (id == 0x32)
1286 p = "saa7174A";
1287 else if (id == 0x6c)
1288 p = "saa7174HL";
1289 else
1290 p = "saa7171";
Hans Verkuil27760fc2008-11-29 12:57:44 -03001291 v4l2_info(sd, "%s found @ 0x%x (%s)\n", p,
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001292 client->addr << 1, client->adapter->name);
Hans Verkuil59b83112010-04-23 09:04:48 -03001293
1294 hdl = &decoder->hdl;
1295 v4l2_ctrl_handler_init(hdl, 9);
1296 /* add in ascending ID order */
1297 v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
1298 V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
1299 v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
1300 V4L2_CID_CONTRAST, 0, 255, 1, 68);
1301 v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
1302 V4L2_CID_SATURATION, 0, 255, 1, 64);
1303 v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
1304 V4L2_CID_HUE, -128, 127, 1, 0);
1305 v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
1306 V4L2_CID_AUDIO_VOLUME, 0, 65535, 65535 / 100, 42000);
1307 v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
1308 V4L2_CID_AUDIO_BALANCE, 0, 65535, 65535 / 100, 32768);
1309 v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
1310 V4L2_CID_AUDIO_BASS, -16, 15, 1, 0);
1311 v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
1312 V4L2_CID_AUDIO_TREBLE, -16, 15, 1, 0);
1313 v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
1314 V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0);
1315 sd->ctrl_handler = hdl;
1316 if (hdl->error) {
1317 int err = hdl->error;
1318
1319 v4l2_ctrl_handler_free(hdl);
1320 kfree(decoder);
1321 return err;
1322 }
1323
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001324 decoder->std = V4L2_STD_NTSC;
1325 decoder->input = -1;
1326 decoder->enable = 1;
1327
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001328 /* FIXME!! */
1329 decoder->playback = 0; /* initially capture mode used */
1330 decoder->audio = 1; /* DECODER_AUDIO_48_KHZ */
1331
1332 decoder->audio_input = 2; /* FIXME!! */
1333
1334 decoder->tuner_audio_mode = TUNER_AUDIO_STEREO;
1335 /* set volume, bass and treble */
1336 decoder->audio_main_vol_l = 6;
1337 decoder->audio_main_vol_r = 6;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001338
Hans Verkuil27760fc2008-11-29 12:57:44 -03001339 v4l2_dbg(1, debug, sd, "writing init values\n");
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001340
1341 /* FIXME!! */
Hans Verkuil27760fc2008-11-29 12:57:44 -03001342 saa717x_write_regs(sd, reg_init_initialize);
Hans Verkuil59b83112010-04-23 09:04:48 -03001343
1344 v4l2_ctrl_handler_setup(hdl);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001345
1346 set_current_state(TASK_INTERRUPTIBLE);
1347 schedule_timeout(2*HZ);
1348 return 0;
1349}
1350
1351static int saa717x_remove(struct i2c_client *client)
1352{
Hans Verkuil27760fc2008-11-29 12:57:44 -03001353 struct v4l2_subdev *sd = i2c_get_clientdata(client);
1354
1355 v4l2_device_unregister_subdev(sd);
Hans Verkuil59b83112010-04-23 09:04:48 -03001356 v4l2_ctrl_handler_free(sd->ctrl_handler);
Hans Verkuil27760fc2008-11-29 12:57:44 -03001357 kfree(to_state(sd));
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001358 return 0;
1359}
1360
1361/* ----------------------------------------------------------------------- */
1362
Jean Delvareaf294862008-05-18 20:49:40 +02001363static const struct i2c_device_id saa717x_id[] = {
1364 { "saa717x", 0 },
1365 { }
1366};
1367MODULE_DEVICE_TABLE(i2c, saa717x_id);
1368
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001369static struct v4l2_i2c_driver_data v4l2_i2c_data = {
1370 .name = "saa717x",
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001371 .probe = saa717x_probe,
1372 .remove = saa717x_remove,
Jean Delvareaf294862008-05-18 20:49:40 +02001373 .id_table = saa717x_id,
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001374};