blob: 668c39cc29e8e8a68d8c384b02b81a10917d67c0 [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.
Hans Verkuilfb7b37c2008-04-09 06:26:17 -030027 */
28
Hans Verkuilfb7b37c2008-04-09 06:26:17 -030029#include <linux/module.h>
30#include <linux/kernel.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090031#include <linux/slab.h>
Hans Verkuilfb7b37c2008-04-09 06:26:17 -030032#include <linux/sched.h>
33
Hans Verkuilfb7b37c2008-04-09 06:26:17 -030034#include <linux/videodev2.h>
35#include <linux/i2c.h>
Hans Verkuil27760fc2008-11-29 12:57:44 -030036#include <media/v4l2-device.h>
Hans Verkuil59b83112010-04-23 09:04:48 -030037#include <media/v4l2-ctrls.h>
Hans Verkuilfb7b37c2008-04-09 06:26:17 -030038
39MODULE_DESCRIPTION("Philips SAA717x audio/video decoder driver");
40MODULE_AUTHOR("K. Ohta, T. Adachi, Hans Verkuil");
41MODULE_LICENSE("GPL");
42
43static int debug;
44module_param(debug, int, 0644);
45MODULE_PARM_DESC(debug, "Debug level (0-1)");
46
47/*
48 * Generic i2c probe
49 * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
50 */
51
52struct saa717x_state {
Hans Verkuil27760fc2008-11-29 12:57:44 -030053 struct v4l2_subdev sd;
Hans Verkuil59b83112010-04-23 09:04:48 -030054 struct v4l2_ctrl_handler hdl;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -030055 v4l2_std_id std;
56 int input;
57 int enable;
58 int radio;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -030059 int playback;
60 int audio;
61 int tuner_audio_mode;
62 int audio_main_mute;
63 int audio_main_vol_r;
64 int audio_main_vol_l;
65 u16 audio_main_bass;
66 u16 audio_main_treble;
67 u16 audio_main_volume;
68 u16 audio_main_balance;
69 int audio_input;
70};
71
Hans Verkuil27760fc2008-11-29 12:57:44 -030072static inline struct saa717x_state *to_state(struct v4l2_subdev *sd)
73{
74 return container_of(sd, struct saa717x_state, sd);
75}
76
Hans Verkuil59b83112010-04-23 09:04:48 -030077static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
78{
79 return &container_of(ctrl->handler, struct saa717x_state, hdl)->sd;
80}
81
Hans Verkuilfb7b37c2008-04-09 06:26:17 -030082/* ----------------------------------------------------------------------- */
83
84/* for audio mode */
Mauro Carvalho Chehab6e6a8b52018-01-04 13:08:56 -050085#define TUNER_AUDIO_MONO 0 /* LL */
86#define TUNER_AUDIO_STEREO 1 /* LR */
87#define TUNER_AUDIO_LANG1 2 /* LL */
88#define TUNER_AUDIO_LANG2 3 /* RR */
Hans Verkuilfb7b37c2008-04-09 06:26:17 -030089
Mauro Carvalho Chehab6e6a8b52018-01-04 13:08:56 -050090#define SAA717X_NTSC_WIDTH (704)
91#define SAA717X_NTSC_HEIGHT (480)
Hans Verkuilfb7b37c2008-04-09 06:26:17 -030092
93/* ----------------------------------------------------------------------- */
94
Hans Verkuil27760fc2008-11-29 12:57:44 -030095static int saa717x_write(struct v4l2_subdev *sd, u32 reg, u32 value)
Hans Verkuilfb7b37c2008-04-09 06:26:17 -030096{
Hans Verkuil27760fc2008-11-29 12:57:44 -030097 struct i2c_client *client = v4l2_get_subdevdata(sd);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -030098 struct i2c_adapter *adap = client->adapter;
99 int fw_addr = reg == 0x454 || (reg >= 0x464 && reg <= 0x478) || reg == 0x480 || reg == 0x488;
100 unsigned char mm1[6];
101 struct i2c_msg msg;
102
103 msg.flags = 0;
104 msg.addr = client->addr;
105 mm1[0] = (reg >> 8) & 0xff;
106 mm1[1] = reg & 0xff;
107
108 if (fw_addr) {
109 mm1[4] = (value >> 16) & 0xff;
110 mm1[3] = (value >> 8) & 0xff;
111 mm1[2] = value & 0xff;
112 } else {
113 mm1[2] = value & 0xff;
114 }
115 msg.len = fw_addr ? 5 : 3; /* Long Registers have *only* three bytes! */
116 msg.buf = mm1;
Hans Verkuil27760fc2008-11-29 12:57:44 -0300117 v4l2_dbg(2, debug, sd, "wrote: reg 0x%03x=%08x\n", reg, value);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300118 return i2c_transfer(adap, &msg, 1) == 1;
119}
120
Hans Verkuil27760fc2008-11-29 12:57:44 -0300121static void saa717x_write_regs(struct v4l2_subdev *sd, u32 *data)
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300122{
123 while (data[0] || data[1]) {
Hans Verkuil27760fc2008-11-29 12:57:44 -0300124 saa717x_write(sd, data[0], data[1]);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300125 data += 2;
126 }
127}
128
Hans Verkuil27760fc2008-11-29 12:57:44 -0300129static u32 saa717x_read(struct v4l2_subdev *sd, u32 reg)
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300130{
Hans Verkuil27760fc2008-11-29 12:57:44 -0300131 struct i2c_client *client = v4l2_get_subdevdata(sd);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300132 struct i2c_adapter *adap = client->adapter;
133 int fw_addr = (reg >= 0x404 && reg <= 0x4b8) || reg == 0x528;
134 unsigned char mm1[2];
135 unsigned char mm2[4] = { 0, 0, 0, 0 };
136 struct i2c_msg msgs[2];
137 u32 value;
138
139 msgs[0].flags = 0;
140 msgs[1].flags = I2C_M_RD;
141 msgs[0].addr = msgs[1].addr = client->addr;
142 mm1[0] = (reg >> 8) & 0xff;
143 mm1[1] = reg & 0xff;
144 msgs[0].len = 2;
145 msgs[0].buf = mm1;
146 msgs[1].len = fw_addr ? 3 : 1; /* Multibyte Registers contains *only* 3 bytes */
147 msgs[1].buf = mm2;
148 i2c_transfer(adap, msgs, 2);
149
150 if (fw_addr)
Mauro Carvalho Chehab4c7ba402015-04-28 10:28:13 -0300151 value = (mm2[2] << 16) | (mm2[1] << 8) | mm2[0];
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300152 else
Mauro Carvalho Chehab4c7ba402015-04-28 10:28:13 -0300153 value = mm2[0];
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300154
Hans Verkuil27760fc2008-11-29 12:57:44 -0300155 v4l2_dbg(2, debug, sd, "read: reg 0x%03x=0x%08x\n", reg, value);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300156 return value;
157}
158
159/* ----------------------------------------------------------------------- */
160
161static u32 reg_init_initialize[] =
162{
163 /* from linux driver */
164 0x101, 0x008, /* Increment delay */
165
166 0x103, 0x000, /* Analog input control 2 */
167 0x104, 0x090, /* Analog input control 3 */
168 0x105, 0x090, /* Analog input control 4 */
169 0x106, 0x0eb, /* Horizontal sync start */
170 0x107, 0x0e0, /* Horizontal sync stop */
171 0x109, 0x055, /* Luminance control */
172
173 0x10f, 0x02a, /* Chroma gain control */
174 0x110, 0x000, /* Chroma control 2 */
175
176 0x114, 0x045, /* analog/ADC */
177
178 0x118, 0x040, /* RAW data gain */
179 0x119, 0x080, /* RAW data offset */
180
181 0x044, 0x000, /* VBI horizontal input window start (L) TASK A */
182 0x045, 0x000, /* VBI horizontal input window start (H) TASK A */
183 0x046, 0x0cf, /* VBI horizontal input window stop (L) TASK A */
184 0x047, 0x002, /* VBI horizontal input window stop (H) TASK A */
185
186 0x049, 0x000, /* VBI vertical input window start (H) TASK A */
187
188 0x04c, 0x0d0, /* VBI horizontal output length (L) TASK A */
189 0x04d, 0x002, /* VBI horizontal output length (H) TASK A */
190
191 0x064, 0x080, /* Lumina brightness TASK A */
192 0x065, 0x040, /* Luminance contrast TASK A */
193 0x066, 0x040, /* Chroma saturation TASK A */
194 /* 067H: Reserved */
195 0x068, 0x000, /* VBI horizontal scaling increment (L) TASK A */
196 0x069, 0x004, /* VBI horizontal scaling increment (H) TASK A */
197 0x06a, 0x000, /* VBI phase offset TASK A */
198
199 0x06e, 0x000, /* Horizontal phase offset Luma TASK A */
200 0x06f, 0x000, /* Horizontal phase offset Chroma TASK A */
201
202 0x072, 0x000, /* Vertical filter mode TASK A */
203
204 0x084, 0x000, /* VBI horizontal input window start (L) TAKS B */
205 0x085, 0x000, /* VBI horizontal input window start (H) TAKS B */
206 0x086, 0x0cf, /* VBI horizontal input window stop (L) TAKS B */
207 0x087, 0x002, /* VBI horizontal input window stop (H) TAKS B */
208
209 0x089, 0x000, /* VBI vertical input window start (H) TAKS B */
210
211 0x08c, 0x0d0, /* VBI horizontal output length (L) TASK B */
212 0x08d, 0x002, /* VBI horizontal output length (H) TASK B */
213
214 0x0a4, 0x080, /* Lumina brightness TASK B */
215 0x0a5, 0x040, /* Luminance contrast TASK B */
216 0x0a6, 0x040, /* Chroma saturation TASK B */
217 /* 0A7H reserved */
218 0x0a8, 0x000, /* VBI horizontal scaling increment (L) TASK B */
219 0x0a9, 0x004, /* VBI horizontal scaling increment (H) TASK B */
220 0x0aa, 0x000, /* VBI phase offset TASK B */
221
222 0x0ae, 0x000, /* Horizontal phase offset Luma TASK B */
223 0x0af, 0x000, /*Horizontal phase offset Chroma TASK B */
224
225 0x0b2, 0x000, /* Vertical filter mode TASK B */
226
227 0x00c, 0x000, /* Start point GREEN path */
228 0x00d, 0x000, /* Start point BLUE path */
229 0x00e, 0x000, /* Start point RED path */
230
231 0x010, 0x010, /* GREEN path gamma curve --- */
232 0x011, 0x020,
233 0x012, 0x030,
234 0x013, 0x040,
235 0x014, 0x050,
236 0x015, 0x060,
237 0x016, 0x070,
238 0x017, 0x080,
239 0x018, 0x090,
240 0x019, 0x0a0,
241 0x01a, 0x0b0,
242 0x01b, 0x0c0,
243 0x01c, 0x0d0,
244 0x01d, 0x0e0,
245 0x01e, 0x0f0,
246 0x01f, 0x0ff, /* --- GREEN path gamma curve */
247
248 0x020, 0x010, /* BLUE path gamma curve --- */
249 0x021, 0x020,
250 0x022, 0x030,
251 0x023, 0x040,
252 0x024, 0x050,
253 0x025, 0x060,
254 0x026, 0x070,
255 0x027, 0x080,
256 0x028, 0x090,
257 0x029, 0x0a0,
258 0x02a, 0x0b0,
259 0x02b, 0x0c0,
260 0x02c, 0x0d0,
261 0x02d, 0x0e0,
262 0x02e, 0x0f0,
263 0x02f, 0x0ff, /* --- BLUE path gamma curve */
264
265 0x030, 0x010, /* RED path gamma curve --- */
266 0x031, 0x020,
267 0x032, 0x030,
268 0x033, 0x040,
269 0x034, 0x050,
270 0x035, 0x060,
271 0x036, 0x070,
272 0x037, 0x080,
273 0x038, 0x090,
274 0x039, 0x0a0,
275 0x03a, 0x0b0,
276 0x03b, 0x0c0,
277 0x03c, 0x0d0,
278 0x03d, 0x0e0,
279 0x03e, 0x0f0,
280 0x03f, 0x0ff, /* --- RED path gamma curve */
281
282 0x109, 0x085, /* Luminance control */
283
284 /**** from app start ****/
285 0x584, 0x000, /* AGC gain control */
286 0x585, 0x000, /* Program count */
287 0x586, 0x003, /* Status reset */
288 0x588, 0x0ff, /* Number of audio samples (L) */
289 0x589, 0x00f, /* Number of audio samples (M) */
290 0x58a, 0x000, /* Number of audio samples (H) */
291 0x58b, 0x000, /* Audio select */
292 0x58c, 0x010, /* Audio channel assign1 */
293 0x58d, 0x032, /* Audio channel assign2 */
294 0x58e, 0x054, /* Audio channel assign3 */
295 0x58f, 0x023, /* Audio format */
296 0x590, 0x000, /* SIF control */
297
298 0x595, 0x000, /* ?? */
299 0x596, 0x000, /* ?? */
300 0x597, 0x000, /* ?? */
301
302 0x464, 0x00, /* Digital input crossbar1 */
303
304 0x46c, 0xbbbb10, /* Digital output selection1-3 */
305 0x470, 0x101010, /* Digital output selection4-6 */
306
307 0x478, 0x00, /* Sound feature control */
308
309 0x474, 0x18, /* Softmute control */
310
311 0x454, 0x0425b9, /* Sound Easy programming(reset) */
312 0x454, 0x042539, /* Sound Easy programming(reset) */
313
314
315 /**** common setting( of DVD play, including scaler commands) ****/
316 0x042, 0x003, /* Data path configuration for VBI (TASK A) */
317
318 0x082, 0x003, /* Data path configuration for VBI (TASK B) */
319
320 0x108, 0x0f8, /* Sync control */
321 0x2a9, 0x0fd, /* ??? */
322 0x102, 0x089, /* select video input "mode 9" */
323 0x111, 0x000, /* Mode/delay control */
324
325 0x10e, 0x00a, /* Chroma control 1 */
326
327 0x594, 0x002, /* SIF, analog I/O select */
328
329 0x454, 0x0425b9, /* Sound */
330 0x454, 0x042539,
331
332 0x111, 0x000,
333 0x10e, 0x00a,
334 0x464, 0x000,
335 0x300, 0x000,
336 0x301, 0x006,
337 0x302, 0x000,
338 0x303, 0x006,
339 0x308, 0x040,
340 0x309, 0x000,
341 0x30a, 0x000,
342 0x30b, 0x000,
343 0x000, 0x002,
344 0x001, 0x000,
345 0x002, 0x000,
346 0x003, 0x000,
347 0x004, 0x033,
348 0x040, 0x01d,
349 0x041, 0x001,
350 0x042, 0x004,
351 0x043, 0x000,
352 0x080, 0x01e,
353 0x081, 0x001,
354 0x082, 0x004,
355 0x083, 0x000,
356 0x190, 0x018,
357 0x115, 0x000,
358 0x116, 0x012,
359 0x117, 0x018,
360 0x04a, 0x011,
361 0x08a, 0x011,
362 0x04b, 0x000,
363 0x08b, 0x000,
364 0x048, 0x000,
365 0x088, 0x000,
366 0x04e, 0x012,
367 0x08e, 0x012,
368 0x058, 0x012,
369 0x098, 0x012,
370 0x059, 0x000,
371 0x099, 0x000,
372 0x05a, 0x003,
373 0x09a, 0x003,
374 0x05b, 0x001,
375 0x09b, 0x001,
376 0x054, 0x008,
377 0x094, 0x008,
378 0x055, 0x000,
379 0x095, 0x000,
380 0x056, 0x0c7,
381 0x096, 0x0c7,
382 0x057, 0x002,
383 0x097, 0x002,
384 0x0ff, 0x0ff,
385 0x060, 0x001,
386 0x0a0, 0x001,
387 0x061, 0x000,
388 0x0a1, 0x000,
389 0x062, 0x000,
390 0x0a2, 0x000,
391 0x063, 0x000,
392 0x0a3, 0x000,
393 0x070, 0x000,
394 0x0b0, 0x000,
395 0x071, 0x004,
396 0x0b1, 0x004,
397 0x06c, 0x0e9,
398 0x0ac, 0x0e9,
399 0x06d, 0x003,
400 0x0ad, 0x003,
401 0x05c, 0x0d0,
402 0x09c, 0x0d0,
403 0x05d, 0x002,
404 0x09d, 0x002,
405 0x05e, 0x0f2,
406 0x09e, 0x0f2,
407 0x05f, 0x000,
408 0x09f, 0x000,
409 0x074, 0x000,
410 0x0b4, 0x000,
411 0x075, 0x000,
412 0x0b5, 0x000,
413 0x076, 0x000,
414 0x0b6, 0x000,
415 0x077, 0x000,
416 0x0b7, 0x000,
417 0x195, 0x008,
418 0x0ff, 0x0ff,
419 0x108, 0x0f8,
420 0x111, 0x000,
421 0x10e, 0x00a,
422 0x2a9, 0x0fd,
423 0x464, 0x001,
424 0x454, 0x042135,
425 0x598, 0x0e7,
426 0x599, 0x07d,
427 0x59a, 0x018,
428 0x59c, 0x066,
429 0x59d, 0x090,
430 0x59e, 0x001,
431 0x584, 0x000,
432 0x585, 0x000,
433 0x586, 0x003,
434 0x588, 0x0ff,
435 0x589, 0x00f,
436 0x58a, 0x000,
437 0x58b, 0x000,
438 0x58c, 0x010,
439 0x58d, 0x032,
440 0x58e, 0x054,
441 0x58f, 0x023,
442 0x590, 0x000,
443 0x595, 0x000,
444 0x596, 0x000,
445 0x597, 0x000,
446 0x464, 0x000,
447 0x46c, 0xbbbb10,
448 0x470, 0x101010,
449
450
451 0x478, 0x000,
452 0x474, 0x018,
453 0x454, 0x042135,
454 0x598, 0x0e7,
455 0x599, 0x07d,
456 0x59a, 0x018,
457 0x59c, 0x066,
458 0x59d, 0x090,
459 0x59e, 0x001,
460 0x584, 0x000,
461 0x585, 0x000,
462 0x586, 0x003,
463 0x588, 0x0ff,
464 0x589, 0x00f,
465 0x58a, 0x000,
466 0x58b, 0x000,
467 0x58c, 0x010,
468 0x58d, 0x032,
469 0x58e, 0x054,
470 0x58f, 0x023,
471 0x590, 0x000,
472 0x595, 0x000,
473 0x596, 0x000,
474 0x597, 0x000,
475 0x464, 0x000,
476 0x46c, 0xbbbb10,
477 0x470, 0x101010,
478
479 0x478, 0x000,
480 0x474, 0x018,
481 0x454, 0x042135,
482 0x598, 0x0e7,
483 0x599, 0x07d,
484 0x59a, 0x018,
485 0x59c, 0x066,
486 0x59d, 0x090,
487 0x59e, 0x001,
488 0x584, 0x000,
489 0x585, 0x000,
490 0x586, 0x003,
491 0x588, 0x0ff,
492 0x589, 0x00f,
493 0x58a, 0x000,
494 0x58b, 0x000,
495 0x58c, 0x010,
496 0x58d, 0x032,
497 0x58e, 0x054,
498 0x58f, 0x023,
499 0x590, 0x000,
500 0x595, 0x000,
501 0x596, 0x000,
502 0x597, 0x000,
503 0x464, 0x000,
504 0x46c, 0xbbbb10,
505 0x470, 0x101010,
506 0x478, 0x000,
507 0x474, 0x018,
508 0x454, 0x042135,
509 0x193, 0x000,
510 0x300, 0x000,
511 0x301, 0x006,
512 0x302, 0x000,
513 0x303, 0x006,
514 0x308, 0x040,
515 0x309, 0x000,
516 0x30a, 0x000,
517 0x30b, 0x000,
518 0x000, 0x002,
519 0x001, 0x000,
520 0x002, 0x000,
521 0x003, 0x000,
522 0x004, 0x033,
523 0x040, 0x01d,
524 0x041, 0x001,
525 0x042, 0x004,
526 0x043, 0x000,
527 0x080, 0x01e,
528 0x081, 0x001,
529 0x082, 0x004,
530 0x083, 0x000,
531 0x190, 0x018,
532 0x115, 0x000,
533 0x116, 0x012,
534 0x117, 0x018,
535 0x04a, 0x011,
536 0x08a, 0x011,
537 0x04b, 0x000,
538 0x08b, 0x000,
539 0x048, 0x000,
540 0x088, 0x000,
541 0x04e, 0x012,
542 0x08e, 0x012,
543 0x058, 0x012,
544 0x098, 0x012,
545 0x059, 0x000,
546 0x099, 0x000,
547 0x05a, 0x003,
548 0x09a, 0x003,
549 0x05b, 0x001,
550 0x09b, 0x001,
551 0x054, 0x008,
552 0x094, 0x008,
553 0x055, 0x000,
554 0x095, 0x000,
555 0x056, 0x0c7,
556 0x096, 0x0c7,
557 0x057, 0x002,
558 0x097, 0x002,
559 0x060, 0x001,
560 0x0a0, 0x001,
561 0x061, 0x000,
562 0x0a1, 0x000,
563 0x062, 0x000,
564 0x0a2, 0x000,
565 0x063, 0x000,
566 0x0a3, 0x000,
567 0x070, 0x000,
568 0x0b0, 0x000,
569 0x071, 0x004,
570 0x0b1, 0x004,
571 0x06c, 0x0e9,
572 0x0ac, 0x0e9,
573 0x06d, 0x003,
574 0x0ad, 0x003,
575 0x05c, 0x0d0,
576 0x09c, 0x0d0,
577 0x05d, 0x002,
578 0x09d, 0x002,
579 0x05e, 0x0f2,
580 0x09e, 0x0f2,
581 0x05f, 0x000,
582 0x09f, 0x000,
583 0x074, 0x000,
584 0x0b4, 0x000,
585 0x075, 0x000,
586 0x0b5, 0x000,
587 0x076, 0x000,
588 0x0b6, 0x000,
589 0x077, 0x000,
590 0x0b7, 0x000,
591 0x195, 0x008,
592 0x598, 0x0e7,
593 0x599, 0x07d,
594 0x59a, 0x018,
595 0x59c, 0x066,
596 0x59d, 0x090,
597 0x59e, 0x001,
598 0x584, 0x000,
599 0x585, 0x000,
600 0x586, 0x003,
601 0x588, 0x0ff,
602 0x589, 0x00f,
603 0x58a, 0x000,
604 0x58b, 0x000,
605 0x58c, 0x010,
606 0x58d, 0x032,
607 0x58e, 0x054,
608 0x58f, 0x023,
609 0x590, 0x000,
610 0x595, 0x000,
611 0x596, 0x000,
612 0x597, 0x000,
613 0x464, 0x000,
614 0x46c, 0xbbbb10,
615 0x470, 0x101010,
616 0x478, 0x000,
617 0x474, 0x018,
618 0x454, 0x042135,
619 0x193, 0x0a6,
620 0x108, 0x0f8,
621 0x042, 0x003,
622 0x082, 0x003,
623 0x454, 0x0425b9,
624 0x454, 0x042539,
625 0x193, 0x000,
626 0x193, 0x0a6,
627 0x464, 0x000,
628
629 0, 0
630};
631
632/* Tuner */
633static u32 reg_init_tuner_input[] = {
634 0x108, 0x0f8, /* Sync control */
635 0x111, 0x000, /* Mode/delay control */
636 0x10e, 0x00a, /* Chroma control 1 */
637 0, 0
638};
639
640/* Composite */
641static u32 reg_init_composite_input[] = {
642 0x108, 0x0e8, /* Sync control */
643 0x111, 0x000, /* Mode/delay control */
644 0x10e, 0x04a, /* Chroma control 1 */
645 0, 0
646};
647
648/* S-Video */
649static u32 reg_init_svideo_input[] = {
650 0x108, 0x0e8, /* Sync control */
651 0x111, 0x000, /* Mode/delay control */
652 0x10e, 0x04a, /* Chroma control 1 */
653 0, 0
654};
655
656static u32 reg_set_audio_template[4][2] =
657{
658 { /* for MONO
659 tadachi 6/29 DMA audio output select?
660 Register 0x46c
661 7-4: DMA2, 3-0: DMA1 ch. DMA4, DMA3 DMA2, DMA1
662 0: MAIN left, 1: MAIN right
663 2: AUX1 left, 3: AUX1 right
664 4: AUX2 left, 5: AUX2 right
665 6: DPL left, 7: DPL right
666 8: DPL center, 9: DPL surround
667 A: monitor output, B: digital sense */
668 0xbbbb00,
669
670 /* tadachi 6/29 DAC and I2S output select?
671 Register 0x470
672 7-4:DAC right ch. 3-0:DAC left ch.
673 I2S1 right,left I2S2 right,left */
674 0x00,
675 },
676 { /* for STEREO */
677 0xbbbb10, 0x101010,
678 },
679 { /* for LANG1 */
680 0xbbbb00, 0x00,
681 },
682 { /* for LANG2/SAP */
683 0xbbbb11, 0x111111,
684 }
685};
686
687
688/* Get detected audio flags (from saa7134 driver) */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300689static void get_inf_dev_status(struct v4l2_subdev *sd,
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300690 int *dual_flag, int *stereo_flag)
691{
692 u32 reg_data3;
693
694 static char *stdres[0x20] = {
695 [0x00] = "no standard detected",
696 [0x01] = "B/G (in progress)",
697 [0x02] = "D/K (in progress)",
698 [0x03] = "M (in progress)",
699
700 [0x04] = "B/G A2",
701 [0x05] = "B/G NICAM",
702 [0x06] = "D/K A2 (1)",
703 [0x07] = "D/K A2 (2)",
704 [0x08] = "D/K A2 (3)",
705 [0x09] = "D/K NICAM",
706 [0x0a] = "L NICAM",
707 [0x0b] = "I NICAM",
708
709 [0x0c] = "M Korea",
710 [0x0d] = "M BTSC ",
711 [0x0e] = "M EIAJ",
712
713 [0x0f] = "FM radio / IF 10.7 / 50 deemp",
714 [0x10] = "FM radio / IF 10.7 / 75 deemp",
715 [0x11] = "FM radio / IF sel / 50 deemp",
716 [0x12] = "FM radio / IF sel / 75 deemp",
717
718 [0x13 ... 0x1e] = "unknown",
719 [0x1f] = "??? [in progress]",
720 };
721
722
723 *dual_flag = *stereo_flag = 0;
724
725 /* (demdec status: 0x528) */
726
727 /* read current status */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300728 reg_data3 = saa717x_read(sd, 0x0528);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300729
Hans Verkuil27760fc2008-11-29 12:57:44 -0300730 v4l2_dbg(1, debug, sd, "tvaudio thread status: 0x%x [%s%s%s]\n",
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300731 reg_data3, stdres[reg_data3 & 0x1f],
732 (reg_data3 & 0x000020) ? ",stereo" : "",
733 (reg_data3 & 0x000040) ? ",dual" : "");
Hans Verkuil27760fc2008-11-29 12:57:44 -0300734 v4l2_dbg(1, debug, sd, "detailed status: "
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300735 "%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s\n",
736 (reg_data3 & 0x000080) ? " A2/EIAJ pilot tone " : "",
737 (reg_data3 & 0x000100) ? " A2/EIAJ dual " : "",
738 (reg_data3 & 0x000200) ? " A2/EIAJ stereo " : "",
739 (reg_data3 & 0x000400) ? " A2/EIAJ noise mute " : "",
740
741 (reg_data3 & 0x000800) ? " BTSC/FM radio pilot " : "",
742 (reg_data3 & 0x001000) ? " SAP carrier " : "",
743 (reg_data3 & 0x002000) ? " BTSC stereo noise mute " : "",
744 (reg_data3 & 0x004000) ? " SAP noise mute " : "",
745 (reg_data3 & 0x008000) ? " VDSP " : "",
746
747 (reg_data3 & 0x010000) ? " NICST " : "",
748 (reg_data3 & 0x020000) ? " NICDU " : "",
749 (reg_data3 & 0x040000) ? " NICAM muted " : "",
750 (reg_data3 & 0x080000) ? " NICAM reserve sound " : "",
751
752 (reg_data3 & 0x100000) ? " init done " : "");
753
754 if (reg_data3 & 0x000220) {
Hans Verkuil27760fc2008-11-29 12:57:44 -0300755 v4l2_dbg(1, debug, sd, "ST!!!\n");
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300756 *stereo_flag = 1;
757 }
758
759 if (reg_data3 & 0x000140) {
Hans Verkuil27760fc2008-11-29 12:57:44 -0300760 v4l2_dbg(1, debug, sd, "DUAL!!!\n");
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300761 *dual_flag = 1;
762 }
763}
764
765/* regs write to set audio mode */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300766static void set_audio_mode(struct v4l2_subdev *sd, int audio_mode)
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300767{
Hans Verkuil27760fc2008-11-29 12:57:44 -0300768 v4l2_dbg(1, debug, sd, "writing registers to set audio mode by set %d\n",
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300769 audio_mode);
770
Hans Verkuil27760fc2008-11-29 12:57:44 -0300771 saa717x_write(sd, 0x46c, reg_set_audio_template[audio_mode][0]);
772 saa717x_write(sd, 0x470, reg_set_audio_template[audio_mode][1]);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300773}
774
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300775/* write regs to set audio volume, bass and treble */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300776static int set_audio_regs(struct v4l2_subdev *sd,
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300777 struct saa717x_state *decoder)
778{
779 u8 mute = 0xac; /* -84 dB */
780 u32 val;
781 unsigned int work_l, work_r;
782
783 /* set SIF analog I/O select */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300784 saa717x_write(sd, 0x0594, decoder->audio_input);
785 v4l2_dbg(1, debug, sd, "set audio input %d\n",
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300786 decoder->audio_input);
787
788 /* normalize ( 65535 to 0 -> 24 to -40 (not -84)) */
789 work_l = (min(65536 - decoder->audio_main_balance, 32768) * decoder->audio_main_volume) / 32768;
790 work_r = (min(decoder->audio_main_balance, (u16)32768) * decoder->audio_main_volume) / 32768;
791 decoder->audio_main_vol_l = (long)work_l * (24 - (-40)) / 65535 - 40;
792 decoder->audio_main_vol_r = (long)work_r * (24 - (-40)) / 65535 - 40;
793
794 /* set main volume */
795 /* main volume L[7-0],R[7-0],0x00 24=24dB,-83dB, -84(mute) */
796 /* def:0dB->6dB(MPG600GR) */
797 /* if mute is on, set mute */
798 if (decoder->audio_main_mute) {
799 val = mute | (mute << 8);
800 } else {
801 val = (u8)decoder->audio_main_vol_l |
802 ((u8)decoder->audio_main_vol_r << 8);
803 }
804
Hans Verkuil27760fc2008-11-29 12:57:44 -0300805 saa717x_write(sd, 0x480, val);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300806
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300807 /* set bass and treble */
Hans Verkuil59b83112010-04-23 09:04:48 -0300808 val = decoder->audio_main_bass & 0x1f;
809 val |= (decoder->audio_main_treble & 0x1f) << 5;
Hans Verkuil27760fc2008-11-29 12:57:44 -0300810 saa717x_write(sd, 0x488, val);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300811 return 0;
812}
813
814/********** scaling staff ***********/
Hans Verkuil27760fc2008-11-29 12:57:44 -0300815static void set_h_prescale(struct v4l2_subdev *sd,
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300816 int task, int prescale)
817{
818 static const struct {
819 int xpsc;
820 int xacl;
821 int xc2_1;
822 int xdcg;
823 int vpfy;
824 } vals[] = {
825 /* XPSC XACL XC2_1 XDCG VPFY */
826 { 1, 0, 0, 0, 0 },
827 { 2, 2, 1, 2, 2 },
828 { 3, 4, 1, 3, 2 },
829 { 4, 8, 1, 4, 2 },
830 { 5, 8, 1, 4, 2 },
831 { 6, 8, 1, 4, 3 },
832 { 7, 8, 1, 4, 3 },
833 { 8, 15, 0, 4, 3 },
834 { 9, 15, 0, 4, 3 },
835 { 10, 16, 1, 5, 3 },
836 };
837 static const int count = ARRAY_SIZE(vals);
838 int i, task_shift;
839
840 task_shift = task * 0x40;
841 for (i = 0; i < count; i++)
842 if (vals[i].xpsc == prescale)
843 break;
844 if (i == count)
845 return;
846
847 /* horizonal prescaling */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300848 saa717x_write(sd, 0x60 + task_shift, vals[i].xpsc);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300849 /* accumulation length */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300850 saa717x_write(sd, 0x61 + task_shift, vals[i].xacl);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300851 /* level control */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300852 saa717x_write(sd, 0x62 + task_shift,
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300853 (vals[i].xc2_1 << 3) | vals[i].xdcg);
854 /*FIR prefilter control */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300855 saa717x_write(sd, 0x63 + task_shift,
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300856 (vals[i].vpfy << 2) | vals[i].vpfy);
857}
858
859/********** scaling staff ***********/
Hans Verkuil27760fc2008-11-29 12:57:44 -0300860static void set_v_scale(struct v4l2_subdev *sd, int task, int yscale)
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300861{
862 int task_shift;
863
864 task_shift = task * 0x40;
865 /* Vertical scaling ratio (LOW) */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300866 saa717x_write(sd, 0x70 + task_shift, yscale & 0xff);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300867 /* Vertical scaling ratio (HI) */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300868 saa717x_write(sd, 0x71 + task_shift, yscale >> 8);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300869}
870
Hans Verkuil59b83112010-04-23 09:04:48 -0300871static int saa717x_s_ctrl(struct v4l2_ctrl *ctrl)
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300872{
Hans Verkuil59b83112010-04-23 09:04:48 -0300873 struct v4l2_subdev *sd = to_sd(ctrl);
Hans Verkuil27760fc2008-11-29 12:57:44 -0300874 struct saa717x_state *state = to_state(sd);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300875
876 switch (ctrl->id) {
877 case V4L2_CID_BRIGHTNESS:
Hans Verkuil59b83112010-04-23 09:04:48 -0300878 saa717x_write(sd, 0x10a, ctrl->val);
879 return 0;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300880
881 case V4L2_CID_CONTRAST:
Hans Verkuil59b83112010-04-23 09:04:48 -0300882 saa717x_write(sd, 0x10b, ctrl->val);
883 return 0;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300884
885 case V4L2_CID_SATURATION:
Hans Verkuil59b83112010-04-23 09:04:48 -0300886 saa717x_write(sd, 0x10c, ctrl->val);
887 return 0;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300888
889 case V4L2_CID_HUE:
Hans Verkuil59b83112010-04-23 09:04:48 -0300890 saa717x_write(sd, 0x10d, ctrl->val);
891 return 0;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300892
893 case V4L2_CID_AUDIO_MUTE:
Hans Verkuil59b83112010-04-23 09:04:48 -0300894 state->audio_main_mute = ctrl->val;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300895 break;
896
897 case V4L2_CID_AUDIO_VOLUME:
Hans Verkuil59b83112010-04-23 09:04:48 -0300898 state->audio_main_volume = ctrl->val;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300899 break;
900
901 case V4L2_CID_AUDIO_BALANCE:
Hans Verkuil59b83112010-04-23 09:04:48 -0300902 state->audio_main_balance = ctrl->val;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300903 break;
904
905 case V4L2_CID_AUDIO_TREBLE:
Hans Verkuil59b83112010-04-23 09:04:48 -0300906 state->audio_main_treble = ctrl->val;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300907 break;
908
909 case V4L2_CID_AUDIO_BASS:
Hans Verkuil59b83112010-04-23 09:04:48 -0300910 state->audio_main_bass = ctrl->val;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300911 break;
912
913 default:
Hans Verkuil59b83112010-04-23 09:04:48 -0300914 return 0;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300915 }
Hans Verkuil59b83112010-04-23 09:04:48 -0300916 set_audio_regs(sd, state);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300917 return 0;
918}
919
Hans Verkuil5325b422009-04-02 11:26:22 -0300920static int saa717x_s_video_routing(struct v4l2_subdev *sd,
921 u32 input, u32 output, u32 config)
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300922{
Hans Verkuil27760fc2008-11-29 12:57:44 -0300923 struct saa717x_state *decoder = to_state(sd);
Hans Verkuil5325b422009-04-02 11:26:22 -0300924 int is_tuner = input & 0x80; /* tuner input flag */
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300925
Hans Verkuil5325b422009-04-02 11:26:22 -0300926 input &= 0x7f;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300927
Hans Verkuil5325b422009-04-02 11:26:22 -0300928 v4l2_dbg(1, debug, sd, "decoder set input (%d)\n", input);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300929 /* inputs from 0-9 are available*/
930 /* saa717x have mode0-mode9 but mode5 is reserved. */
Roel Kluinf14a2972009-10-23 07:59:42 -0300931 if (input > 9 || input == 5)
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300932 return -EINVAL;
933
Hans Verkuil5325b422009-04-02 11:26:22 -0300934 if (decoder->input != input) {
935 int input_line = input;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300936
937 decoder->input = input_line;
Hans Verkuil27760fc2008-11-29 12:57:44 -0300938 v4l2_dbg(1, debug, sd, "now setting %s input %d\n",
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300939 input_line >= 6 ? "S-Video" : "Composite",
940 input_line);
941
942 /* select mode */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300943 saa717x_write(sd, 0x102,
944 (saa717x_read(sd, 0x102) & 0xf0) |
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300945 input_line);
946
947 /* bypass chrominance trap for modes 6..9 */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300948 saa717x_write(sd, 0x109,
949 (saa717x_read(sd, 0x109) & 0x7f) |
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300950 (input_line < 6 ? 0x0 : 0x80));
951
952 /* change audio_mode */
953 if (is_tuner) {
954 /* tuner */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300955 set_audio_mode(sd, decoder->tuner_audio_mode);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300956 } else {
957 /* Force to STEREO mode if Composite or
958 * S-Video were chosen */
Hans Verkuil27760fc2008-11-29 12:57:44 -0300959 set_audio_mode(sd, TUNER_AUDIO_STEREO);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300960 }
961 /* change initialize procedure (Composite/S-Video) */
962 if (is_tuner)
Hans Verkuil27760fc2008-11-29 12:57:44 -0300963 saa717x_write_regs(sd, reg_init_tuner_input);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300964 else if (input_line >= 6)
Hans Verkuil27760fc2008-11-29 12:57:44 -0300965 saa717x_write_regs(sd, reg_init_svideo_input);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300966 else
Hans Verkuil27760fc2008-11-29 12:57:44 -0300967 saa717x_write_regs(sd, reg_init_composite_input);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300968 }
969
970 return 0;
971}
972
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300973#ifdef CONFIG_VIDEO_ADV_DEBUG
Hans Verkuilaecde8b52008-12-30 07:14:19 -0300974static int saa717x_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
Hans Verkuil27760fc2008-11-29 12:57:44 -0300975{
Hans Verkuil27760fc2008-11-29 12:57:44 -0300976 reg->val = saa717x_read(sd, reg->reg);
Hans Verkuilaecde8b52008-12-30 07:14:19 -0300977 reg->size = 1;
Hans Verkuil27760fc2008-11-29 12:57:44 -0300978 return 0;
979}
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300980
Hans Verkuil977ba3b12013-03-24 08:28:46 -0300981static int saa717x_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
Hans Verkuil27760fc2008-11-29 12:57:44 -0300982{
Hans Verkuil27760fc2008-11-29 12:57:44 -0300983 u16 addr = reg->reg & 0xffff;
984 u8 val = reg->val & 0xff;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300985
Hans Verkuil27760fc2008-11-29 12:57:44 -0300986 saa717x_write(sd, addr, val);
987 return 0;
988}
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300989#endif
990
Hans Verkuil6e80c472015-03-21 09:39:09 -0300991static int saa717x_set_fmt(struct v4l2_subdev *sd,
992 struct v4l2_subdev_pad_config *cfg,
993 struct v4l2_subdev_format *format)
Hans Verkuil27760fc2008-11-29 12:57:44 -0300994{
Hans Verkuil6e80c472015-03-21 09:39:09 -0300995 struct v4l2_mbus_framefmt *fmt = &format->format;
Hans Verkuil27760fc2008-11-29 12:57:44 -0300996 int prescale, h_scale, v_scale;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300997
Hans Verkuil27760fc2008-11-29 12:57:44 -0300998 v4l2_dbg(1, debug, sd, "decoder set size\n");
Hans Verkuilfb7b37c2008-04-09 06:26:17 -0300999
Hans Verkuil6e80c472015-03-21 09:39:09 -03001000 if (format->pad || fmt->code != MEDIA_BUS_FMT_FIXED)
Hans Verkuil6c69db92010-05-09 09:50:34 -03001001 return -EINVAL;
1002
Hans Verkuil27760fc2008-11-29 12:57:44 -03001003 /* FIXME need better bounds checking here */
Hans Verkuil6c69db92010-05-09 09:50:34 -03001004 if (fmt->width < 1 || fmt->width > 1440)
Hans Verkuil27760fc2008-11-29 12:57:44 -03001005 return -EINVAL;
Hans Verkuil6c69db92010-05-09 09:50:34 -03001006 if (fmt->height < 1 || fmt->height > 960)
Hans Verkuil27760fc2008-11-29 12:57:44 -03001007 return -EINVAL;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001008
Hans Verkuil6c69db92010-05-09 09:50:34 -03001009 fmt->field = V4L2_FIELD_INTERLACED;
1010 fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
1011
Hans Verkuil6e80c472015-03-21 09:39:09 -03001012 if (format->which == V4L2_SUBDEV_FORMAT_TRY)
1013 return 0;
1014
Hans Verkuil27760fc2008-11-29 12:57:44 -03001015 /* scaling setting */
1016 /* NTSC and interlace only */
Hans Verkuil6c69db92010-05-09 09:50:34 -03001017 prescale = SAA717X_NTSC_WIDTH / fmt->width;
Hans Verkuil27760fc2008-11-29 12:57:44 -03001018 if (prescale == 0)
1019 prescale = 1;
Hans Verkuil6c69db92010-05-09 09:50:34 -03001020 h_scale = 1024 * SAA717X_NTSC_WIDTH / prescale / fmt->width;
Hans Verkuil27760fc2008-11-29 12:57:44 -03001021 /* interlace */
Hans Verkuil6c69db92010-05-09 09:50:34 -03001022 v_scale = 512 * 2 * SAA717X_NTSC_HEIGHT / fmt->height;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001023
Hans Verkuil27760fc2008-11-29 12:57:44 -03001024 /* Horizontal prescaling etc */
1025 set_h_prescale(sd, 0, prescale);
1026 set_h_prescale(sd, 1, prescale);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001027
Hans Verkuil27760fc2008-11-29 12:57:44 -03001028 /* Horizontal scaling increment */
1029 /* TASK A */
1030 saa717x_write(sd, 0x6C, (u8)(h_scale & 0xFF));
1031 saa717x_write(sd, 0x6D, (u8)((h_scale >> 8) & 0xFF));
1032 /* TASK B */
1033 saa717x_write(sd, 0xAC, (u8)(h_scale & 0xFF));
1034 saa717x_write(sd, 0xAD, (u8)((h_scale >> 8) & 0xFF));
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001035
Hans Verkuil27760fc2008-11-29 12:57:44 -03001036 /* Vertical prescaling etc */
1037 set_v_scale(sd, 0, v_scale);
1038 set_v_scale(sd, 1, v_scale);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001039
Hans Verkuil27760fc2008-11-29 12:57:44 -03001040 /* set video output size */
1041 /* video number of pixels at output */
1042 /* TASK A */
Hans Verkuil6c69db92010-05-09 09:50:34 -03001043 saa717x_write(sd, 0x5C, (u8)(fmt->width & 0xFF));
1044 saa717x_write(sd, 0x5D, (u8)((fmt->width >> 8) & 0xFF));
Hans Verkuil27760fc2008-11-29 12:57:44 -03001045 /* TASK B */
Hans Verkuil6c69db92010-05-09 09:50:34 -03001046 saa717x_write(sd, 0x9C, (u8)(fmt->width & 0xFF));
1047 saa717x_write(sd, 0x9D, (u8)((fmt->width >> 8) & 0xFF));
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001048
Hans Verkuil27760fc2008-11-29 12:57:44 -03001049 /* video number of lines at output */
1050 /* TASK A */
Hans Verkuil6c69db92010-05-09 09:50:34 -03001051 saa717x_write(sd, 0x5E, (u8)(fmt->height & 0xFF));
1052 saa717x_write(sd, 0x5F, (u8)((fmt->height >> 8) & 0xFF));
Hans Verkuil27760fc2008-11-29 12:57:44 -03001053 /* TASK B */
Hans Verkuil6c69db92010-05-09 09:50:34 -03001054 saa717x_write(sd, 0x9E, (u8)(fmt->height & 0xFF));
1055 saa717x_write(sd, 0x9F, (u8)((fmt->height >> 8) & 0xFF));
Hans Verkuil27760fc2008-11-29 12:57:44 -03001056 return 0;
1057}
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001058
Hans Verkuil27760fc2008-11-29 12:57:44 -03001059static int saa717x_s_radio(struct v4l2_subdev *sd)
1060{
1061 struct saa717x_state *decoder = to_state(sd);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001062
Hans Verkuil27760fc2008-11-29 12:57:44 -03001063 decoder->radio = 1;
1064 return 0;
1065}
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001066
Hans Verkuil27760fc2008-11-29 12:57:44 -03001067static int saa717x_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
1068{
1069 struct saa717x_state *decoder = to_state(sd);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001070
Hans Verkuil27760fc2008-11-29 12:57:44 -03001071 v4l2_dbg(1, debug, sd, "decoder set norm ");
Colin Ian King72c6efb2017-07-03 05:26:39 -04001072 v4l2_dbg(1, debug, sd, "(not yet implemented)\n");
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001073
Hans Verkuil27760fc2008-11-29 12:57:44 -03001074 decoder->radio = 0;
1075 decoder->std = std;
1076 return 0;
1077}
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001078
Hans Verkuil5325b422009-04-02 11:26:22 -03001079static int saa717x_s_audio_routing(struct v4l2_subdev *sd,
1080 u32 input, u32 output, u32 config)
Hans Verkuil27760fc2008-11-29 12:57:44 -03001081{
1082 struct saa717x_state *decoder = to_state(sd);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001083
Hans Verkuil5325b422009-04-02 11:26:22 -03001084 if (input < 3) { /* FIXME! --tadachi */
1085 decoder->audio_input = input;
Hans Verkuil27760fc2008-11-29 12:57:44 -03001086 v4l2_dbg(1, debug, sd,
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001087 "set decoder audio input to %d\n",
1088 decoder->audio_input);
Hans Verkuil27760fc2008-11-29 12:57:44 -03001089 set_audio_regs(sd, decoder);
1090 return 0;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001091 }
Hans Verkuil27760fc2008-11-29 12:57:44 -03001092 return -ERANGE;
1093}
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001094
Hans Verkuil27760fc2008-11-29 12:57:44 -03001095static int saa717x_s_stream(struct v4l2_subdev *sd, int enable)
1096{
1097 struct saa717x_state *decoder = to_state(sd);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001098
Hans Verkuil27760fc2008-11-29 12:57:44 -03001099 v4l2_dbg(1, debug, sd, "decoder %s output\n",
1100 enable ? "enable" : "disable");
1101 decoder->enable = enable;
1102 saa717x_write(sd, 0x193, enable ? 0xa6 : 0x26);
1103 return 0;
1104}
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001105
Hans Verkuil27760fc2008-11-29 12:57:44 -03001106/* change audio mode */
Hans Verkuil2f73c7c2013-03-15 06:10:06 -03001107static int saa717x_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *vt)
Hans Verkuil27760fc2008-11-29 12:57:44 -03001108{
1109 struct saa717x_state *decoder = to_state(sd);
1110 int audio_mode;
1111 char *mes[4] = {
1112 "MONO", "STEREO", "LANG1", "LANG2/SAP"
1113 };
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001114
Julia Lawallb921d9292009-11-08 14:49:05 -03001115 audio_mode = TUNER_AUDIO_STEREO;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001116
Hans Verkuil27760fc2008-11-29 12:57:44 -03001117 switch (vt->audmode) {
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001118 case V4L2_TUNER_MODE_MONO:
1119 audio_mode = TUNER_AUDIO_MONO;
1120 break;
1121 case V4L2_TUNER_MODE_STEREO:
1122 audio_mode = TUNER_AUDIO_STEREO;
1123 break;
1124 case V4L2_TUNER_MODE_LANG2:
1125 audio_mode = TUNER_AUDIO_LANG2;
1126 break;
1127 case V4L2_TUNER_MODE_LANG1:
1128 audio_mode = TUNER_AUDIO_LANG1;
1129 break;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001130 }
1131
Hans Verkuil27760fc2008-11-29 12:57:44 -03001132 v4l2_dbg(1, debug, sd, "change audio mode to %s\n",
1133 mes[audio_mode]);
1134 decoder->tuner_audio_mode = audio_mode;
1135 /* The registers are not changed here. */
1136 /* See DECODER_ENABLE_OUTPUT section. */
1137 set_audio_mode(sd, decoder->tuner_audio_mode);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001138 return 0;
1139}
1140
Hans Verkuil27760fc2008-11-29 12:57:44 -03001141static int saa717x_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
1142{
1143 struct saa717x_state *decoder = to_state(sd);
1144 int dual_f, stereo_f;
1145
1146 if (decoder->radio)
1147 return 0;
1148 get_inf_dev_status(sd, &dual_f, &stereo_f);
1149
1150 v4l2_dbg(1, debug, sd, "DETECT==st:%d dual:%d\n",
1151 stereo_f, dual_f);
1152
1153 /* mono */
1154 if ((dual_f == 0) && (stereo_f == 0)) {
1155 vt->rxsubchans = V4L2_TUNER_SUB_MONO;
1156 v4l2_dbg(1, debug, sd, "DETECT==MONO\n");
1157 }
1158
1159 /* stereo */
1160 if (stereo_f == 1) {
1161 if (vt->audmode == V4L2_TUNER_MODE_STEREO ||
1162 vt->audmode == V4L2_TUNER_MODE_LANG1) {
1163 vt->rxsubchans = V4L2_TUNER_SUB_STEREO;
1164 v4l2_dbg(1, debug, sd, "DETECT==ST(ST)\n");
1165 } else {
1166 vt->rxsubchans = V4L2_TUNER_SUB_MONO;
1167 v4l2_dbg(1, debug, sd, "DETECT==ST(MONO)\n");
1168 }
1169 }
1170
1171 /* dual */
1172 if (dual_f == 1) {
1173 if (vt->audmode == V4L2_TUNER_MODE_LANG2) {
1174 vt->rxsubchans = V4L2_TUNER_SUB_LANG2 | V4L2_TUNER_SUB_MONO;
1175 v4l2_dbg(1, debug, sd, "DETECT==DUAL1\n");
1176 } else {
1177 vt->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_MONO;
1178 v4l2_dbg(1, debug, sd, "DETECT==DUAL2\n");
1179 }
1180 }
1181 return 0;
1182}
1183
Hans Verkuil59b83112010-04-23 09:04:48 -03001184static int saa717x_log_status(struct v4l2_subdev *sd)
1185{
1186 struct saa717x_state *state = to_state(sd);
1187
1188 v4l2_ctrl_handler_log_status(&state->hdl, sd->name);
1189 return 0;
1190}
1191
Hans Verkuil27760fc2008-11-29 12:57:44 -03001192/* ----------------------------------------------------------------------- */
1193
Hans Verkuil59b83112010-04-23 09:04:48 -03001194static const struct v4l2_ctrl_ops saa717x_ctrl_ops = {
1195 .s_ctrl = saa717x_s_ctrl,
1196};
1197
Hans Verkuil27760fc2008-11-29 12:57:44 -03001198static const struct v4l2_subdev_core_ops saa717x_core_ops = {
1199#ifdef CONFIG_VIDEO_ADV_DEBUG
1200 .g_register = saa717x_g_register,
1201 .s_register = saa717x_s_register,
1202#endif
Hans Verkuil59b83112010-04-23 09:04:48 -03001203 .log_status = saa717x_log_status,
Hans Verkuil27760fc2008-11-29 12:57:44 -03001204};
1205
1206static const struct v4l2_subdev_tuner_ops saa717x_tuner_ops = {
1207 .g_tuner = saa717x_g_tuner,
1208 .s_tuner = saa717x_s_tuner,
Hans Verkuil27760fc2008-11-29 12:57:44 -03001209 .s_radio = saa717x_s_radio,
1210};
1211
1212static const struct v4l2_subdev_video_ops saa717x_video_ops = {
Laurent Pinchart8774bed2014-04-28 16:53:01 -03001213 .s_std = saa717x_s_std,
Hans Verkuil27760fc2008-11-29 12:57:44 -03001214 .s_routing = saa717x_s_video_routing,
Hans Verkuil27760fc2008-11-29 12:57:44 -03001215 .s_stream = saa717x_s_stream,
1216};
1217
1218static const struct v4l2_subdev_audio_ops saa717x_audio_ops = {
1219 .s_routing = saa717x_s_audio_routing,
1220};
1221
Hans Verkuil6e80c472015-03-21 09:39:09 -03001222static const struct v4l2_subdev_pad_ops saa717x_pad_ops = {
1223 .set_fmt = saa717x_set_fmt,
1224};
1225
Hans Verkuil27760fc2008-11-29 12:57:44 -03001226static const struct v4l2_subdev_ops saa717x_ops = {
1227 .core = &saa717x_core_ops,
1228 .tuner = &saa717x_tuner_ops,
1229 .audio = &saa717x_audio_ops,
1230 .video = &saa717x_video_ops,
Hans Verkuil6e80c472015-03-21 09:39:09 -03001231 .pad = &saa717x_pad_ops,
Hans Verkuil27760fc2008-11-29 12:57:44 -03001232};
1233
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001234/* ----------------------------------------------------------------------- */
1235
1236
1237/* i2c implementation */
1238
1239/* ----------------------------------------------------------------------- */
Jean Delvared2653e92008-04-29 23:11:39 +02001240static int saa717x_probe(struct i2c_client *client,
1241 const struct i2c_device_id *did)
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001242{
1243 struct saa717x_state *decoder;
Hans Verkuil59b83112010-04-23 09:04:48 -03001244 struct v4l2_ctrl_handler *hdl;
Hans Verkuil27760fc2008-11-29 12:57:44 -03001245 struct v4l2_subdev *sd;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001246 u8 id = 0;
1247 char *p = "";
1248
1249 /* Check if the adapter supports the needed features */
1250 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
1251 return -EIO;
1252
Laurent Pinchartc02b2112013-05-02 08:29:43 -03001253 decoder = devm_kzalloc(&client->dev, sizeof(*decoder), GFP_KERNEL);
Hans Verkuil27760fc2008-11-29 12:57:44 -03001254 if (decoder == NULL)
1255 return -ENOMEM;
1256
1257 sd = &decoder->sd;
1258 v4l2_i2c_subdev_init(sd, client, &saa717x_ops);
1259
1260 if (saa717x_write(sd, 0x5a4, 0xfe) &&
1261 saa717x_write(sd, 0x5a5, 0x0f) &&
1262 saa717x_write(sd, 0x5a6, 0x00) &&
1263 saa717x_write(sd, 0x5a7, 0x01))
1264 id = saa717x_read(sd, 0x5a0);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001265 if (id != 0xc2 && id != 0x32 && id != 0xf2 && id != 0x6c) {
Hans Verkuil27760fc2008-11-29 12:57:44 -03001266 v4l2_dbg(1, debug, sd, "saa717x not found (id=%02x)\n", id);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001267 return -ENODEV;
1268 }
1269 if (id == 0xc2)
1270 p = "saa7173";
1271 else if (id == 0x32)
1272 p = "saa7174A";
1273 else if (id == 0x6c)
1274 p = "saa7174HL";
1275 else
1276 p = "saa7171";
Hans Verkuil27760fc2008-11-29 12:57:44 -03001277 v4l2_info(sd, "%s found @ 0x%x (%s)\n", p,
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001278 client->addr << 1, client->adapter->name);
Hans Verkuil59b83112010-04-23 09:04:48 -03001279
1280 hdl = &decoder->hdl;
1281 v4l2_ctrl_handler_init(hdl, 9);
1282 /* add in ascending ID order */
1283 v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
1284 V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
1285 v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
1286 V4L2_CID_CONTRAST, 0, 255, 1, 68);
1287 v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
1288 V4L2_CID_SATURATION, 0, 255, 1, 64);
1289 v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
1290 V4L2_CID_HUE, -128, 127, 1, 0);
1291 v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
1292 V4L2_CID_AUDIO_VOLUME, 0, 65535, 65535 / 100, 42000);
1293 v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
1294 V4L2_CID_AUDIO_BALANCE, 0, 65535, 65535 / 100, 32768);
1295 v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
1296 V4L2_CID_AUDIO_BASS, -16, 15, 1, 0);
1297 v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
1298 V4L2_CID_AUDIO_TREBLE, -16, 15, 1, 0);
1299 v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
1300 V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0);
1301 sd->ctrl_handler = hdl;
1302 if (hdl->error) {
1303 int err = hdl->error;
1304
1305 v4l2_ctrl_handler_free(hdl);
Hans Verkuil59b83112010-04-23 09:04:48 -03001306 return err;
1307 }
1308
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001309 decoder->std = V4L2_STD_NTSC;
1310 decoder->input = -1;
1311 decoder->enable = 1;
1312
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001313 /* FIXME!! */
1314 decoder->playback = 0; /* initially capture mode used */
1315 decoder->audio = 1; /* DECODER_AUDIO_48_KHZ */
1316
1317 decoder->audio_input = 2; /* FIXME!! */
1318
1319 decoder->tuner_audio_mode = TUNER_AUDIO_STEREO;
1320 /* set volume, bass and treble */
1321 decoder->audio_main_vol_l = 6;
1322 decoder->audio_main_vol_r = 6;
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001323
Hans Verkuil27760fc2008-11-29 12:57:44 -03001324 v4l2_dbg(1, debug, sd, "writing init values\n");
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001325
1326 /* FIXME!! */
Hans Verkuil27760fc2008-11-29 12:57:44 -03001327 saa717x_write_regs(sd, reg_init_initialize);
Hans Verkuil59b83112010-04-23 09:04:48 -03001328
1329 v4l2_ctrl_handler_setup(hdl);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001330
1331 set_current_state(TASK_INTERRUPTIBLE);
1332 schedule_timeout(2*HZ);
1333 return 0;
1334}
1335
1336static int saa717x_remove(struct i2c_client *client)
1337{
Hans Verkuil27760fc2008-11-29 12:57:44 -03001338 struct v4l2_subdev *sd = i2c_get_clientdata(client);
1339
1340 v4l2_device_unregister_subdev(sd);
Hans Verkuil59b83112010-04-23 09:04:48 -03001341 v4l2_ctrl_handler_free(sd->ctrl_handler);
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001342 return 0;
1343}
1344
1345/* ----------------------------------------------------------------------- */
1346
Jean Delvareaf294862008-05-18 20:49:40 +02001347static const struct i2c_device_id saa717x_id[] = {
1348 { "saa717x", 0 },
1349 { }
1350};
1351MODULE_DEVICE_TABLE(i2c, saa717x_id);
1352
Hans Verkuil720d9162010-09-15 15:01:48 -03001353static struct i2c_driver saa717x_driver = {
1354 .driver = {
Hans Verkuil720d9162010-09-15 15:01:48 -03001355 .name = "saa717x",
1356 },
1357 .probe = saa717x_probe,
1358 .remove = saa717x_remove,
1359 .id_table = saa717x_id,
Hans Verkuilfb7b37c2008-04-09 06:26:17 -03001360};
Hans Verkuil720d9162010-09-15 15:01:48 -03001361
Axel Linc6e8d862012-02-12 06:56:32 -03001362module_i2c_driver(saa717x_driver);