blob: 71328109642e15ccef16aa5e2ac18da972c86ed6 [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
43MODULE_DESCRIPTION("Philips SAA717x audio/video decoder driver");
44MODULE_AUTHOR("K. Ohta, T. Adachi, Hans Verkuil");
45MODULE_LICENSE("GPL");
46
47static int debug;
48module_param(debug, int, 0644);
49MODULE_PARM_DESC(debug, "Debug level (0-1)");
50
51/*
52 * Generic i2c probe
53 * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
54 */
55
56struct saa717x_state {
Hans Verkuil27760fc2008-11-29 12:57:44 -030057 struct v4l2_subdev sd;
Hans Verkuil59b83112010-04-23 09:04:48 -030058 struct v4l2_ctrl_handler hdl;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -030059 v4l2_std_id std;
60 int input;
61 int enable;
62 int radio;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -030063 int playback;
64 int audio;
65 int tuner_audio_mode;
66 int audio_main_mute;
67 int audio_main_vol_r;
68 int audio_main_vol_l;
69 u16 audio_main_bass;
70 u16 audio_main_treble;
71 u16 audio_main_volume;
72 u16 audio_main_balance;
73 int audio_input;
74};
75
Hans Verkuil27760fc2008-11-29 12:57:44 -030076static inline struct saa717x_state *to_state(struct v4l2_subdev *sd)
77{
78 return container_of(sd, struct saa717x_state, sd);
79}
80
Hans Verkuil59b83112010-04-23 09:04:48 -030081static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
82{
83 return &container_of(ctrl->handler, struct saa717x_state, hdl)->sd;
84}
85
Hans Verkuilfb7b37c2008-04-09 06:26:17 -030086/* ----------------------------------------------------------------------- */
87
88/* for audio mode */
89#define TUNER_AUDIO_MONO 0 /* LL */
90#define TUNER_AUDIO_STEREO 1 /* LR */
91#define TUNER_AUDIO_LANG1 2 /* LL */
92#define TUNER_AUDIO_LANG2 3 /* RR */
93
94#define SAA717X_NTSC_WIDTH (704)
95#define SAA717X_NTSC_HEIGHT (480)
96
97/* ----------------------------------------------------------------------- */
98
Hans Verkuil27760fc2008-11-29 12:57:44 -030099static int saa717x_write(struct v4l2_subdev *sd, u32 reg, u32 value)
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300100{
Hans Verkuil27760fc2008-11-29 12:57:44 -0300101 struct i2c_client *client = v4l2_get_subdevdata(sd);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300102 struct i2c_adapter *adap = client->adapter;
103 int fw_addr = reg == 0x454 || (reg >= 0x464 && reg <= 0x478) || reg == 0x480 || reg == 0x488;
104 unsigned char mm1[6];
105 struct i2c_msg msg;
106
107 msg.flags = 0;
108 msg.addr = client->addr;
109 mm1[0] = (reg >> 8) & 0xff;
110 mm1[1] = reg & 0xff;
111
112 if (fw_addr) {
113 mm1[4] = (value >> 16) & 0xff;
114 mm1[3] = (value >> 8) & 0xff;
115 mm1[2] = value & 0xff;
116 } else {
117 mm1[2] = value & 0xff;
118 }
119 msg.len = fw_addr ? 5 : 3; /* Long Registers have *only* three bytes! */
120 msg.buf = mm1;
Hans Verkuil27760fc2008-11-29 12:57:44 -0300121 v4l2_dbg(2, debug, sd, "wrote: reg 0x%03x=%08x\n", reg, value);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300122 return i2c_transfer(adap, &msg, 1) == 1;
123}
124
Hans Verkuil27760fc2008-11-29 12:57:44 -0300125static void saa717x_write_regs(struct v4l2_subdev *sd, u32 *data)
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300126{
127 while (data[0] || data[1]) {
Hans Verkuil27760fc2008-11-29 12:57:44 -0300128 saa717x_write(sd, data[0], data[1]);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300129 data += 2;
130 }
131}
132
Hans Verkuil27760fc2008-11-29 12:57:44 -0300133static u32 saa717x_read(struct v4l2_subdev *sd, u32 reg)
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300134{
Hans Verkuil27760fc2008-11-29 12:57:44 -0300135 struct i2c_client *client = v4l2_get_subdevdata(sd);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300136 struct i2c_adapter *adap = client->adapter;
137 int fw_addr = (reg >= 0x404 && reg <= 0x4b8) || reg == 0x528;
138 unsigned char mm1[2];
139 unsigned char mm2[4] = { 0, 0, 0, 0 };
140 struct i2c_msg msgs[2];
141 u32 value;
142
143 msgs[0].flags = 0;
144 msgs[1].flags = I2C_M_RD;
145 msgs[0].addr = msgs[1].addr = client->addr;
146 mm1[0] = (reg >> 8) & 0xff;
147 mm1[1] = reg & 0xff;
148 msgs[0].len = 2;
149 msgs[0].buf = mm1;
150 msgs[1].len = fw_addr ? 3 : 1; /* Multibyte Registers contains *only* 3 bytes */
151 msgs[1].buf = mm2;
152 i2c_transfer(adap, msgs, 2);
153
154 if (fw_addr)
155 value = (mm2[2] & 0xff) | ((mm2[1] & 0xff) >> 8) | ((mm2[0] & 0xff) >> 16);
156 else
157 value = mm2[0] & 0xff;
158
Hans Verkuil27760fc2008-11-29 12:57:44 -0300159 v4l2_dbg(2, debug, sd, "read: reg 0x%03x=0x%08x\n", reg, value);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300160 return value;
161}
162
163/* ----------------------------------------------------------------------- */
164
165static u32 reg_init_initialize[] =
166{
167 /* from linux driver */
168 0x101, 0x008, /* Increment delay */
169
170 0x103, 0x000, /* Analog input control 2 */
171 0x104, 0x090, /* Analog input control 3 */
172 0x105, 0x090, /* Analog input control 4 */
173 0x106, 0x0eb, /* Horizontal sync start */
174 0x107, 0x0e0, /* Horizontal sync stop */
175 0x109, 0x055, /* Luminance control */
176
177 0x10f, 0x02a, /* Chroma gain control */
178 0x110, 0x000, /* Chroma control 2 */
179
180 0x114, 0x045, /* analog/ADC */
181
182 0x118, 0x040, /* RAW data gain */
183 0x119, 0x080, /* RAW data offset */
184
185 0x044, 0x000, /* VBI horizontal input window start (L) TASK A */
186 0x045, 0x000, /* VBI horizontal input window start (H) TASK A */
187 0x046, 0x0cf, /* VBI horizontal input window stop (L) TASK A */
188 0x047, 0x002, /* VBI horizontal input window stop (H) TASK A */
189
190 0x049, 0x000, /* VBI vertical input window start (H) TASK A */
191
192 0x04c, 0x0d0, /* VBI horizontal output length (L) TASK A */
193 0x04d, 0x002, /* VBI horizontal output length (H) TASK A */
194
195 0x064, 0x080, /* Lumina brightness TASK A */
196 0x065, 0x040, /* Luminance contrast TASK A */
197 0x066, 0x040, /* Chroma saturation TASK A */
198 /* 067H: Reserved */
199 0x068, 0x000, /* VBI horizontal scaling increment (L) TASK A */
200 0x069, 0x004, /* VBI horizontal scaling increment (H) TASK A */
201 0x06a, 0x000, /* VBI phase offset TASK A */
202
203 0x06e, 0x000, /* Horizontal phase offset Luma TASK A */
204 0x06f, 0x000, /* Horizontal phase offset Chroma TASK A */
205
206 0x072, 0x000, /* Vertical filter mode TASK A */
207
208 0x084, 0x000, /* VBI horizontal input window start (L) TAKS B */
209 0x085, 0x000, /* VBI horizontal input window start (H) TAKS B */
210 0x086, 0x0cf, /* VBI horizontal input window stop (L) TAKS B */
211 0x087, 0x002, /* VBI horizontal input window stop (H) TAKS B */
212
213 0x089, 0x000, /* VBI vertical input window start (H) TAKS B */
214
215 0x08c, 0x0d0, /* VBI horizontal output length (L) TASK B */
216 0x08d, 0x002, /* VBI horizontal output length (H) TASK B */
217
218 0x0a4, 0x080, /* Lumina brightness TASK B */
219 0x0a5, 0x040, /* Luminance contrast TASK B */
220 0x0a6, 0x040, /* Chroma saturation TASK B */
221 /* 0A7H reserved */
222 0x0a8, 0x000, /* VBI horizontal scaling increment (L) TASK B */
223 0x0a9, 0x004, /* VBI horizontal scaling increment (H) TASK B */
224 0x0aa, 0x000, /* VBI phase offset TASK B */
225
226 0x0ae, 0x000, /* Horizontal phase offset Luma TASK B */
227 0x0af, 0x000, /*Horizontal phase offset Chroma TASK B */
228
229 0x0b2, 0x000, /* Vertical filter mode TASK B */
230
231 0x00c, 0x000, /* Start point GREEN path */
232 0x00d, 0x000, /* Start point BLUE path */
233 0x00e, 0x000, /* Start point RED path */
234
235 0x010, 0x010, /* GREEN path gamma curve --- */
236 0x011, 0x020,
237 0x012, 0x030,
238 0x013, 0x040,
239 0x014, 0x050,
240 0x015, 0x060,
241 0x016, 0x070,
242 0x017, 0x080,
243 0x018, 0x090,
244 0x019, 0x0a0,
245 0x01a, 0x0b0,
246 0x01b, 0x0c0,
247 0x01c, 0x0d0,
248 0x01d, 0x0e0,
249 0x01e, 0x0f0,
250 0x01f, 0x0ff, /* --- GREEN path gamma curve */
251
252 0x020, 0x010, /* BLUE path gamma curve --- */
253 0x021, 0x020,
254 0x022, 0x030,
255 0x023, 0x040,
256 0x024, 0x050,
257 0x025, 0x060,
258 0x026, 0x070,
259 0x027, 0x080,
260 0x028, 0x090,
261 0x029, 0x0a0,
262 0x02a, 0x0b0,
263 0x02b, 0x0c0,
264 0x02c, 0x0d0,
265 0x02d, 0x0e0,
266 0x02e, 0x0f0,
267 0x02f, 0x0ff, /* --- BLUE path gamma curve */
268
269 0x030, 0x010, /* RED path gamma curve --- */
270 0x031, 0x020,
271 0x032, 0x030,
272 0x033, 0x040,
273 0x034, 0x050,
274 0x035, 0x060,
275 0x036, 0x070,
276 0x037, 0x080,
277 0x038, 0x090,
278 0x039, 0x0a0,
279 0x03a, 0x0b0,
280 0x03b, 0x0c0,
281 0x03c, 0x0d0,
282 0x03d, 0x0e0,
283 0x03e, 0x0f0,
284 0x03f, 0x0ff, /* --- RED path gamma curve */
285
286 0x109, 0x085, /* Luminance control */
287
288 /**** from app start ****/
289 0x584, 0x000, /* AGC gain control */
290 0x585, 0x000, /* Program count */
291 0x586, 0x003, /* Status reset */
292 0x588, 0x0ff, /* Number of audio samples (L) */
293 0x589, 0x00f, /* Number of audio samples (M) */
294 0x58a, 0x000, /* Number of audio samples (H) */
295 0x58b, 0x000, /* Audio select */
296 0x58c, 0x010, /* Audio channel assign1 */
297 0x58d, 0x032, /* Audio channel assign2 */
298 0x58e, 0x054, /* Audio channel assign3 */
299 0x58f, 0x023, /* Audio format */
300 0x590, 0x000, /* SIF control */
301
302 0x595, 0x000, /* ?? */
303 0x596, 0x000, /* ?? */
304 0x597, 0x000, /* ?? */
305
306 0x464, 0x00, /* Digital input crossbar1 */
307
308 0x46c, 0xbbbb10, /* Digital output selection1-3 */
309 0x470, 0x101010, /* Digital output selection4-6 */
310
311 0x478, 0x00, /* Sound feature control */
312
313 0x474, 0x18, /* Softmute control */
314
315 0x454, 0x0425b9, /* Sound Easy programming(reset) */
316 0x454, 0x042539, /* Sound Easy programming(reset) */
317
318
319 /**** common setting( of DVD play, including scaler commands) ****/
320 0x042, 0x003, /* Data path configuration for VBI (TASK A) */
321
322 0x082, 0x003, /* Data path configuration for VBI (TASK B) */
323
324 0x108, 0x0f8, /* Sync control */
325 0x2a9, 0x0fd, /* ??? */
326 0x102, 0x089, /* select video input "mode 9" */
327 0x111, 0x000, /* Mode/delay control */
328
329 0x10e, 0x00a, /* Chroma control 1 */
330
331 0x594, 0x002, /* SIF, analog I/O select */
332
333 0x454, 0x0425b9, /* Sound */
334 0x454, 0x042539,
335
336 0x111, 0x000,
337 0x10e, 0x00a,
338 0x464, 0x000,
339 0x300, 0x000,
340 0x301, 0x006,
341 0x302, 0x000,
342 0x303, 0x006,
343 0x308, 0x040,
344 0x309, 0x000,
345 0x30a, 0x000,
346 0x30b, 0x000,
347 0x000, 0x002,
348 0x001, 0x000,
349 0x002, 0x000,
350 0x003, 0x000,
351 0x004, 0x033,
352 0x040, 0x01d,
353 0x041, 0x001,
354 0x042, 0x004,
355 0x043, 0x000,
356 0x080, 0x01e,
357 0x081, 0x001,
358 0x082, 0x004,
359 0x083, 0x000,
360 0x190, 0x018,
361 0x115, 0x000,
362 0x116, 0x012,
363 0x117, 0x018,
364 0x04a, 0x011,
365 0x08a, 0x011,
366 0x04b, 0x000,
367 0x08b, 0x000,
368 0x048, 0x000,
369 0x088, 0x000,
370 0x04e, 0x012,
371 0x08e, 0x012,
372 0x058, 0x012,
373 0x098, 0x012,
374 0x059, 0x000,
375 0x099, 0x000,
376 0x05a, 0x003,
377 0x09a, 0x003,
378 0x05b, 0x001,
379 0x09b, 0x001,
380 0x054, 0x008,
381 0x094, 0x008,
382 0x055, 0x000,
383 0x095, 0x000,
384 0x056, 0x0c7,
385 0x096, 0x0c7,
386 0x057, 0x002,
387 0x097, 0x002,
388 0x0ff, 0x0ff,
389 0x060, 0x001,
390 0x0a0, 0x001,
391 0x061, 0x000,
392 0x0a1, 0x000,
393 0x062, 0x000,
394 0x0a2, 0x000,
395 0x063, 0x000,
396 0x0a3, 0x000,
397 0x070, 0x000,
398 0x0b0, 0x000,
399 0x071, 0x004,
400 0x0b1, 0x004,
401 0x06c, 0x0e9,
402 0x0ac, 0x0e9,
403 0x06d, 0x003,
404 0x0ad, 0x003,
405 0x05c, 0x0d0,
406 0x09c, 0x0d0,
407 0x05d, 0x002,
408 0x09d, 0x002,
409 0x05e, 0x0f2,
410 0x09e, 0x0f2,
411 0x05f, 0x000,
412 0x09f, 0x000,
413 0x074, 0x000,
414 0x0b4, 0x000,
415 0x075, 0x000,
416 0x0b5, 0x000,
417 0x076, 0x000,
418 0x0b6, 0x000,
419 0x077, 0x000,
420 0x0b7, 0x000,
421 0x195, 0x008,
422 0x0ff, 0x0ff,
423 0x108, 0x0f8,
424 0x111, 0x000,
425 0x10e, 0x00a,
426 0x2a9, 0x0fd,
427 0x464, 0x001,
428 0x454, 0x042135,
429 0x598, 0x0e7,
430 0x599, 0x07d,
431 0x59a, 0x018,
432 0x59c, 0x066,
433 0x59d, 0x090,
434 0x59e, 0x001,
435 0x584, 0x000,
436 0x585, 0x000,
437 0x586, 0x003,
438 0x588, 0x0ff,
439 0x589, 0x00f,
440 0x58a, 0x000,
441 0x58b, 0x000,
442 0x58c, 0x010,
443 0x58d, 0x032,
444 0x58e, 0x054,
445 0x58f, 0x023,
446 0x590, 0x000,
447 0x595, 0x000,
448 0x596, 0x000,
449 0x597, 0x000,
450 0x464, 0x000,
451 0x46c, 0xbbbb10,
452 0x470, 0x101010,
453
454
455 0x478, 0x000,
456 0x474, 0x018,
457 0x454, 0x042135,
458 0x598, 0x0e7,
459 0x599, 0x07d,
460 0x59a, 0x018,
461 0x59c, 0x066,
462 0x59d, 0x090,
463 0x59e, 0x001,
464 0x584, 0x000,
465 0x585, 0x000,
466 0x586, 0x003,
467 0x588, 0x0ff,
468 0x589, 0x00f,
469 0x58a, 0x000,
470 0x58b, 0x000,
471 0x58c, 0x010,
472 0x58d, 0x032,
473 0x58e, 0x054,
474 0x58f, 0x023,
475 0x590, 0x000,
476 0x595, 0x000,
477 0x596, 0x000,
478 0x597, 0x000,
479 0x464, 0x000,
480 0x46c, 0xbbbb10,
481 0x470, 0x101010,
482
483 0x478, 0x000,
484 0x474, 0x018,
485 0x454, 0x042135,
486 0x598, 0x0e7,
487 0x599, 0x07d,
488 0x59a, 0x018,
489 0x59c, 0x066,
490 0x59d, 0x090,
491 0x59e, 0x001,
492 0x584, 0x000,
493 0x585, 0x000,
494 0x586, 0x003,
495 0x588, 0x0ff,
496 0x589, 0x00f,
497 0x58a, 0x000,
498 0x58b, 0x000,
499 0x58c, 0x010,
500 0x58d, 0x032,
501 0x58e, 0x054,
502 0x58f, 0x023,
503 0x590, 0x000,
504 0x595, 0x000,
505 0x596, 0x000,
506 0x597, 0x000,
507 0x464, 0x000,
508 0x46c, 0xbbbb10,
509 0x470, 0x101010,
510 0x478, 0x000,
511 0x474, 0x018,
512 0x454, 0x042135,
513 0x193, 0x000,
514 0x300, 0x000,
515 0x301, 0x006,
516 0x302, 0x000,
517 0x303, 0x006,
518 0x308, 0x040,
519 0x309, 0x000,
520 0x30a, 0x000,
521 0x30b, 0x000,
522 0x000, 0x002,
523 0x001, 0x000,
524 0x002, 0x000,
525 0x003, 0x000,
526 0x004, 0x033,
527 0x040, 0x01d,
528 0x041, 0x001,
529 0x042, 0x004,
530 0x043, 0x000,
531 0x080, 0x01e,
532 0x081, 0x001,
533 0x082, 0x004,
534 0x083, 0x000,
535 0x190, 0x018,
536 0x115, 0x000,
537 0x116, 0x012,
538 0x117, 0x018,
539 0x04a, 0x011,
540 0x08a, 0x011,
541 0x04b, 0x000,
542 0x08b, 0x000,
543 0x048, 0x000,
544 0x088, 0x000,
545 0x04e, 0x012,
546 0x08e, 0x012,
547 0x058, 0x012,
548 0x098, 0x012,
549 0x059, 0x000,
550 0x099, 0x000,
551 0x05a, 0x003,
552 0x09a, 0x003,
553 0x05b, 0x001,
554 0x09b, 0x001,
555 0x054, 0x008,
556 0x094, 0x008,
557 0x055, 0x000,
558 0x095, 0x000,
559 0x056, 0x0c7,
560 0x096, 0x0c7,
561 0x057, 0x002,
562 0x097, 0x002,
563 0x060, 0x001,
564 0x0a0, 0x001,
565 0x061, 0x000,
566 0x0a1, 0x000,
567 0x062, 0x000,
568 0x0a2, 0x000,
569 0x063, 0x000,
570 0x0a3, 0x000,
571 0x070, 0x000,
572 0x0b0, 0x000,
573 0x071, 0x004,
574 0x0b1, 0x004,
575 0x06c, 0x0e9,
576 0x0ac, 0x0e9,
577 0x06d, 0x003,
578 0x0ad, 0x003,
579 0x05c, 0x0d0,
580 0x09c, 0x0d0,
581 0x05d, 0x002,
582 0x09d, 0x002,
583 0x05e, 0x0f2,
584 0x09e, 0x0f2,
585 0x05f, 0x000,
586 0x09f, 0x000,
587 0x074, 0x000,
588 0x0b4, 0x000,
589 0x075, 0x000,
590 0x0b5, 0x000,
591 0x076, 0x000,
592 0x0b6, 0x000,
593 0x077, 0x000,
594 0x0b7, 0x000,
595 0x195, 0x008,
596 0x598, 0x0e7,
597 0x599, 0x07d,
598 0x59a, 0x018,
599 0x59c, 0x066,
600 0x59d, 0x090,
601 0x59e, 0x001,
602 0x584, 0x000,
603 0x585, 0x000,
604 0x586, 0x003,
605 0x588, 0x0ff,
606 0x589, 0x00f,
607 0x58a, 0x000,
608 0x58b, 0x000,
609 0x58c, 0x010,
610 0x58d, 0x032,
611 0x58e, 0x054,
612 0x58f, 0x023,
613 0x590, 0x000,
614 0x595, 0x000,
615 0x596, 0x000,
616 0x597, 0x000,
617 0x464, 0x000,
618 0x46c, 0xbbbb10,
619 0x470, 0x101010,
620 0x478, 0x000,
621 0x474, 0x018,
622 0x454, 0x042135,
623 0x193, 0x0a6,
624 0x108, 0x0f8,
625 0x042, 0x003,
626 0x082, 0x003,
627 0x454, 0x0425b9,
628 0x454, 0x042539,
629 0x193, 0x000,
630 0x193, 0x0a6,
631 0x464, 0x000,
632
633 0, 0
634};
635
636/* Tuner */
637static u32 reg_init_tuner_input[] = {
638 0x108, 0x0f8, /* Sync control */
639 0x111, 0x000, /* Mode/delay control */
640 0x10e, 0x00a, /* Chroma control 1 */
641 0, 0
642};
643
644/* Composite */
645static u32 reg_init_composite_input[] = {
646 0x108, 0x0e8, /* Sync control */
647 0x111, 0x000, /* Mode/delay control */
648 0x10e, 0x04a, /* Chroma control 1 */
649 0, 0
650};
651
652/* S-Video */
653static u32 reg_init_svideo_input[] = {
654 0x108, 0x0e8, /* Sync control */
655 0x111, 0x000, /* Mode/delay control */
656 0x10e, 0x04a, /* Chroma control 1 */
657 0, 0
658};
659
660static u32 reg_set_audio_template[4][2] =
661{
662 { /* for MONO
663 tadachi 6/29 DMA audio output select?
664 Register 0x46c
665 7-4: DMA2, 3-0: DMA1 ch. DMA4, DMA3 DMA2, DMA1
666 0: MAIN left, 1: MAIN right
667 2: AUX1 left, 3: AUX1 right
668 4: AUX2 left, 5: AUX2 right
669 6: DPL left, 7: DPL right
670 8: DPL center, 9: DPL surround
671 A: monitor output, B: digital sense */
672 0xbbbb00,
673
674 /* tadachi 6/29 DAC and I2S output select?
675 Register 0x470
676 7-4:DAC right ch. 3-0:DAC left ch.
677 I2S1 right,left I2S2 right,left */
678 0x00,
679 },
680 { /* for STEREO */
681 0xbbbb10, 0x101010,
682 },
683 { /* for LANG1 */
684 0xbbbb00, 0x00,
685 },
686 { /* for LANG2/SAP */
687 0xbbbb11, 0x111111,
688 }
689};
690
691
692/* Get detected audio flags (from saa7134 driver) */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300693static void get_inf_dev_status(struct v4l2_subdev *sd,
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300694 int *dual_flag, int *stereo_flag)
695{
696 u32 reg_data3;
697
698 static char *stdres[0x20] = {
699 [0x00] = "no standard detected",
700 [0x01] = "B/G (in progress)",
701 [0x02] = "D/K (in progress)",
702 [0x03] = "M (in progress)",
703
704 [0x04] = "B/G A2",
705 [0x05] = "B/G NICAM",
706 [0x06] = "D/K A2 (1)",
707 [0x07] = "D/K A2 (2)",
708 [0x08] = "D/K A2 (3)",
709 [0x09] = "D/K NICAM",
710 [0x0a] = "L NICAM",
711 [0x0b] = "I NICAM",
712
713 [0x0c] = "M Korea",
714 [0x0d] = "M BTSC ",
715 [0x0e] = "M EIAJ",
716
717 [0x0f] = "FM radio / IF 10.7 / 50 deemp",
718 [0x10] = "FM radio / IF 10.7 / 75 deemp",
719 [0x11] = "FM radio / IF sel / 50 deemp",
720 [0x12] = "FM radio / IF sel / 75 deemp",
721
722 [0x13 ... 0x1e] = "unknown",
723 [0x1f] = "??? [in progress]",
724 };
725
726
727 *dual_flag = *stereo_flag = 0;
728
729 /* (demdec status: 0x528) */
730
731 /* read current status */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300732 reg_data3 = saa717x_read(sd, 0x0528);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300733
Hans Verkuil27760fc2008-11-29 12:57:44 -0300734 v4l2_dbg(1, debug, sd, "tvaudio thread status: 0x%x [%s%s%s]\n",
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300735 reg_data3, stdres[reg_data3 & 0x1f],
736 (reg_data3 & 0x000020) ? ",stereo" : "",
737 (reg_data3 & 0x000040) ? ",dual" : "");
Hans Verkuil27760fc2008-11-29 12:57:44 -0300738 v4l2_dbg(1, debug, sd, "detailed status: "
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300739 "%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s\n",
740 (reg_data3 & 0x000080) ? " A2/EIAJ pilot tone " : "",
741 (reg_data3 & 0x000100) ? " A2/EIAJ dual " : "",
742 (reg_data3 & 0x000200) ? " A2/EIAJ stereo " : "",
743 (reg_data3 & 0x000400) ? " A2/EIAJ noise mute " : "",
744
745 (reg_data3 & 0x000800) ? " BTSC/FM radio pilot " : "",
746 (reg_data3 & 0x001000) ? " SAP carrier " : "",
747 (reg_data3 & 0x002000) ? " BTSC stereo noise mute " : "",
748 (reg_data3 & 0x004000) ? " SAP noise mute " : "",
749 (reg_data3 & 0x008000) ? " VDSP " : "",
750
751 (reg_data3 & 0x010000) ? " NICST " : "",
752 (reg_data3 & 0x020000) ? " NICDU " : "",
753 (reg_data3 & 0x040000) ? " NICAM muted " : "",
754 (reg_data3 & 0x080000) ? " NICAM reserve sound " : "",
755
756 (reg_data3 & 0x100000) ? " init done " : "");
757
758 if (reg_data3 & 0x000220) {
Hans Verkuil27760fc2008-11-29 12:57:44 -0300759 v4l2_dbg(1, debug, sd, "ST!!!\n");
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300760 *stereo_flag = 1;
761 }
762
763 if (reg_data3 & 0x000140) {
Hans Verkuil27760fc2008-11-29 12:57:44 -0300764 v4l2_dbg(1, debug, sd, "DUAL!!!\n");
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300765 *dual_flag = 1;
766 }
767}
768
769/* regs write to set audio mode */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300770static void set_audio_mode(struct v4l2_subdev *sd, int audio_mode)
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300771{
Hans Verkuil27760fc2008-11-29 12:57:44 -0300772 v4l2_dbg(1, debug, sd, "writing registers to set audio mode by set %d\n",
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300773 audio_mode);
774
Hans Verkuil27760fc2008-11-29 12:57:44 -0300775 saa717x_write(sd, 0x46c, reg_set_audio_template[audio_mode][0]);
776 saa717x_write(sd, 0x470, reg_set_audio_template[audio_mode][1]);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300777}
778
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300779/* write regs to set audio volume, bass and treble */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300780static int set_audio_regs(struct v4l2_subdev *sd,
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300781 struct saa717x_state *decoder)
782{
783 u8 mute = 0xac; /* -84 dB */
784 u32 val;
785 unsigned int work_l, work_r;
786
787 /* set SIF analog I/O select */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300788 saa717x_write(sd, 0x0594, decoder->audio_input);
789 v4l2_dbg(1, debug, sd, "set audio input %d\n",
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300790 decoder->audio_input);
791
792 /* normalize ( 65535 to 0 -> 24 to -40 (not -84)) */
793 work_l = (min(65536 - decoder->audio_main_balance, 32768) * decoder->audio_main_volume) / 32768;
794 work_r = (min(decoder->audio_main_balance, (u16)32768) * decoder->audio_main_volume) / 32768;
795 decoder->audio_main_vol_l = (long)work_l * (24 - (-40)) / 65535 - 40;
796 decoder->audio_main_vol_r = (long)work_r * (24 - (-40)) / 65535 - 40;
797
798 /* set main volume */
799 /* main volume L[7-0],R[7-0],0x00 24=24dB,-83dB, -84(mute) */
800 /* def:0dB->6dB(MPG600GR) */
801 /* if mute is on, set mute */
802 if (decoder->audio_main_mute) {
803 val = mute | (mute << 8);
804 } else {
805 val = (u8)decoder->audio_main_vol_l |
806 ((u8)decoder->audio_main_vol_r << 8);
807 }
808
Hans Verkuil27760fc2008-11-29 12:57:44 -0300809 saa717x_write(sd, 0x480, val);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300810
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300811 /* set bass and treble */
Hans Verkuil59b83112010-04-23 09:04:48 -0300812 val = decoder->audio_main_bass & 0x1f;
813 val |= (decoder->audio_main_treble & 0x1f) << 5;
Hans Verkuil27760fc2008-11-29 12:57:44 -0300814 saa717x_write(sd, 0x488, val);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300815 return 0;
816}
817
818/********** scaling staff ***********/
Hans Verkuil27760fc2008-11-29 12:57:44 -0300819static void set_h_prescale(struct v4l2_subdev *sd,
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300820 int task, int prescale)
821{
822 static const struct {
823 int xpsc;
824 int xacl;
825 int xc2_1;
826 int xdcg;
827 int vpfy;
828 } vals[] = {
829 /* XPSC XACL XC2_1 XDCG VPFY */
830 { 1, 0, 0, 0, 0 },
831 { 2, 2, 1, 2, 2 },
832 { 3, 4, 1, 3, 2 },
833 { 4, 8, 1, 4, 2 },
834 { 5, 8, 1, 4, 2 },
835 { 6, 8, 1, 4, 3 },
836 { 7, 8, 1, 4, 3 },
837 { 8, 15, 0, 4, 3 },
838 { 9, 15, 0, 4, 3 },
839 { 10, 16, 1, 5, 3 },
840 };
841 static const int count = ARRAY_SIZE(vals);
842 int i, task_shift;
843
844 task_shift = task * 0x40;
845 for (i = 0; i < count; i++)
846 if (vals[i].xpsc == prescale)
847 break;
848 if (i == count)
849 return;
850
851 /* horizonal prescaling */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300852 saa717x_write(sd, 0x60 + task_shift, vals[i].xpsc);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300853 /* accumulation length */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300854 saa717x_write(sd, 0x61 + task_shift, vals[i].xacl);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300855 /* level control */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300856 saa717x_write(sd, 0x62 + task_shift,
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300857 (vals[i].xc2_1 << 3) | vals[i].xdcg);
858 /*FIR prefilter control */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300859 saa717x_write(sd, 0x63 + task_shift,
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300860 (vals[i].vpfy << 2) | vals[i].vpfy);
861}
862
863/********** scaling staff ***********/
Hans Verkuil27760fc2008-11-29 12:57:44 -0300864static void set_v_scale(struct v4l2_subdev *sd, int task, int yscale)
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300865{
866 int task_shift;
867
868 task_shift = task * 0x40;
869 /* Vertical scaling ratio (LOW) */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300870 saa717x_write(sd, 0x70 + task_shift, yscale & 0xff);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300871 /* Vertical scaling ratio (HI) */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300872 saa717x_write(sd, 0x71 + task_shift, yscale >> 8);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300873}
874
Hans Verkuil59b83112010-04-23 09:04:48 -0300875static int saa717x_s_ctrl(struct v4l2_ctrl *ctrl)
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300876{
Hans Verkuil59b83112010-04-23 09:04:48 -0300877 struct v4l2_subdev *sd = to_sd(ctrl);
Hans Verkuil27760fc2008-11-29 12:57:44 -0300878 struct saa717x_state *state = to_state(sd);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300879
880 switch (ctrl->id) {
881 case V4L2_CID_BRIGHTNESS:
Hans Verkuil59b83112010-04-23 09:04:48 -0300882 saa717x_write(sd, 0x10a, ctrl->val);
883 return 0;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300884
885 case V4L2_CID_CONTRAST:
Hans Verkuil59b83112010-04-23 09:04:48 -0300886 saa717x_write(sd, 0x10b, ctrl->val);
887 return 0;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300888
889 case V4L2_CID_SATURATION:
Hans Verkuil59b83112010-04-23 09:04:48 -0300890 saa717x_write(sd, 0x10c, ctrl->val);
891 return 0;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300892
893 case V4L2_CID_HUE:
Hans Verkuil59b83112010-04-23 09:04:48 -0300894 saa717x_write(sd, 0x10d, ctrl->val);
895 return 0;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300896
897 case V4L2_CID_AUDIO_MUTE:
Hans Verkuil59b83112010-04-23 09:04:48 -0300898 state->audio_main_mute = ctrl->val;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300899 break;
900
901 case V4L2_CID_AUDIO_VOLUME:
Hans Verkuil59b83112010-04-23 09:04:48 -0300902 state->audio_main_volume = ctrl->val;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300903 break;
904
905 case V4L2_CID_AUDIO_BALANCE:
Hans Verkuil59b83112010-04-23 09:04:48 -0300906 state->audio_main_balance = ctrl->val;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300907 break;
908
909 case V4L2_CID_AUDIO_TREBLE:
Hans Verkuil59b83112010-04-23 09:04:48 -0300910 state->audio_main_treble = ctrl->val;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300911 break;
912
913 case V4L2_CID_AUDIO_BASS:
Hans Verkuil59b83112010-04-23 09:04:48 -0300914 state->audio_main_bass = ctrl->val;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300915 break;
916
917 default:
Hans Verkuil59b83112010-04-23 09:04:48 -0300918 return 0;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300919 }
Hans Verkuil59b83112010-04-23 09:04:48 -0300920 set_audio_regs(sd, state);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300921 return 0;
922}
923
Hans Verkuil5325b422009-04-02 11:26:22 -0300924static int saa717x_s_video_routing(struct v4l2_subdev *sd,
925 u32 input, u32 output, u32 config)
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300926{
Hans Verkuil27760fc2008-11-29 12:57:44 -0300927 struct saa717x_state *decoder = to_state(sd);
Hans Verkuil5325b422009-04-02 11:26:22 -0300928 int is_tuner = input & 0x80; /* tuner input flag */
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300929
Hans Verkuil5325b422009-04-02 11:26:22 -0300930 input &= 0x7f;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300931
Hans Verkuil5325b422009-04-02 11:26:22 -0300932 v4l2_dbg(1, debug, sd, "decoder set input (%d)\n", input);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300933 /* inputs from 0-9 are available*/
934 /* saa717x have mode0-mode9 but mode5 is reserved. */
Roel Kluinf14a2972009-10-23 07:59:42 -0300935 if (input > 9 || input == 5)
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300936 return -EINVAL;
937
Hans Verkuil5325b422009-04-02 11:26:22 -0300938 if (decoder->input != input) {
939 int input_line = input;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300940
941 decoder->input = input_line;
Hans Verkuil27760fc2008-11-29 12:57:44 -0300942 v4l2_dbg(1, debug, sd, "now setting %s input %d\n",
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300943 input_line >= 6 ? "S-Video" : "Composite",
944 input_line);
945
946 /* select mode */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300947 saa717x_write(sd, 0x102,
948 (saa717x_read(sd, 0x102) & 0xf0) |
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300949 input_line);
950
951 /* bypass chrominance trap for modes 6..9 */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300952 saa717x_write(sd, 0x109,
953 (saa717x_read(sd, 0x109) & 0x7f) |
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300954 (input_line < 6 ? 0x0 : 0x80));
955
956 /* change audio_mode */
957 if (is_tuner) {
958 /* tuner */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300959 set_audio_mode(sd, decoder->tuner_audio_mode);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300960 } else {
961 /* Force to STEREO mode if Composite or
962 * S-Video were chosen */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300963 set_audio_mode(sd, TUNER_AUDIO_STEREO);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300964 }
965 /* change initialize procedure (Composite/S-Video) */
966 if (is_tuner)
Hans Verkuil27760fc2008-11-29 12:57:44 -0300967 saa717x_write_regs(sd, reg_init_tuner_input);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300968 else if (input_line >= 6)
Hans Verkuil27760fc2008-11-29 12:57:44 -0300969 saa717x_write_regs(sd, reg_init_svideo_input);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300970 else
Hans Verkuil27760fc2008-11-29 12:57:44 -0300971 saa717x_write_regs(sd, reg_init_composite_input);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300972 }
973
974 return 0;
975}
976
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300977#ifdef CONFIG_VIDEO_ADV_DEBUG
Hans Verkuilaecde8b52008-12-30 07:14:19 -0300978static int saa717x_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
Hans Verkuil27760fc2008-11-29 12:57:44 -0300979{
980 struct i2c_client *client = v4l2_get_subdevdata(sd);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300981
Hans Verkuilaecde8b52008-12-30 07:14:19 -0300982 if (!v4l2_chip_match_i2c_client(client, &reg->match))
Hans Verkuil27760fc2008-11-29 12:57:44 -0300983 return -EINVAL;
984 if (!capable(CAP_SYS_ADMIN))
985 return -EPERM;
986 reg->val = saa717x_read(sd, reg->reg);
Hans Verkuilaecde8b52008-12-30 07:14:19 -0300987 reg->size = 1;
Hans Verkuil27760fc2008-11-29 12:57:44 -0300988 return 0;
989}
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300990
Hans Verkuil977ba3b2013-03-24 08:28:46 -0300991static int saa717x_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
Hans Verkuil27760fc2008-11-29 12:57:44 -0300992{
993 struct i2c_client *client = v4l2_get_subdevdata(sd);
994 u16 addr = reg->reg & 0xffff;
995 u8 val = reg->val & 0xff;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300996
Hans Verkuilaecde8b52008-12-30 07:14:19 -0300997 if (!v4l2_chip_match_i2c_client(client, &reg->match))
Hans Verkuil27760fc2008-11-29 12:57:44 -0300998 return -EINVAL;
999 if (!capable(CAP_SYS_ADMIN))
1000 return -EPERM;
1001 saa717x_write(sd, addr, val);
1002 return 0;
1003}
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001004#endif
1005
Hans Verkuil6c69db92010-05-09 09:50:34 -03001006static int saa717x_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt)
Hans Verkuil27760fc2008-11-29 12:57:44 -03001007{
Hans Verkuil27760fc2008-11-29 12:57:44 -03001008 int prescale, h_scale, v_scale;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001009
Hans Verkuil27760fc2008-11-29 12:57:44 -03001010 v4l2_dbg(1, debug, sd, "decoder set size\n");
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001011
Hans Verkuil6c69db92010-05-09 09:50:34 -03001012 if (fmt->code != V4L2_MBUS_FMT_FIXED)
1013 return -EINVAL;
1014
Hans Verkuil27760fc2008-11-29 12:57:44 -03001015 /* FIXME need better bounds checking here */
Hans Verkuil6c69db92010-05-09 09:50:34 -03001016 if (fmt->width < 1 || fmt->width > 1440)
Hans Verkuil27760fc2008-11-29 12:57:44 -03001017 return -EINVAL;
Hans Verkuil6c69db92010-05-09 09:50:34 -03001018 if (fmt->height < 1 || fmt->height > 960)
Hans Verkuil27760fc2008-11-29 12:57:44 -03001019 return -EINVAL;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001020
Hans Verkuil6c69db92010-05-09 09:50:34 -03001021 fmt->field = V4L2_FIELD_INTERLACED;
1022 fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
1023
Hans Verkuil27760fc2008-11-29 12:57:44 -03001024 /* scaling setting */
1025 /* NTSC and interlace only */
Hans Verkuil6c69db92010-05-09 09:50:34 -03001026 prescale = SAA717X_NTSC_WIDTH / fmt->width;
Hans Verkuil27760fc2008-11-29 12:57:44 -03001027 if (prescale == 0)
1028 prescale = 1;
Hans Verkuil6c69db92010-05-09 09:50:34 -03001029 h_scale = 1024 * SAA717X_NTSC_WIDTH / prescale / fmt->width;
Hans Verkuil27760fc2008-11-29 12:57:44 -03001030 /* interlace */
Hans Verkuil6c69db92010-05-09 09:50:34 -03001031 v_scale = 512 * 2 * SAA717X_NTSC_HEIGHT / fmt->height;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001032
Hans Verkuil27760fc2008-11-29 12:57:44 -03001033 /* Horizontal prescaling etc */
1034 set_h_prescale(sd, 0, prescale);
1035 set_h_prescale(sd, 1, prescale);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001036
Hans Verkuil27760fc2008-11-29 12:57:44 -03001037 /* Horizontal scaling increment */
1038 /* TASK A */
1039 saa717x_write(sd, 0x6C, (u8)(h_scale & 0xFF));
1040 saa717x_write(sd, 0x6D, (u8)((h_scale >> 8) & 0xFF));
1041 /* TASK B */
1042 saa717x_write(sd, 0xAC, (u8)(h_scale & 0xFF));
1043 saa717x_write(sd, 0xAD, (u8)((h_scale >> 8) & 0xFF));
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001044
Hans Verkuil27760fc2008-11-29 12:57:44 -03001045 /* Vertical prescaling etc */
1046 set_v_scale(sd, 0, v_scale);
1047 set_v_scale(sd, 1, v_scale);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001048
Hans Verkuil27760fc2008-11-29 12:57:44 -03001049 /* set video output size */
1050 /* video number of pixels at output */
1051 /* TASK A */
Hans Verkuil6c69db92010-05-09 09:50:34 -03001052 saa717x_write(sd, 0x5C, (u8)(fmt->width & 0xFF));
1053 saa717x_write(sd, 0x5D, (u8)((fmt->width >> 8) & 0xFF));
Hans Verkuil27760fc2008-11-29 12:57:44 -03001054 /* TASK B */
Hans Verkuil6c69db92010-05-09 09:50:34 -03001055 saa717x_write(sd, 0x9C, (u8)(fmt->width & 0xFF));
1056 saa717x_write(sd, 0x9D, (u8)((fmt->width >> 8) & 0xFF));
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001057
Hans Verkuil27760fc2008-11-29 12:57:44 -03001058 /* video number of lines at output */
1059 /* TASK A */
Hans Verkuil6c69db92010-05-09 09:50:34 -03001060 saa717x_write(sd, 0x5E, (u8)(fmt->height & 0xFF));
1061 saa717x_write(sd, 0x5F, (u8)((fmt->height >> 8) & 0xFF));
Hans Verkuil27760fc2008-11-29 12:57:44 -03001062 /* TASK B */
Hans Verkuil6c69db92010-05-09 09:50:34 -03001063 saa717x_write(sd, 0x9E, (u8)(fmt->height & 0xFF));
1064 saa717x_write(sd, 0x9F, (u8)((fmt->height >> 8) & 0xFF));
Hans Verkuil27760fc2008-11-29 12:57:44 -03001065 return 0;
1066}
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001067
Hans Verkuil27760fc2008-11-29 12:57:44 -03001068static int saa717x_s_radio(struct v4l2_subdev *sd)
1069{
1070 struct saa717x_state *decoder = to_state(sd);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001071
Hans Verkuil27760fc2008-11-29 12:57:44 -03001072 decoder->radio = 1;
1073 return 0;
1074}
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001075
Hans Verkuil27760fc2008-11-29 12:57:44 -03001076static int saa717x_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
1077{
1078 struct saa717x_state *decoder = to_state(sd);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001079
Hans Verkuil27760fc2008-11-29 12:57:44 -03001080 v4l2_dbg(1, debug, sd, "decoder set norm ");
1081 v4l2_dbg(1, debug, sd, "(not yet implementd)\n");
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001082
Hans Verkuil27760fc2008-11-29 12:57:44 -03001083 decoder->radio = 0;
1084 decoder->std = std;
1085 return 0;
1086}
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001087
Hans Verkuil5325b422009-04-02 11:26:22 -03001088static int saa717x_s_audio_routing(struct v4l2_subdev *sd,
1089 u32 input, u32 output, u32 config)
Hans Verkuil27760fc2008-11-29 12:57:44 -03001090{
1091 struct saa717x_state *decoder = to_state(sd);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001092
Hans Verkuil5325b422009-04-02 11:26:22 -03001093 if (input < 3) { /* FIXME! --tadachi */
1094 decoder->audio_input = input;
Hans Verkuil27760fc2008-11-29 12:57:44 -03001095 v4l2_dbg(1, debug, sd,
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001096 "set decoder audio input to %d\n",
1097 decoder->audio_input);
Hans Verkuil27760fc2008-11-29 12:57:44 -03001098 set_audio_regs(sd, decoder);
1099 return 0;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001100 }
Hans Verkuil27760fc2008-11-29 12:57:44 -03001101 return -ERANGE;
1102}
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001103
Hans Verkuil27760fc2008-11-29 12:57:44 -03001104static int saa717x_s_stream(struct v4l2_subdev *sd, int enable)
1105{
1106 struct saa717x_state *decoder = to_state(sd);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001107
Hans Verkuil27760fc2008-11-29 12:57:44 -03001108 v4l2_dbg(1, debug, sd, "decoder %s output\n",
1109 enable ? "enable" : "disable");
1110 decoder->enable = enable;
1111 saa717x_write(sd, 0x193, enable ? 0xa6 : 0x26);
1112 return 0;
1113}
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001114
Hans Verkuil27760fc2008-11-29 12:57:44 -03001115/* change audio mode */
Hans Verkuil2f73c7c2013-03-15 06:10:06 -03001116static int saa717x_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *vt)
Hans Verkuil27760fc2008-11-29 12:57:44 -03001117{
1118 struct saa717x_state *decoder = to_state(sd);
1119 int audio_mode;
1120 char *mes[4] = {
1121 "MONO", "STEREO", "LANG1", "LANG2/SAP"
1122 };
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001123
Julia Lawallb921d922009-11-08 14:49:05 -03001124 audio_mode = TUNER_AUDIO_STEREO;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001125
Hans Verkuil27760fc2008-11-29 12:57:44 -03001126 switch (vt->audmode) {
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001127 case V4L2_TUNER_MODE_MONO:
1128 audio_mode = TUNER_AUDIO_MONO;
1129 break;
1130 case V4L2_TUNER_MODE_STEREO:
1131 audio_mode = TUNER_AUDIO_STEREO;
1132 break;
1133 case V4L2_TUNER_MODE_LANG2:
1134 audio_mode = TUNER_AUDIO_LANG2;
1135 break;
1136 case V4L2_TUNER_MODE_LANG1:
1137 audio_mode = TUNER_AUDIO_LANG1;
1138 break;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001139 }
1140
Hans Verkuil27760fc2008-11-29 12:57:44 -03001141 v4l2_dbg(1, debug, sd, "change audio mode to %s\n",
1142 mes[audio_mode]);
1143 decoder->tuner_audio_mode = audio_mode;
1144 /* The registers are not changed here. */
1145 /* See DECODER_ENABLE_OUTPUT section. */
1146 set_audio_mode(sd, decoder->tuner_audio_mode);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001147 return 0;
1148}
1149
Hans Verkuil27760fc2008-11-29 12:57:44 -03001150static int saa717x_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
1151{
1152 struct saa717x_state *decoder = to_state(sd);
1153 int dual_f, stereo_f;
1154
1155 if (decoder->radio)
1156 return 0;
1157 get_inf_dev_status(sd, &dual_f, &stereo_f);
1158
1159 v4l2_dbg(1, debug, sd, "DETECT==st:%d dual:%d\n",
1160 stereo_f, dual_f);
1161
1162 /* mono */
1163 if ((dual_f == 0) && (stereo_f == 0)) {
1164 vt->rxsubchans = V4L2_TUNER_SUB_MONO;
1165 v4l2_dbg(1, debug, sd, "DETECT==MONO\n");
1166 }
1167
1168 /* stereo */
1169 if (stereo_f == 1) {
1170 if (vt->audmode == V4L2_TUNER_MODE_STEREO ||
1171 vt->audmode == V4L2_TUNER_MODE_LANG1) {
1172 vt->rxsubchans = V4L2_TUNER_SUB_STEREO;
1173 v4l2_dbg(1, debug, sd, "DETECT==ST(ST)\n");
1174 } else {
1175 vt->rxsubchans = V4L2_TUNER_SUB_MONO;
1176 v4l2_dbg(1, debug, sd, "DETECT==ST(MONO)\n");
1177 }
1178 }
1179
1180 /* dual */
1181 if (dual_f == 1) {
1182 if (vt->audmode == V4L2_TUNER_MODE_LANG2) {
1183 vt->rxsubchans = V4L2_TUNER_SUB_LANG2 | V4L2_TUNER_SUB_MONO;
1184 v4l2_dbg(1, debug, sd, "DETECT==DUAL1\n");
1185 } else {
1186 vt->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_MONO;
1187 v4l2_dbg(1, debug, sd, "DETECT==DUAL2\n");
1188 }
1189 }
1190 return 0;
1191}
1192
Hans Verkuil59b83112010-04-23 09:04:48 -03001193static int saa717x_log_status(struct v4l2_subdev *sd)
1194{
1195 struct saa717x_state *state = to_state(sd);
1196
1197 v4l2_ctrl_handler_log_status(&state->hdl, sd->name);
1198 return 0;
1199}
1200
Hans Verkuil27760fc2008-11-29 12:57:44 -03001201/* ----------------------------------------------------------------------- */
1202
Hans Verkuil59b83112010-04-23 09:04:48 -03001203static const struct v4l2_ctrl_ops saa717x_ctrl_ops = {
1204 .s_ctrl = saa717x_s_ctrl,
1205};
1206
Hans Verkuil27760fc2008-11-29 12:57:44 -03001207static const struct v4l2_subdev_core_ops saa717x_core_ops = {
1208#ifdef CONFIG_VIDEO_ADV_DEBUG
1209 .g_register = saa717x_g_register,
1210 .s_register = saa717x_s_register,
1211#endif
Hans Verkuilf41737e2009-04-01 03:52:39 -03001212 .s_std = saa717x_s_std,
Hans Verkuil59b83112010-04-23 09:04:48 -03001213 .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
1214 .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
1215 .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
1216 .g_ctrl = v4l2_subdev_g_ctrl,
1217 .s_ctrl = v4l2_subdev_s_ctrl,
1218 .queryctrl = v4l2_subdev_queryctrl,
1219 .querymenu = v4l2_subdev_querymenu,
1220 .log_status = saa717x_log_status,
Hans Verkuil27760fc2008-11-29 12:57:44 -03001221};
1222
1223static const struct v4l2_subdev_tuner_ops saa717x_tuner_ops = {
1224 .g_tuner = saa717x_g_tuner,
1225 .s_tuner = saa717x_s_tuner,
Hans Verkuil27760fc2008-11-29 12:57:44 -03001226 .s_radio = saa717x_s_radio,
1227};
1228
1229static const struct v4l2_subdev_video_ops saa717x_video_ops = {
1230 .s_routing = saa717x_s_video_routing,
Hans Verkuil6c69db92010-05-09 09:50:34 -03001231 .s_mbus_fmt = saa717x_s_mbus_fmt,
Hans Verkuil27760fc2008-11-29 12:57:44 -03001232 .s_stream = saa717x_s_stream,
1233};
1234
1235static const struct v4l2_subdev_audio_ops saa717x_audio_ops = {
1236 .s_routing = saa717x_s_audio_routing,
1237};
1238
1239static const struct v4l2_subdev_ops saa717x_ops = {
1240 .core = &saa717x_core_ops,
1241 .tuner = &saa717x_tuner_ops,
1242 .audio = &saa717x_audio_ops,
1243 .video = &saa717x_video_ops,
1244};
1245
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001246/* ----------------------------------------------------------------------- */
1247
1248
1249/* i2c implementation */
1250
1251/* ----------------------------------------------------------------------- */
Jean Delvared2653e92008-04-29 23:11:39 +02001252static int saa717x_probe(struct i2c_client *client,
1253 const struct i2c_device_id *did)
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001254{
1255 struct saa717x_state *decoder;
Hans Verkuil59b83112010-04-23 09:04:48 -03001256 struct v4l2_ctrl_handler *hdl;
Hans Verkuil27760fc2008-11-29 12:57:44 -03001257 struct v4l2_subdev *sd;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001258 u8 id = 0;
1259 char *p = "";
1260
1261 /* Check if the adapter supports the needed features */
1262 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
1263 return -EIO;
1264
Laurent Pinchartc02b2112013-05-02 08:29:43 -03001265 decoder = devm_kzalloc(&client->dev, sizeof(*decoder), GFP_KERNEL);
Hans Verkuil27760fc2008-11-29 12:57:44 -03001266 if (decoder == NULL)
1267 return -ENOMEM;
1268
1269 sd = &decoder->sd;
1270 v4l2_i2c_subdev_init(sd, client, &saa717x_ops);
1271
1272 if (saa717x_write(sd, 0x5a4, 0xfe) &&
1273 saa717x_write(sd, 0x5a5, 0x0f) &&
1274 saa717x_write(sd, 0x5a6, 0x00) &&
1275 saa717x_write(sd, 0x5a7, 0x01))
1276 id = saa717x_read(sd, 0x5a0);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001277 if (id != 0xc2 && id != 0x32 && id != 0xf2 && id != 0x6c) {
Hans Verkuil27760fc2008-11-29 12:57:44 -03001278 v4l2_dbg(1, debug, sd, "saa717x not found (id=%02x)\n", id);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001279 return -ENODEV;
1280 }
1281 if (id == 0xc2)
1282 p = "saa7173";
1283 else if (id == 0x32)
1284 p = "saa7174A";
1285 else if (id == 0x6c)
1286 p = "saa7174HL";
1287 else
1288 p = "saa7171";
Hans Verkuil27760fc2008-11-29 12:57:44 -03001289 v4l2_info(sd, "%s found @ 0x%x (%s)\n", p,
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001290 client->addr << 1, client->adapter->name);
Hans Verkuil59b83112010-04-23 09:04:48 -03001291
1292 hdl = &decoder->hdl;
1293 v4l2_ctrl_handler_init(hdl, 9);
1294 /* add in ascending ID order */
1295 v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
1296 V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
1297 v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
1298 V4L2_CID_CONTRAST, 0, 255, 1, 68);
1299 v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
1300 V4L2_CID_SATURATION, 0, 255, 1, 64);
1301 v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
1302 V4L2_CID_HUE, -128, 127, 1, 0);
1303 v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
1304 V4L2_CID_AUDIO_VOLUME, 0, 65535, 65535 / 100, 42000);
1305 v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
1306 V4L2_CID_AUDIO_BALANCE, 0, 65535, 65535 / 100, 32768);
1307 v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
1308 V4L2_CID_AUDIO_BASS, -16, 15, 1, 0);
1309 v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
1310 V4L2_CID_AUDIO_TREBLE, -16, 15, 1, 0);
1311 v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
1312 V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0);
1313 sd->ctrl_handler = hdl;
1314 if (hdl->error) {
1315 int err = hdl->error;
1316
1317 v4l2_ctrl_handler_free(hdl);
Hans Verkuil59b83112010-04-23 09:04:48 -03001318 return err;
1319 }
1320
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001321 decoder->std = V4L2_STD_NTSC;
1322 decoder->input = -1;
1323 decoder->enable = 1;
1324
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001325 /* FIXME!! */
1326 decoder->playback = 0; /* initially capture mode used */
1327 decoder->audio = 1; /* DECODER_AUDIO_48_KHZ */
1328
1329 decoder->audio_input = 2; /* FIXME!! */
1330
1331 decoder->tuner_audio_mode = TUNER_AUDIO_STEREO;
1332 /* set volume, bass and treble */
1333 decoder->audio_main_vol_l = 6;
1334 decoder->audio_main_vol_r = 6;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001335
Hans Verkuil27760fc2008-11-29 12:57:44 -03001336 v4l2_dbg(1, debug, sd, "writing init values\n");
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001337
1338 /* FIXME!! */
Hans Verkuil27760fc2008-11-29 12:57:44 -03001339 saa717x_write_regs(sd, reg_init_initialize);
Hans Verkuil59b83112010-04-23 09:04:48 -03001340
1341 v4l2_ctrl_handler_setup(hdl);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001342
1343 set_current_state(TASK_INTERRUPTIBLE);
1344 schedule_timeout(2*HZ);
1345 return 0;
1346}
1347
1348static int saa717x_remove(struct i2c_client *client)
1349{
Hans Verkuil27760fc2008-11-29 12:57:44 -03001350 struct v4l2_subdev *sd = i2c_get_clientdata(client);
1351
1352 v4l2_device_unregister_subdev(sd);
Hans Verkuil59b83112010-04-23 09:04:48 -03001353 v4l2_ctrl_handler_free(sd->ctrl_handler);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001354 return 0;
1355}
1356
1357/* ----------------------------------------------------------------------- */
1358
Jean Delvareaf294862008-05-18 20:49:40 +02001359static const struct i2c_device_id saa717x_id[] = {
1360 { "saa717x", 0 },
1361 { }
1362};
1363MODULE_DEVICE_TABLE(i2c, saa717x_id);
1364
Hans Verkuil720d9162010-09-15 15:01:48 -03001365static struct i2c_driver saa717x_driver = {
1366 .driver = {
1367 .owner = THIS_MODULE,
1368 .name = "saa717x",
1369 },
1370 .probe = saa717x_probe,
1371 .remove = saa717x_remove,
1372 .id_table = saa717x_id,
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001373};
Hans Verkuil720d9162010-09-15 15:01:48 -03001374
Axel Linc6e8d862012-02-12 06:56:32 -03001375module_i2c_driver(saa717x_driver);