Merge tag 'block-5.11-2021-01-10' of git://git.kernel.dk/linux-block
[linux/fpc-iii.git] / drivers / media / i2c / saa717x.c
blobba103a6a1875d9ab1d1d26a0005a3988f3d1eedd
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * saa717x - Philips SAA717xHL video decoder driver
5 * Based on the saa7115 driver
7 * Changes by Ohta Kyuma <alpha292@bremen.or.jp>
8 * - Apply to SAA717x,NEC uPD64031,uPD64083. (1/31/2004)
10 * Changes by T.Adachi (tadachi@tadachi-net.com)
11 * - support audio, video scaler etc, and checked the initialize sequence.
13 * Cleaned up by Hans Verkuil <hverkuil@xs4all.nl>
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.
20 #include <linux/module.h>
21 #include <linux/kernel.h>
22 #include <linux/slab.h>
23 #include <linux/sched.h>
25 #include <linux/videodev2.h>
26 #include <linux/i2c.h>
27 #include <media/v4l2-device.h>
28 #include <media/v4l2-ctrls.h>
30 MODULE_DESCRIPTION("Philips SAA717x audio/video decoder driver");
31 MODULE_AUTHOR("K. Ohta, T. Adachi, Hans Verkuil");
32 MODULE_LICENSE("GPL");
34 static int debug;
35 module_param(debug, int, 0644);
36 MODULE_PARM_DESC(debug, "Debug level (0-1)");
39 * Generic i2c probe
40 * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
43 struct 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;
63 static inline struct saa717x_state *to_state(struct v4l2_subdev *sd)
65 return container_of(sd, struct saa717x_state, sd);
68 static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
70 return &container_of(ctrl->handler, struct saa717x_state, hdl)->sd;
73 /* ----------------------------------------------------------------------- */
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 */
81 #define SAA717X_NTSC_WIDTH (704)
82 #define SAA717X_NTSC_HEIGHT (480)
84 /* ----------------------------------------------------------------------- */
86 static int saa717x_write(struct v4l2_subdev *sd, u32 reg, u32 value)
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;
94 msg.flags = 0;
95 msg.addr = client->addr;
96 mm1[0] = (reg >> 8) & 0xff;
97 mm1[1] = reg & 0xff;
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;
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, &msg, 1) == 1;
112 static void saa717x_write_regs(struct v4l2_subdev *sd, u32 *data)
114 while (data[0] || data[1]) {
115 saa717x_write(sd, data[0], data[1]);
116 data += 2;
120 static u32 saa717x_read(struct v4l2_subdev *sd, u32 reg)
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;
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, 2);
141 if (fw_addr)
142 value = (mm2[2] << 16) | (mm2[1] << 8) | mm2[0];
143 else
144 value = mm2[0];
146 v4l2_dbg(2, debug, sd, "read: reg 0x%03x=0x%08x\n", reg, value);
147 return value;
150 /* ----------------------------------------------------------------------- */
152 static u32 reg_init_initialize[] =
154 /* from linux driver */
155 0x101, 0x008, /* Increment delay */
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 */
164 0x10f, 0x02a, /* Chroma gain control */
165 0x110, 0x000, /* Chroma control 2 */
167 0x114, 0x045, /* analog/ADC */
169 0x118, 0x040, /* RAW data gain */
170 0x119, 0x080, /* RAW data offset */
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 */
177 0x049, 0x000, /* VBI vertical input window start (H) TASK A */
179 0x04c, 0x0d0, /* VBI horizontal output length (L) TASK A */
180 0x04d, 0x002, /* VBI horizontal output length (H) TASK A */
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 */
190 0x06e, 0x000, /* Horizontal phase offset Luma TASK A */
191 0x06f, 0x000, /* Horizontal phase offset Chroma TASK A */
193 0x072, 0x000, /* Vertical filter mode TASK A */
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 */
200 0x089, 0x000, /* VBI vertical input window start (H) TAKS B */
202 0x08c, 0x0d0, /* VBI horizontal output length (L) TASK B */
203 0x08d, 0x002, /* VBI horizontal output length (H) TASK B */
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 */
213 0x0ae, 0x000, /* Horizontal phase offset Luma TASK B */
214 0x0af, 0x000, /*Horizontal phase offset Chroma TASK B */
216 0x0b2, 0x000, /* Vertical filter mode TASK B */
218 0x00c, 0x000, /* Start point GREEN path */
219 0x00d, 0x000, /* Start point BLUE path */
220 0x00e, 0x000, /* Start point RED path */
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 */
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 */
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 */
273 0x109, 0x085, /* Luminance control */
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 */
289 0x595, 0x000, /* ?? */
290 0x596, 0x000, /* ?? */
291 0x597, 0x000, /* ?? */
293 0x464, 0x00, /* Digital input crossbar1 */
295 0x46c, 0xbbbb10, /* Digital output selection1-3 */
296 0x470, 0x101010, /* Digital output selection4-6 */
298 0x478, 0x00, /* Sound feature control */
300 0x474, 0x18, /* Softmute control */
302 0x454, 0x0425b9, /* Sound Easy programming(reset) */
303 0x454, 0x042539, /* Sound Easy programming(reset) */
306 /**** common setting( of DVD play, including scaler commands) ****/
307 0x042, 0x003, /* Data path configuration for VBI (TASK A) */
309 0x082, 0x003, /* Data path configuration for VBI (TASK B) */
311 0x108, 0x0f8, /* Sync control */
312 0x2a9, 0x0fd, /* ??? */
313 0x102, 0x089, /* select video input "mode 9" */
314 0x111, 0x000, /* Mode/delay control */
316 0x10e, 0x00a, /* Chroma control 1 */
318 0x594, 0x002, /* SIF, analog I/O select */
320 0x454, 0x0425b9, /* Sound */
321 0x454, 0x042539,
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,
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,
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,
620 0, 0
623 /* Tuner */
624 static 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
631 /* Composite */
632 static 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
639 /* S-Video */
640 static 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
647 static u32 reg_set_audio_template[4][2] =
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,
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,
667 { /* for STEREO */
668 0xbbbb10, 0x101010,
670 { /* for LANG1 */
671 0xbbbb00, 0x00,
673 { /* for LANG2/SAP */
674 0xbbbb11, 0x111111,
679 /* Get detected audio flags (from saa7134 driver) */
680 static void get_inf_dev_status(struct v4l2_subdev *sd,
681 int *dual_flag, int *stereo_flag)
683 u32 reg_data3;
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)",
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",
700 [0x0c] = "M Korea",
701 [0x0d] = "M BTSC ",
702 [0x0e] = "M EIAJ",
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",
709 [0x13 ... 0x1e] = "unknown",
710 [0x1f] = "??? [in progress]",
714 *dual_flag = *stereo_flag = 0;
716 /* (demdec status: 0x528) */
718 /* read current status */
719 reg_data3 = saa717x_read(sd, 0x0528);
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 " : "",
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 " : "",
738 (reg_data3 & 0x010000) ? " NICST " : "",
739 (reg_data3 & 0x020000) ? " NICDU " : "",
740 (reg_data3 & 0x040000) ? " NICAM muted " : "",
741 (reg_data3 & 0x080000) ? " NICAM reserve sound " : "",
743 (reg_data3 & 0x100000) ? " init done " : "");
745 if (reg_data3 & 0x000220) {
746 v4l2_dbg(1, debug, sd, "ST!!!\n");
747 *stereo_flag = 1;
750 if (reg_data3 & 0x000140) {
751 v4l2_dbg(1, debug, sd, "DUAL!!!\n");
752 *dual_flag = 1;
756 /* regs write to set audio mode */
757 static void set_audio_mode(struct v4l2_subdev *sd, int audio_mode)
759 v4l2_dbg(1, debug, sd, "writing registers to set audio mode by set %d\n",
760 audio_mode);
762 saa717x_write(sd, 0x46c, reg_set_audio_template[audio_mode][0]);
763 saa717x_write(sd, 0x470, reg_set_audio_template[audio_mode][1]);
766 /* write regs to set audio volume, bass and treble */
767 static int set_audio_regs(struct v4l2_subdev *sd,
768 struct saa717x_state *decoder)
770 u8 mute = 0xac; /* -84 dB */
771 u32 val;
772 unsigned int work_l, work_r;
774 /* set SIF analog I/O select */
775 saa717x_write(sd, 0x0594, decoder->audio_input);
776 v4l2_dbg(1, debug, sd, "set audio input %d\n",
777 decoder->audio_input);
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;
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);
796 saa717x_write(sd, 0x480, val);
798 /* set bass and treble */
799 val = decoder->audio_main_bass & 0x1f;
800 val |= (decoder->audio_main_treble & 0x1f) << 5;
801 saa717x_write(sd, 0x488, val);
802 return 0;
805 /********** scaling staff ***********/
806 static void set_h_prescale(struct v4l2_subdev *sd,
807 int task, int prescale)
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 },
828 static const int count = ARRAY_SIZE(vals);
829 int i, task_shift;
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;
838 /* horizontal prescaling */
839 saa717x_write(sd, 0x60 + task_shift, vals[i].xpsc);
840 /* accumulation length */
841 saa717x_write(sd, 0x61 + task_shift, vals[i].xacl);
842 /* level control */
843 saa717x_write(sd, 0x62 + task_shift,
844 (vals[i].xc2_1 << 3) | vals[i].xdcg);
845 /*FIR prefilter control */
846 saa717x_write(sd, 0x63 + task_shift,
847 (vals[i].vpfy << 2) | vals[i].vpfy);
850 /********** scaling staff ***********/
851 static void set_v_scale(struct v4l2_subdev *sd, int task, int yscale)
853 int task_shift;
855 task_shift = task * 0x40;
856 /* Vertical scaling ratio (LOW) */
857 saa717x_write(sd, 0x70 + task_shift, yscale & 0xff);
858 /* Vertical scaling ratio (HI) */
859 saa717x_write(sd, 0x71 + task_shift, yscale >> 8);
862 static int saa717x_s_ctrl(struct v4l2_ctrl *ctrl)
864 struct v4l2_subdev *sd = to_sd(ctrl);
865 struct saa717x_state *state = to_state(sd);
867 switch (ctrl->id) {
868 case V4L2_CID_BRIGHTNESS:
869 saa717x_write(sd, 0x10a, ctrl->val);
870 return 0;
872 case V4L2_CID_CONTRAST:
873 saa717x_write(sd, 0x10b, ctrl->val);
874 return 0;
876 case V4L2_CID_SATURATION:
877 saa717x_write(sd, 0x10c, ctrl->val);
878 return 0;
880 case V4L2_CID_HUE:
881 saa717x_write(sd, 0x10d, ctrl->val);
882 return 0;
884 case V4L2_CID_AUDIO_MUTE:
885 state->audio_main_mute = ctrl->val;
886 break;
888 case V4L2_CID_AUDIO_VOLUME:
889 state->audio_main_volume = ctrl->val;
890 break;
892 case V4L2_CID_AUDIO_BALANCE:
893 state->audio_main_balance = ctrl->val;
894 break;
896 case V4L2_CID_AUDIO_TREBLE:
897 state->audio_main_treble = ctrl->val;
898 break;
900 case V4L2_CID_AUDIO_BASS:
901 state->audio_main_bass = ctrl->val;
902 break;
904 default:
905 return 0;
907 set_audio_regs(sd, state);
908 return 0;
911 static int saa717x_s_video_routing(struct v4l2_subdev *sd,
912 u32 input, u32 output, u32 config)
914 struct saa717x_state *decoder = to_state(sd);
915 int is_tuner = input & 0x80; /* tuner input flag */
917 input &= 0x7f;
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;
925 if (decoder->input != input) {
926 int input_line = input;
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);
933 /* select mode */
934 saa717x_write(sd, 0x102,
935 (saa717x_read(sd, 0x102) & 0xf0) |
936 input_line);
938 /* bypass chrominance trap for modes 6..9 */
939 saa717x_write(sd, 0x109,
940 (saa717x_read(sd, 0x109) & 0x7f) |
941 (input_line < 6 ? 0x0 : 0x80));
943 /* change audio_mode */
944 if (is_tuner) {
945 /* tuner */
946 set_audio_mode(sd, 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);
952 /* change initialize procedure (Composite/S-Video) */
953 if (is_tuner)
954 saa717x_write_regs(sd, reg_init_tuner_input);
955 else if (input_line >= 6)
956 saa717x_write_regs(sd, reg_init_svideo_input);
957 else
958 saa717x_write_regs(sd, reg_init_composite_input);
961 return 0;
964 #ifdef CONFIG_VIDEO_ADV_DEBUG
965 static int saa717x_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
967 reg->val = saa717x_read(sd, reg->reg);
968 reg->size = 1;
969 return 0;
972 static int saa717x_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
974 u16 addr = reg->reg & 0xffff;
975 u8 val = reg->val & 0xff;
977 saa717x_write(sd, addr, val);
978 return 0;
980 #endif
982 static int saa717x_set_fmt(struct v4l2_subdev *sd,
983 struct v4l2_subdev_pad_config *cfg,
984 struct v4l2_subdev_format *format)
986 struct v4l2_mbus_framefmt *fmt = &format->format;
987 int prescale, h_scale, v_scale;
989 v4l2_dbg(1, debug, sd, "decoder set size\n");
991 if (format->pad || fmt->code != MEDIA_BUS_FMT_FIXED)
992 return -EINVAL;
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;
1000 fmt->field = V4L2_FIELD_INTERLACED;
1001 fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
1003 if (format->which == V4L2_SUBDEV_FORMAT_TRY)
1004 return 0;
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;
1015 /* Horizontal prescaling etc */
1016 set_h_prescale(sd, 0, prescale);
1017 set_h_prescale(sd, 1, prescale);
1019 /* Horizontal scaling increment */
1020 /* TASK A */
1021 saa717x_write(sd, 0x6C, (u8)(h_scale & 0xFF));
1022 saa717x_write(sd, 0x6D, (u8)((h_scale >> 8) & 0xFF));
1023 /* TASK B */
1024 saa717x_write(sd, 0xAC, (u8)(h_scale & 0xFF));
1025 saa717x_write(sd, 0xAD, (u8)((h_scale >> 8) & 0xFF));
1027 /* Vertical prescaling etc */
1028 set_v_scale(sd, 0, v_scale);
1029 set_v_scale(sd, 1, v_scale);
1031 /* set video output size */
1032 /* video number of pixels at output */
1033 /* TASK A */
1034 saa717x_write(sd, 0x5C, (u8)(fmt->width & 0xFF));
1035 saa717x_write(sd, 0x5D, (u8)((fmt->width >> 8) & 0xFF));
1036 /* TASK B */
1037 saa717x_write(sd, 0x9C, (u8)(fmt->width & 0xFF));
1038 saa717x_write(sd, 0x9D, (u8)((fmt->width >> 8) & 0xFF));
1040 /* video number of lines at output */
1041 /* TASK A */
1042 saa717x_write(sd, 0x5E, (u8)(fmt->height & 0xFF));
1043 saa717x_write(sd, 0x5F, (u8)((fmt->height >> 8) & 0xFF));
1044 /* TASK B */
1045 saa717x_write(sd, 0x9E, (u8)(fmt->height & 0xFF));
1046 saa717x_write(sd, 0x9F, (u8)((fmt->height >> 8) & 0xFF));
1047 return 0;
1050 static int saa717x_s_radio(struct v4l2_subdev *sd)
1052 struct saa717x_state *decoder = to_state(sd);
1054 decoder->radio = 1;
1055 return 0;
1058 static int saa717x_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
1060 struct saa717x_state *decoder = to_state(sd);
1062 v4l2_dbg(1, debug, sd, "decoder set norm ");
1063 v4l2_dbg(1, debug, sd, "(not yet implemented)\n");
1065 decoder->radio = 0;
1066 decoder->std = std;
1067 return 0;
1070 static int saa717x_s_audio_routing(struct v4l2_subdev *sd,
1071 u32 input, u32 output, u32 config)
1073 struct saa717x_state *decoder = to_state(sd);
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;
1083 return -ERANGE;
1086 static int saa717x_s_stream(struct v4l2_subdev *sd, int enable)
1088 struct saa717x_state *decoder = to_state(sd);
1090 v4l2_dbg(1, debug, sd, "decoder %s output\n",
1091 enable ? "enable" : "disable");
1092 decoder->enable = enable;
1093 saa717x_write(sd, 0x193, enable ? 0xa6 : 0x26);
1094 return 0;
1097 /* change audio mode */
1098 static int saa717x_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *vt)
1100 struct saa717x_state *decoder = to_state(sd);
1101 int audio_mode;
1102 char *mes[4] = {
1103 "MONO", "STEREO", "LANG1", "LANG2/SAP"
1106 audio_mode = TUNER_AUDIO_STEREO;
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;
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, decoder->tuner_audio_mode);
1129 return 0;
1132 static int saa717x_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
1134 struct saa717x_state *decoder = to_state(sd);
1135 int dual_f, stereo_f;
1137 if (decoder->radio)
1138 return 0;
1139 get_inf_dev_status(sd, &dual_f, &stereo_f);
1141 v4l2_dbg(1, debug, sd, "DETECT==st:%d dual:%d\n",
1142 stereo_f, dual_f);
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");
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");
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");
1172 return 0;
1175 static int saa717x_log_status(struct v4l2_subdev *sd)
1177 struct saa717x_state *state = to_state(sd);
1179 v4l2_ctrl_handler_log_status(&state->hdl, sd->name);
1180 return 0;
1183 /* ----------------------------------------------------------------------- */
1185 static const struct v4l2_ctrl_ops saa717x_ctrl_ops = {
1186 .s_ctrl = saa717x_s_ctrl,
1189 static 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,
1197 static 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,
1203 static 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,
1209 static const struct v4l2_subdev_audio_ops saa717x_audio_ops = {
1210 .s_routing = saa717x_s_audio_routing,
1213 static const struct v4l2_subdev_pad_ops saa717x_pad_ops = {
1214 .set_fmt = saa717x_set_fmt,
1217 static 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,
1225 /* ----------------------------------------------------------------------- */
1228 /* i2c implementation */
1230 /* ----------------------------------------------------------------------- */
1231 static int saa717x_probe(struct i2c_client *client,
1232 const struct i2c_device_id *did)
1234 struct saa717x_state *decoder;
1235 struct v4l2_ctrl_handler *hdl;
1236 struct v4l2_subdev *sd;
1237 u8 id = 0;
1238 char *p = "";
1240 /* Check if the adapter supports the needed features */
1241 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
1242 return -EIO;
1244 decoder = devm_kzalloc(&client->dev, sizeof(*decoder), GFP_KERNEL);
1245 if (decoder == NULL)
1246 return -ENOMEM;
1248 sd = &decoder->sd;
1249 v4l2_i2c_subdev_init(sd, client, &saa717x_ops);
1251 if (saa717x_write(sd, 0x5a4, 0xfe) &&
1252 saa717x_write(sd, 0x5a5, 0x0f) &&
1253 saa717x_write(sd, 0x5a6, 0x00) &&
1254 saa717x_write(sd, 0x5a7, 0x01))
1255 id = saa717x_read(sd, 0x5a0);
1256 if (id != 0xc2 && id != 0x32 && id != 0xf2 && id != 0x6c) {
1257 v4l2_dbg(1, debug, sd, "saa717x not found (id=%02x)\n", id);
1258 return -ENODEV;
1260 if (id == 0xc2)
1261 p = "saa7173";
1262 else if (id == 0x32)
1263 p = "saa7174A";
1264 else if (id == 0x6c)
1265 p = "saa7174HL";
1266 else
1267 p = "saa7171";
1268 v4l2_info(sd, "%s found @ 0x%x (%s)\n", p,
1269 client->addr << 1, client->adapter->name);
1271 hdl = &decoder->hdl;
1272 v4l2_ctrl_handler_init(hdl, 9);
1273 /* add in ascending ID order */
1274 v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
1275 V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
1276 v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
1277 V4L2_CID_CONTRAST, 0, 255, 1, 68);
1278 v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
1279 V4L2_CID_SATURATION, 0, 255, 1, 64);
1280 v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
1281 V4L2_CID_HUE, -128, 127, 1, 0);
1282 v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
1283 V4L2_CID_AUDIO_VOLUME, 0, 65535, 65535 / 100, 42000);
1284 v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
1285 V4L2_CID_AUDIO_BALANCE, 0, 65535, 65535 / 100, 32768);
1286 v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
1287 V4L2_CID_AUDIO_BASS, -16, 15, 1, 0);
1288 v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
1289 V4L2_CID_AUDIO_TREBLE, -16, 15, 1, 0);
1290 v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
1291 V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0);
1292 sd->ctrl_handler = hdl;
1293 if (hdl->error) {
1294 int err = hdl->error;
1296 v4l2_ctrl_handler_free(hdl);
1297 return err;
1300 decoder->std = V4L2_STD_NTSC;
1301 decoder->input = -1;
1302 decoder->enable = 1;
1304 /* FIXME!! */
1305 decoder->playback = 0; /* initially capture mode used */
1306 decoder->audio = 1; /* DECODER_AUDIO_48_KHZ */
1308 decoder->audio_input = 2; /* FIXME!! */
1310 decoder->tuner_audio_mode = TUNER_AUDIO_STEREO;
1311 /* set volume, bass and treble */
1312 decoder->audio_main_vol_l = 6;
1313 decoder->audio_main_vol_r = 6;
1315 v4l2_dbg(1, debug, sd, "writing init values\n");
1317 /* FIXME!! */
1318 saa717x_write_regs(sd, reg_init_initialize);
1320 v4l2_ctrl_handler_setup(hdl);
1322 set_current_state(TASK_INTERRUPTIBLE);
1323 schedule_timeout(2*HZ);
1324 return 0;
1327 static int saa717x_remove(struct i2c_client *client)
1329 struct v4l2_subdev *sd = i2c_get_clientdata(client);
1331 v4l2_device_unregister_subdev(sd);
1332 v4l2_ctrl_handler_free(sd->ctrl_handler);
1333 return 0;
1336 /* ----------------------------------------------------------------------- */
1338 static const struct i2c_device_id saa717x_id[] = {
1339 { "saa717x", 0 },
1342 MODULE_DEVICE_TABLE(i2c, saa717x_id);
1344 static struct i2c_driver saa717x_driver = {
1345 .driver = {
1346 .name = "saa717x",
1348 .probe = saa717x_probe,
1349 .remove = saa717x_remove,
1350 .id_table = saa717x_id,
1353 module_i2c_driver(saa717x_driver);