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

source code of linux/drivers/media/i2c/saa717x.c