blob: f0eb9851bf532125c73469f4fd43a158693067b6 [file] [log] [blame]
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001/* saa7115 - Philips SAA7114/SAA7115 video decoder driver
2 *
3 * Based on saa7114 driver by Maxim Yevtyushkin, which is based on
4 * the saa7111 driver by Dave Perks.
5 *
6 * Copyright (C) 1998 Dave Perks <dperks@ibm.net>
7 * Copyright (C) 2002 Maxim Yevtyushkin <max@linuxmedialabs.com>
8 *
9 * Slight changes for video timing and attachment output by
10 * Wolfgang Scherr <scherr@net4you.net>
11 *
12 * Moved over to the linux >= 2.4.x i2c protocol (1/1/2003)
13 * by Ronald Bultje <rbultje@ronald.bitfreak.net>
14 *
15 * Added saa7115 support by Kevin Thayer <nufan_wfk at yahoo.com>
16 * (2/17/2003)
17 *
18 * VBI support (2004) and cleanups (2005) by Hans Verkuil <hverkuil@xs4all.nl>
19 *
20 * This program is free software; you can redistribute it and/or
21 * modify it under the terms of the GNU General Public License
22 * as published by the Free Software Foundation; either version 2
23 * of the License, or (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
33 */
34
35
36#include <linux/kernel.h>
37#include <linux/module.h>
38#include <linux/slab.h>
39#include <linux/i2c.h>
40#include <linux/videodev2.h>
Hans Verkuile19b2fc2005-11-13 16:08:04 -080041#include <media/v4l2-common.h>
Hans Verkuilc7f36122006-01-09 15:25:45 -020042#include <media/audiochip.h>
Hans Verkuil3578d3d2006-01-09 15:25:41 -020043#include <asm/div64.h>
Hans Verkuile19b2fc2005-11-13 16:08:04 -080044
45MODULE_DESCRIPTION("Philips SAA7114/SAA7115 video decoder driver");
Hans Verkuil1f4b3362005-11-13 16:08:05 -080046MODULE_AUTHOR("Maxim Yevtyushkin, Kevin Thayer, Chris Kennedy, Hans Verkuil");
Hans Verkuile19b2fc2005-11-13 16:08:04 -080047MODULE_LICENSE("GPL");
48
49static int debug = 0;
Hans Verkuilfac9e892006-01-09 15:32:40 -020050module_param(debug, bool, 0644);
Hans Verkuile19b2fc2005-11-13 16:08:04 -080051
52MODULE_PARM_DESC(debug, "Debug level (0-1)");
53
Hans Verkuile19b2fc2005-11-13 16:08:04 -080054static unsigned short normal_i2c[] = { 0x42 >> 1, 0x40 >> 1, I2C_CLIENT_END };
55
56
57I2C_CLIENT_INSMOD;
58
59struct saa7115_state {
60 v4l2_std_id std;
61 int input;
62 int enable;
Hans Verkuil3faeeae2006-01-09 15:25:44 -020063 int radio;
Hans Verkuile19b2fc2005-11-13 16:08:04 -080064 int bright;
65 int contrast;
66 int hue;
67 int sat;
68 enum v4l2_chip_ident ident;
Hans Verkuil3578d3d2006-01-09 15:25:41 -020069 u32 audclk_freq;
Hans Verkuile19b2fc2005-11-13 16:08:04 -080070};
71
72/* ----------------------------------------------------------------------- */
73
74static inline int saa7115_write(struct i2c_client *client, u8 reg, u8 value)
75{
76 return i2c_smbus_write_byte_data(client, reg, value);
77}
78
79static int saa7115_writeregs(struct i2c_client *client, const unsigned char *regs)
80{
81 unsigned char reg, data;
82
83 while (*regs != 0x00) {
84 reg = *(regs++);
85 data = *(regs++);
86 if (saa7115_write(client, reg, data) < 0)
87 return -1;
88 }
89 return 0;
90}
91
92static inline int saa7115_read(struct i2c_client *client, u8 reg)
93{
94 return i2c_smbus_read_byte_data(client, reg);
95}
96
97/* ----------------------------------------------------------------------- */
98
99/* If a value differs from the Hauppauge driver values, then the comment starts with
100 'was 0xXX' to denote the Hauppauge value. Otherwise the value is identical to what the
101 Hauppauge driver sets. */
102
103static const unsigned char saa7115_init_auto_input[] = {
104 0x01, 0x48, /* white peak control disabled */
105 0x03, 0x20, /* was 0x30. 0x20: long vertical blanking */
106 0x04, 0x90, /* analog gain set to 0 */
107 0x05, 0x90, /* analog gain set to 0 */
108 0x06, 0xeb, /* horiz sync begin = -21 */
109 0x07, 0xe0, /* horiz sync stop = -17 */
110 0x0a, 0x80, /* was 0x88. decoder brightness, 0x80 is itu standard */
111 0x0b, 0x44, /* was 0x48. decoder contrast, 0x44 is itu standard */
112 0x0c, 0x40, /* was 0x47. decoder saturation, 0x40 is itu standard */
113 0x0d, 0x00, /* chrominance hue control */
114 0x0f, 0x00, /* chrominance gain control: use automicatic mode */
115 0x10, 0x06, /* chrominance/luminance control: active adaptive combfilter */
116 0x11, 0x00, /* delay control */
117 0x12, 0x9d, /* RTS0 output control: VGATE */
118 0x13, 0x80, /* X-port output control: ITU656 standard mode, RTCO output enable RTCE */
119 0x14, 0x00, /* analog/ADC/auto compatibility control */
120 0x18, 0x40, /* raw data gain 0x00 = nominal */
121 0x19, 0x80, /* raw data offset 0x80 = 0 LSB */
122 0x1a, 0x77, /* color killer level control 0x77 = recommended */
123 0x1b, 0x42, /* misc chroma control 0x42 = recommended */
124 0x1c, 0xa9, /* combfilter control 0xA9 = recommended */
125 0x1d, 0x01, /* combfilter control 0x01 = recommended */
126 0x88, 0xd0, /* reset device */
127 0x88, 0xf0, /* set device programmed, all in operational mode */
128 0x00, 0x00
129};
130
131static const unsigned char saa7115_cfg_reset_scaler[] = {
132 0x87, 0x00, /* disable I-port output */
133 0x88, 0xd0, /* reset scaler */
134 0x88, 0xf0, /* activate scaler */
135 0x87, 0x01, /* enable I-port output */
136 0x00, 0x00
137};
138
139/* ============== SAA7715 VIDEO templates ============= */
140
141static const unsigned char saa7115_cfg_60hz_fullres_x[] = {
142 0xcc, 0xd0, /* hsize low (output), hor. output window size = 0x2d0 = 720 */
143 0xcd, 0x02, /* hsize hi (output) */
144
145 /* Why not in 60hz-Land, too? */
146 0xd0, 0x01, /* downscale = 1 */
147 0xd8, 0x00, /* hor lum scaling 0x0400 = 1 */
148 0xd9, 0x04,
149 0xdc, 0x00, /* hor chrom scaling 0x0200. must be hor lum scaling / 2 */
150 0xdd, 0x02, /* H-scaling incr chroma */
151
152 0x00, 0x00
153};
154static const unsigned char saa7115_cfg_60hz_fullres_y[] = {
155 0xce, 0xf8, /* vsize low (output), ver. output window size = 248 (but 60hz is 240?) */
156 0xcf, 0x00, /* vsize hi (output) */
157
158 /* Why not in 60hz-Land, too? */
159 0xd5, 0x40, /* Lum contrast, nominal value = 0x40 */
160 0xd6, 0x40, /* Chroma satur. nominal value = 0x80 */
161
162 0xe0, 0x00, /* V-scaling incr luma low */
163 0xe1, 0x04, /* " hi */
164 0xe2, 0x00, /* V-scaling incr chroma low */
165 0xe3, 0x04, /* " hi */
166
167 0x00, 0x00
168};
169
170static const unsigned char saa7115_cfg_60hz_video[] = {
171 0x80, 0x00, /* reset tasks */
172 0x88, 0xd0, /* reset scaler */
173
174 0x15, 0x03, /* VGATE pulse start */
175 0x16, 0x11, /* VGATE pulse stop */
176 0x17, 0x9c, /* VGATE MSB and other values */
177
178 0x08, 0x68, /* 0xBO: auto detection, 0x68 = NTSC */
179 0x0e, 0x07, /* lots of different stuff... video autodetection is on */
180
181 0x5a, 0x06, /* Vertical offset, standard 60hz value for ITU656 line counting */
182
183 /* Task A */
184 0x90, 0x80, /* Task Handling Control */
185 0x91, 0x48, /* X-port formats/config */
186 0x92, 0x40, /* Input Ref. signal Def. */
187 0x93, 0x84, /* I-port config */
188 0x94, 0x01, /* hoffset low (input), 0x0002 is minimum */
189 0x95, 0x00, /* hoffset hi (input) */
190 0x96, 0xd0, /* hsize low (input), 0x02d0 = 720 */
191 0x97, 0x02, /* hsize hi (input) */
192 0x98, 0x05, /* voffset low (input) */
193 0x99, 0x00, /* voffset hi (input) */
194 0x9a, 0x0c, /* vsize low (input), 0x0c = 12 */
195 0x9b, 0x00, /* vsize hi (input) */
196 0x9c, 0xa0, /* hsize low (output), 0x05a0 = 1440 */
197 0x9d, 0x05, /* hsize hi (output) */
198 0x9e, 0x0c, /* vsize low (output), 0x0c = 12 */
199 0x9f, 0x00, /* vsize hi (output) */
200
201 /* Task B */
202 0xc0, 0x00, /* Task Handling Control */
203 0xc1, 0x08, /* X-port formats/config */
204 0xc2, 0x00, /* Input Ref. signal Def. */
205 0xc3, 0x80, /* I-port config */
206 0xc4, 0x02, /* hoffset low (input), 0x0002 is minimum */
207 0xc5, 0x00, /* hoffset hi (input) */
208 0xc6, 0xd0, /* hsize low (input), 0x02d0 = 720 */
209 0xc7, 0x02, /* hsize hi (input) */
210 0xc8, 0x12, /* voffset low (input), 0x12 = 18 */
211 0xc9, 0x00, /* voffset hi (input) */
212 0xca, 0xf8, /* vsize low (input), 0xf8 = 248 */
213 0xcb, 0x00, /* vsize hi (input) */
214 0xcc, 0xd0, /* hsize low (output), 0x02d0 = 720 */
215 0xcd, 0x02, /* hsize hi (output) */
216
217 0xf0, 0xad, /* Set PLL Register. 60hz 525 lines per frame, 27 MHz */
218 0xf1, 0x05, /* low bit with 0xF0 */
219 0xf5, 0xad, /* Set pulse generator register */
220 0xf6, 0x01,
221
222 0x87, 0x00, /* Disable I-port output */
223 0x88, 0xd0, /* reset scaler */
224 0x80, 0x20, /* Activate only task "B", continuous mode (was 0xA0) */
225 0x88, 0xf0, /* activate scaler */
226 0x87, 0x01, /* Enable I-port output */
227 0x00, 0x00
228};
229
230static const unsigned char saa7115_cfg_50hz_fullres_x[] = {
231 0xcc, 0xd0, /* hsize low (output), 720 same as 60hz */
232 0xcd, 0x02, /* hsize hi (output) */
233
234 0xd0, 0x01, /* down scale = 1 */
235 0xd8, 0x00, /* hor lum scaling 0x0400 = 1 */
236 0xd9, 0x04,
237 0xdc, 0x00, /* hor chrom scaling 0x0200. must be hor lum scaling / 2 */
238 0xdd, 0x02, /* H-scaling incr chroma */
239
240 0x00, 0x00
241};
242static const unsigned char saa7115_cfg_50hz_fullres_y[] = {
243 0xce, 0x20, /* vsize low (output), 0x0120 = 288 */
244 0xcf, 0x01, /* vsize hi (output) */
245
246 0xd5, 0x40, /* Lum contrast, nominal value = 0x40 */
247 0xd6, 0x40, /* Chroma satur. nominal value = 0x80 */
248
249 0xe0, 0x00, /* V-scaling incr luma low */
250 0xe1, 0x04, /* " hi */
251 0xe2, 0x00, /* V-scaling incr chroma low */
252 0xe3, 0x04, /* " hi */
253
254 0x00, 0x00
255};
256
257static const unsigned char saa7115_cfg_50hz_video[] = {
258 0x80, 0x00, /* reset tasks */
259 0x88, 0xd0, /* reset scaler */
260
261 0x15, 0x37, /* VGATE start */
262 0x16, 0x16, /* VGATE stop */
263 0x17, 0x99, /* VGATE MSB and other values */
264
265 0x08, 0x28, /* 0x28 = PAL */
266 0x0e, 0x07, /* chrominance control 1 */
267
268 0x5a, 0x03, /* Vertical offset, standard 50hz value */
269
270 /* Task A */
271 0x90, 0x81, /* Task Handling Control */
272 0x91, 0x48, /* X-port formats/config */
273 0x92, 0x40, /* Input Ref. signal Def. */
274 0x93, 0x84, /* I-port config */
275 /* This is weird: the datasheet says that you should use 2 as the minimum value, */
276 /* but Hauppauge uses 0, and changing that to 2 causes indeed problems (for 50hz) */
277 0x94, 0x00, /* hoffset low (input), 0x0002 is minimum */
278 0x95, 0x00, /* hoffset hi (input) */
279 0x96, 0xd0, /* hsize low (input), 0x02d0 = 720 */
280 0x97, 0x02, /* hsize hi (input) */
281 0x98, 0x03, /* voffset low (input) */
282 0x99, 0x00, /* voffset hi (input) */
283 0x9a, 0x12, /* vsize low (input), 0x12 = 18 */
284 0x9b, 0x00, /* vsize hi (input) */
285 0x9c, 0xa0, /* hsize low (output), 0x05a0 = 1440 */
286 0x9d, 0x05, /* hsize hi (output) */
287 0x9e, 0x12, /* vsize low (output), 0x12 = 18 */
288 0x9f, 0x00, /* vsize hi (output) */
289
290 /* Task B */
291 0xc0, 0x00, /* Task Handling Control */
292 0xc1, 0x08, /* X-port formats/config */
293 0xc2, 0x00, /* Input Ref. signal Def. */
294 0xc3, 0x80, /* I-port config */
295 0xc4, 0x00, /* hoffset low (input), 0x0002 is minimum. See comment at 0x94 above. */
296 0xc5, 0x00, /* hoffset hi (input) */
297 0xc6, 0xd0, /* hsize low (input), 0x02d0 = 720 */
298 0xc7, 0x02, /* hsize hi (input) */
299 0xc8, 0x16, /* voffset low (input), 0x16 = 22 */
300 0xc9, 0x00, /* voffset hi (input) */
301 0xca, 0x20, /* vsize low (input), 0x0120 = 288 */
302 0xcb, 0x01, /* vsize hi (input) */
303 0xcc, 0xd0, /* hsize low (output), 0x02d0 = 720 */
304 0xcd, 0x02, /* hsize hi (output) */
305 0xce, 0x20, /* vsize low (output), 0x0120 = 288 */
306 0xcf, 0x01, /* vsize hi (output) */
307
308 0xf0, 0xb0, /* Set PLL Register. 50hz 625 lines per frame, 27 MHz */
309 0xf1, 0x05, /* low bit with 0xF0, (was 0x05) */
310 0xf5, 0xb0, /* Set pulse generator register */
311 0xf6, 0x01,
312
313 0x87, 0x00, /* Disable I-port output */
314 0x88, 0xd0, /* reset scaler (was 0xD0) */
315 0x80, 0x20, /* Activate only task "B" */
316 0x88, 0xf0, /* activate scaler */
317 0x87, 0x01, /* Enable I-port output */
318 0x00, 0x00
319};
320
321/* ============== SAA7715 VIDEO templates (end) ======= */
322
323static const unsigned char saa7115_cfg_vbi_on[] = {
324 0x80, 0x00, /* reset tasks */
325 0x88, 0xd0, /* reset scaler */
326 0x80, 0x30, /* Activate both tasks */
327 0x88, 0xf0, /* activate scaler */
328 0x87, 0x01, /* Enable I-port output */
329 0x00, 0x00
330};
331
332static const unsigned char saa7115_cfg_vbi_off[] = {
333 0x80, 0x00, /* reset tasks */
334 0x88, 0xd0, /* reset scaler */
335 0x80, 0x20, /* Activate only task "B" */
336 0x88, 0xf0, /* activate scaler */
337 0x87, 0x01, /* Enable I-port output */
338 0x00, 0x00
339};
340
341static const unsigned char saa7115_init_misc[] = {
342 0x38, 0x03, /* audio stuff */
343 0x39, 0x10,
344 0x3a, 0x08,
345
346 0x81, 0x01, /* reg 0x15,0x16 define blanking window */
347 0x82, 0x00,
348 0x83, 0x01, /* I port settings */
349 0x84, 0x20,
350 0x85, 0x21,
351 0x86, 0xc5,
352 0x87, 0x01,
353
354 /* Task A */
355 0xa0, 0x01, /* down scale = 1 */
356 0xa1, 0x00, /* prescale accumulation length = 1 */
357 0xa2, 0x00, /* dc gain and fir prefilter control */
358 0xa4, 0x80, /* Lum Brightness, nominal value = 0x80 */
359 0xa5, 0x40, /* Lum contrast, nominal value = 0x40 */
360 0xa6, 0x40, /* Chroma satur. nominal value = 0x80 */
361 0xa8, 0x00, /* hor lum scaling 0x0200 = 2 zoom */
362 0xa9, 0x02, /* note: 2 x zoom ensures that VBI lines have same length as video lines. */
363 0xaa, 0x00, /* H-phase offset Luma = 0 */
364 0xac, 0x00, /* hor chrom scaling 0x0200. must be hor lum scaling / 2 */
365 0xad, 0x01, /* H-scaling incr chroma */
366 0xae, 0x00, /* H-phase offset chroma. must be offset luma / 2 */
367
368 0xb0, 0x00, /* V-scaling incr luma low */
369 0xb1, 0x04, /* " hi */
370 0xb2, 0x00, /* V-scaling incr chroma low */
371 0xb3, 0x04, /* " hi */
372 0xb4, 0x01, /* V-scaling mode control */
373 0xb8, 0x00, /* V-phase offset chroma 00 */
374 0xb9, 0x00, /* V-phase offset chroma 01 */
375 0xba, 0x00, /* V-phase offset chroma 10 */
376 0xbb, 0x00, /* V-phase offset chroma 11 */
377 0xbc, 0x00, /* V-phase offset luma 00 */
378 0xbd, 0x00, /* V-phase offset luma 01 */
379 0xbe, 0x00, /* V-phase offset luma 10 */
380 0xbf, 0x00, /* V-phase offset luma 11 */
381
382 /* Task B */
383 0xd0, 0x01, /* down scale = 1 */
384 0xd1, 0x00, /* prescale accumulation length = 1 */
385 0xd2, 0x00, /* dc gain and fir prefilter control */
386 0xd4, 0x80, /* Lum Brightness, nominal value = 0x80 */
387 0xd5, 0x40, /* Lum contrast, nominal value = 0x40 */
388 0xd6, 0x40, /* Chroma satur. nominal value = 0x80 */
389 0xd8, 0x00, /* hor lum scaling 0x0400 = 1 */
390 0xd9, 0x04,
391 0xda, 0x00, /* H-phase offset Luma = 0 */
392 0xdc, 0x00, /* hor chrom scaling 0x0200. must be hor lum scaling / 2 */
393 0xdd, 0x02, /* H-scaling incr chroma */
394 0xde, 0x00, /* H-phase offset chroma. must be offset luma / 2 */
395
396 0xe0, 0x00, /* V-scaling incr luma low */
397 0xe1, 0x04, /* " hi */
398 0xe2, 0x00, /* V-scaling incr chroma low */
399 0xe3, 0x04, /* " hi */
400 0xe4, 0x01, /* V-scaling mode control */
401 0xe8, 0x00, /* V-phase offset chroma 00 */
402 0xe9, 0x00, /* V-phase offset chroma 01 */
403 0xea, 0x00, /* V-phase offset chroma 10 */
404 0xeb, 0x00, /* V-phase offset chroma 11 */
405 0xec, 0x00, /* V-phase offset luma 00 */
406 0xed, 0x00, /* V-phase offset luma 01 */
407 0xee, 0x00, /* V-phase offset luma 10 */
408 0xef, 0x00, /* V-phase offset luma 11 */
409
410 0xf2, 0x50, /* crystal clock = 24.576 MHz, target = 27MHz */
411 0xf3, 0x46,
412 0xf4, 0x00,
413 0xf7, 0x4b, /* not the recommended settings! */
414 0xf8, 0x00,
415 0xf9, 0x4b,
416 0xfa, 0x00,
417 0xfb, 0x4b,
418 0xff, 0x88, /* PLL2 lock detection settings: 71 lines 50% phase error */
419
420 /* Turn off VBI */
421 0x40, 0x20, /* No framing code errors allowed. */
422 0x41, 0xff,
423 0x42, 0xff,
424 0x43, 0xff,
425 0x44, 0xff,
426 0x45, 0xff,
427 0x46, 0xff,
428 0x47, 0xff,
429 0x48, 0xff,
430 0x49, 0xff,
431 0x4a, 0xff,
432 0x4b, 0xff,
433 0x4c, 0xff,
434 0x4d, 0xff,
435 0x4e, 0xff,
436 0x4f, 0xff,
437 0x50, 0xff,
438 0x51, 0xff,
439 0x52, 0xff,
440 0x53, 0xff,
441 0x54, 0xff,
442 0x55, 0xff,
443 0x56, 0xff,
444 0x57, 0xff,
445 0x58, 0x40,
446 0x59, 0x47,
447 0x5b, 0x83,
448 0x5d, 0xbd,
449 0x5e, 0x35,
450
451 0x02, 0x84, /* input tuner -> input 4, amplifier active */
452 0x09, 0x53, /* 0x53, was 0x56 for 60hz. luminance control */
453
454 0x80, 0x20, /* enable task B */
455 0x88, 0xd0,
456 0x88, 0xf0,
457 0x00, 0x00
458};
459
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800460static int saa7115_odd_parity(u8 c)
461{
462 c ^= (c >> 4);
463 c ^= (c >> 2);
464 c ^= (c >> 1);
465
466 return c & 1;
467}
468
469static int saa7115_decode_vps(u8 * dst, u8 * p)
470{
471 static const u8 biphase_tbl[] = {
472 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
473 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
474 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96,
475 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2,
476 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94,
477 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0,
478 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
479 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
480 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5,
481 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1,
482 0xc3, 0x4b, 0x43, 0xc3, 0x87, 0x0f, 0x07, 0x87,
483 0x83, 0x0b, 0x03, 0x83, 0xc3, 0x4b, 0x43, 0xc3,
484 0xc1, 0x49, 0x41, 0xc1, 0x85, 0x0d, 0x05, 0x85,
485 0x81, 0x09, 0x01, 0x81, 0xc1, 0x49, 0x41, 0xc1,
486 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5,
487 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1,
488 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4,
489 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0,
490 0xc2, 0x4a, 0x42, 0xc2, 0x86, 0x0e, 0x06, 0x86,
491 0x82, 0x0a, 0x02, 0x82, 0xc2, 0x4a, 0x42, 0xc2,
492 0xc0, 0x48, 0x40, 0xc0, 0x84, 0x0c, 0x04, 0x84,
493 0x80, 0x08, 0x00, 0x80, 0xc0, 0x48, 0x40, 0xc0,
494 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4,
495 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0,
496 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
497 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
498 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96,
499 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2,
500 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94,
501 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0,
502 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
503 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
504 };
505 int i;
506 u8 c, err = 0;
507
508 for (i = 0; i < 2 * 13; i += 2) {
509 err |= biphase_tbl[p[i]] | biphase_tbl[p[i + 1]];
510 c = (biphase_tbl[p[i + 1]] & 0xf) | ((biphase_tbl[p[i]] & 0xf) << 4);
511 dst[i / 2] = c;
512 }
513 return err & 0xf0;
514}
515
516static int saa7115_decode_wss(u8 * p)
517{
518 static const int wss_bits[8] = {
519 0, 0, 0, 1, 0, 1, 1, 1
520 };
521 unsigned char parity;
522 int wss = 0;
523 int i;
524
525 for (i = 0; i < 16; i++) {
526 int b1 = wss_bits[p[i] & 7];
527 int b2 = wss_bits[(p[i] >> 3) & 7];
528
529 if (b1 == b2)
530 return -1;
531 wss |= b2 << i;
532 }
533 parity = wss & 15;
534 parity ^= parity >> 2;
535 parity ^= parity >> 1;
536
537 if (!(parity & 1))
538 return -1;
539
540 return wss;
541}
542
543
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200544static int saa7115_set_audio_clock_freq(struct i2c_client *client, u32 freq)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800545{
546 struct saa7115_state *state = i2c_get_clientdata(client);
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200547 u32 acpf;
548 u32 acni;
549 u32 hz;
550 u64 f;
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800551
Mauro Carvalho Chehabf167cb42006-01-11 19:41:49 -0200552 v4l_dbg(1, debug, client, "set audio clock freq: %d\n", freq);
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200553
554 /* sanity check */
555 if (freq < 32000 || freq > 48000)
556 return -EINVAL;
557
558 /* hz is the refresh rate times 100 */
559 hz = (state->std & V4L2_STD_525_60) ? 5994 : 5000;
560 /* acpf = (256 * freq) / field_frequency == (256 * 100 * freq) / hz */
561 acpf = (25600 * freq) / hz;
562 /* acni = (256 * freq * 2^23) / crystal_frequency =
563 (freq * 2^(8+23)) / crystal_frequency =
564 (freq << 31) / 32.11 MHz */
565 f = freq;
566 f = f << 31;
567 do_div(f, 32110000);
568 acni = f;
569
570 saa7115_write(client, 0x30, acpf & 0xff);
571 saa7115_write(client, 0x31, (acpf >> 8) & 0xff);
572 saa7115_write(client, 0x32, (acpf >> 16) & 0x03);
573 saa7115_write(client, 0x34, acni & 0xff);
574 saa7115_write(client, 0x35, (acni >> 8) & 0xff);
575 saa7115_write(client, 0x36, (acni >> 16) & 0x3f);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800576 state->audclk_freq = freq;
577 return 0;
578}
579
580static int saa7115_set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
581{
582 struct saa7115_state *state = i2c_get_clientdata(client);
583
584 switch (ctrl->id) {
585 case V4L2_CID_BRIGHTNESS:
586 if (ctrl->value < 0 || ctrl->value > 255) {
Hans Verkuilfac9e892006-01-09 15:32:40 -0200587 v4l_err(client, "invalid brightness setting %d\n", ctrl->value);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800588 return -ERANGE;
589 }
590
591 state->bright = ctrl->value;
592 saa7115_write(client, 0x0a, state->bright);
593 break;
594
595 case V4L2_CID_CONTRAST:
596 if (ctrl->value < 0 || ctrl->value > 127) {
Hans Verkuilfac9e892006-01-09 15:32:40 -0200597 v4l_err(client, "invalid contrast setting %d\n", ctrl->value);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800598 return -ERANGE;
599 }
600
601 state->contrast = ctrl->value;
602 saa7115_write(client, 0x0b, state->contrast);
603 break;
604
605 case V4L2_CID_SATURATION:
606 if (ctrl->value < 0 || ctrl->value > 127) {
Hans Verkuilfac9e892006-01-09 15:32:40 -0200607 v4l_err(client, "invalid saturation setting %d\n", ctrl->value);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800608 return -ERANGE;
609 }
610
611 state->sat = ctrl->value;
612 saa7115_write(client, 0x0c, state->sat);
613 break;
614
615 case V4L2_CID_HUE:
616 if (ctrl->value < -127 || ctrl->value > 127) {
Hans Verkuilfac9e892006-01-09 15:32:40 -0200617 v4l_err(client, "invalid hue setting %d\n", ctrl->value);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800618 return -ERANGE;
619 }
620
621 state->hue = ctrl->value;
622 saa7115_write(client, 0x0d, state->hue);
623 break;
Hans Verkuil3faeeae2006-01-09 15:25:44 -0200624
625 default:
626 return -EINVAL;
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800627 }
628
629 return 0;
630}
631
632static int saa7115_get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
633{
634 struct saa7115_state *state = i2c_get_clientdata(client);
635
636 switch (ctrl->id) {
637 case V4L2_CID_BRIGHTNESS:
638 ctrl->value = state->bright;
639 break;
640 case V4L2_CID_CONTRAST:
641 ctrl->value = state->contrast;
642 break;
643 case V4L2_CID_SATURATION:
644 ctrl->value = state->sat;
645 break;
646 case V4L2_CID_HUE:
647 ctrl->value = state->hue;
648 break;
649 default:
650 return -EINVAL;
651 }
652
653 return 0;
654}
655
656static void saa7115_set_v4lstd(struct i2c_client *client, v4l2_std_id std)
657{
658 struct saa7115_state *state = i2c_get_clientdata(client);
659 int taskb = saa7115_read(client, 0x80) & 0x10;
660
Hans Verkuil30b54d52006-01-09 15:25:43 -0200661 /* Prevent unnecessary standard changes. During a standard
662 change the I-Port is temporarily disabled. Any devices
663 reading from that port can get confused.
664 Note that VIDIOC_S_STD is also used to switch from
665 radio to TV mode, so if a VIDIOC_S_STD is broadcast to
666 all I2C devices then you do not want to have an unwanted
667 side-effect here. */
668 if (std == state->std)
669 return;
670
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800671 // This works for NTSC-M, SECAM-L and the 50Hz PAL variants.
672 if (std & V4L2_STD_525_60) {
Mauro Carvalho Chehabf167cb42006-01-11 19:41:49 -0200673 v4l_dbg(1, debug, client, "decoder set standard 60 Hz\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800674 saa7115_writeregs(client, saa7115_cfg_60hz_video);
675 } else {
Mauro Carvalho Chehabf167cb42006-01-11 19:41:49 -0200676 v4l_dbg(1, debug, client, "decoder set standard 50 Hz\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800677 saa7115_writeregs(client, saa7115_cfg_50hz_video);
678 }
679
680 state->std = std;
681
682 /* restart task B if needed */
683 if (taskb && state->ident == V4L2_IDENT_SAA7114) {
684 saa7115_writeregs(client, saa7115_cfg_vbi_on);
685 }
686
687 /* switch audio mode too! */
688 saa7115_set_audio_clock_freq(client, state->audclk_freq);
689}
690
691static v4l2_std_id saa7115_get_v4lstd(struct i2c_client *client)
692{
693 struct saa7115_state *state = i2c_get_clientdata(client);
694
695 return state->std;
696}
697
698static void saa7115_log_status(struct i2c_client *client)
699{
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800700 struct saa7115_state *state = i2c_get_clientdata(client);
701 int reg1e, reg1f;
702 int signalOk;
703 int vcr;
704
Hans Verkuilfac9e892006-01-09 15:32:40 -0200705 v4l_info(client, "Audio frequency: %d Hz\n", state->audclk_freq);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800706 if (client->name[6] == '4') {
707 /* status for the saa7114 */
708 reg1f = saa7115_read(client, 0x1f);
709 signalOk = (reg1f & 0xc1) == 0x81;
Hans Verkuilfac9e892006-01-09 15:32:40 -0200710 v4l_info(client, "Video signal: %s\n", signalOk ? "ok" : "bad");
711 v4l_info(client, "Frequency: %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz");
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800712 return;
713 }
714
715 /* status for the saa7115 */
716 reg1e = saa7115_read(client, 0x1e);
717 reg1f = saa7115_read(client, 0x1f);
718
719 signalOk = (reg1f & 0xc1) == 0x81 && (reg1e & 0xc0) == 0x80;
720 vcr = !(reg1f & 0x10);
721
Hans Verkuil21fa7152006-01-09 15:25:41 -0200722 if (state->input >= 6) {
Hans Verkuilfac9e892006-01-09 15:32:40 -0200723 v4l_info(client, "Input: S-Video %d\n", state->input - 6);
Hans Verkuil21fa7152006-01-09 15:25:41 -0200724 } else {
Hans Verkuilfac9e892006-01-09 15:32:40 -0200725 v4l_info(client, "Input: Composite %d\n", state->input);
Hans Verkuil21fa7152006-01-09 15:25:41 -0200726 }
Hans Verkuilfac9e892006-01-09 15:32:40 -0200727 v4l_info(client, "Video signal: %s\n", signalOk ? (vcr ? "VCR" : "broadcast/DVD") : "bad");
728 v4l_info(client, "Frequency: %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz");
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800729
730 switch (reg1e & 0x03) {
731 case 1:
Hans Verkuilfac9e892006-01-09 15:32:40 -0200732 v4l_info(client, "Detected format: NTSC\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800733 break;
734 case 2:
Hans Verkuilfac9e892006-01-09 15:32:40 -0200735 v4l_info(client, "Detected format: PAL\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800736 break;
737 case 3:
Hans Verkuilfac9e892006-01-09 15:32:40 -0200738 v4l_info(client, "Detected format: SECAM\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800739 break;
740 default:
Hans Verkuilfac9e892006-01-09 15:32:40 -0200741 v4l_info(client, "Detected format: BW/No color\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800742 break;
743 }
744}
745
746/* setup the sliced VBI lcr registers according to the sliced VBI format */
747static void saa7115_set_lcr(struct i2c_client *client, struct v4l2_sliced_vbi_format *fmt)
748{
749 struct saa7115_state *state = i2c_get_clientdata(client);
750 int is_50hz = (state->std & V4L2_STD_625_50);
751 u8 lcr[24];
752 int i, x;
753
754 /* saa7114 doesn't yet support VBI */
755 if (state->ident == V4L2_IDENT_SAA7114)
756 return;
757
758 for (i = 0; i <= 23; i++)
759 lcr[i] = 0xff;
760
761 if (fmt->service_set == 0) {
762 /* raw VBI */
763 if (is_50hz)
764 for (i = 6; i <= 23; i++)
765 lcr[i] = 0xdd;
766 else
767 for (i = 10; i <= 21; i++)
768 lcr[i] = 0xdd;
769 } else {
770 /* sliced VBI */
771 /* first clear lines that cannot be captured */
772 if (is_50hz) {
773 for (i = 0; i <= 5; i++)
774 fmt->service_lines[0][i] =
775 fmt->service_lines[1][i] = 0;
776 }
777 else {
778 for (i = 0; i <= 9; i++)
779 fmt->service_lines[0][i] =
780 fmt->service_lines[1][i] = 0;
781 for (i = 22; i <= 23; i++)
782 fmt->service_lines[0][i] =
783 fmt->service_lines[1][i] = 0;
784 }
785
786 /* Now set the lcr values according to the specified service */
787 for (i = 6; i <= 23; i++) {
788 lcr[i] = 0;
789 for (x = 0; x <= 1; x++) {
790 switch (fmt->service_lines[1-x][i]) {
791 case 0:
792 lcr[i] |= 0xf << (4 * x);
793 break;
Mauro Carvalho Chehab6ac48b42006-01-23 17:11:05 -0200794 case V4L2_SLICED_TELETEXT_PAL_B:
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800795 lcr[i] |= 1 << (4 * x);
796 break;
797 case V4L2_SLICED_CAPTION_525:
798 lcr[i] |= 4 << (4 * x);
799 break;
800 case V4L2_SLICED_WSS_625:
801 lcr[i] |= 5 << (4 * x);
802 break;
803 case V4L2_SLICED_VPS:
804 lcr[i] |= 7 << (4 * x);
805 break;
806 }
807 }
808 }
809 }
810
811 /* write the lcr registers */
812 for (i = 2; i <= 23; i++) {
813 saa7115_write(client, i - 2 + 0x41, lcr[i]);
814 }
815
816 /* enable/disable raw VBI capturing */
817 saa7115_writeregs(client, fmt->service_set == 0 ? saa7115_cfg_vbi_on : saa7115_cfg_vbi_off);
818}
819
820static int saa7115_get_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
821{
822 static u16 lcr2vbi[] = {
Mauro Carvalho Chehab6ac48b42006-01-23 17:11:05 -0200823 0, V4L2_SLICED_TELETEXT_PAL_B, 0, /* 1 */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800824 0, V4L2_SLICED_CAPTION_525, /* 4 */
825 V4L2_SLICED_WSS_625, 0, /* 5 */
826 V4L2_SLICED_VPS, 0, 0, 0, 0, /* 7 */
827 0, 0, 0, 0
828 };
829 struct v4l2_sliced_vbi_format *sliced = &fmt->fmt.sliced;
830 int i;
831
832 if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
833 return -EINVAL;
834 memset(sliced, 0, sizeof(*sliced));
835 /* done if using raw VBI */
836 if (saa7115_read(client, 0x80) & 0x10)
837 return 0;
838 for (i = 2; i <= 23; i++) {
839 u8 v = saa7115_read(client, i - 2 + 0x41);
840
841 sliced->service_lines[0][i] = lcr2vbi[v >> 4];
842 sliced->service_lines[1][i] = lcr2vbi[v & 0xf];
843 sliced->service_set |=
844 sliced->service_lines[0][i] | sliced->service_lines[1][i];
845 }
846 return 0;
847}
848
849static int saa7115_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
850{
851 struct saa7115_state *state = i2c_get_clientdata(client);
852 struct v4l2_pix_format *pix;
853 int HPSC, HFSC;
854 int VSCY, Vsrc;
855 int is_50hz = state->std & V4L2_STD_625_50;
856
857 if (fmt->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
858 saa7115_set_lcr(client, &fmt->fmt.sliced);
859 return 0;
860 }
861 if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
862 return -EINVAL;
863
864 pix = &(fmt->fmt.pix);
865
Mauro Carvalho Chehabf167cb42006-01-11 19:41:49 -0200866 v4l_dbg(1, debug, client, "decoder set size\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800867
868 /* FIXME need better bounds checking here */
869 if ((pix->width < 1) || (pix->width > 1440))
870 return -EINVAL;
871 if ((pix->height < 1) || (pix->height > 960))
872 return -EINVAL;
873
874 /* probably have a valid size, let's set it */
875 /* Set output width/height */
876 /* width */
877 saa7115_write(client, 0xcc, (u8) (pix->width & 0xff));
878 saa7115_write(client, 0xcd, (u8) ((pix->width >> 8) & 0xff));
879 /* height */
880 saa7115_write(client, 0xce, (u8) (pix->height & 0xff));
881 saa7115_write(client, 0xcf, (u8) ((pix->height >> 8) & 0xff));
882
883 /* Scaling settings */
884 /* Hprescaler is floor(inres/outres) */
885 /* FIXME hardcoding input res */
886 if (pix->width != 720) {
887 HPSC = (int)(720 / pix->width);
888 /* 0 is not allowed (div. by zero) */
889 HPSC = HPSC ? HPSC : 1;
890 HFSC = (int)((1024 * 720) / (HPSC * pix->width));
891
Mauro Carvalho Chehabf167cb42006-01-11 19:41:49 -0200892 v4l_dbg(1, debug, client, "Hpsc: 0x%05x, Hfsc: 0x%05x\n", HPSC, HFSC);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800893 /* FIXME hardcodes to "Task B"
894 * write H prescaler integer */
895 saa7115_write(client, 0xd0, (u8) (HPSC & 0x3f));
896
897 /* write H fine-scaling (luminance) */
898 saa7115_write(client, 0xd8, (u8) (HFSC & 0xff));
899 saa7115_write(client, 0xd9, (u8) ((HFSC >> 8) & 0xff));
900 /* write H fine-scaling (chrominance)
901 * must be lum/2, so i'll just bitshift :) */
902 saa7115_write(client, 0xDC, (u8) ((HFSC >> 1) & 0xff));
903 saa7115_write(client, 0xDD, (u8) ((HFSC >> 9) & 0xff));
904 } else {
905 if (is_50hz) {
Mauro Carvalho Chehabf167cb42006-01-11 19:41:49 -0200906 v4l_dbg(1, debug, client, "Setting full 50hz width\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800907 saa7115_writeregs(client, saa7115_cfg_50hz_fullres_x);
908 } else {
Mauro Carvalho Chehabf167cb42006-01-11 19:41:49 -0200909 v4l_dbg(1, debug, client, "Setting full 60hz width\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800910 saa7115_writeregs(client, saa7115_cfg_60hz_fullres_x);
911 }
912 }
913
914 Vsrc = is_50hz ? 576 : 480;
915
916 if (pix->height != Vsrc) {
917 VSCY = (int)((1024 * Vsrc) / pix->height);
Mauro Carvalho Chehabf167cb42006-01-11 19:41:49 -0200918 v4l_dbg(1, debug, client, "Vsrc: %d, Vscy: 0x%05x\n", Vsrc, VSCY);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800919
920 /* Correct Contrast and Luminance */
921 saa7115_write(client, 0xd5, (u8) (64 * 1024 / VSCY));
922 saa7115_write(client, 0xd6, (u8) (64 * 1024 / VSCY));
923
924 /* write V fine-scaling (luminance) */
925 saa7115_write(client, 0xe0, (u8) (VSCY & 0xff));
926 saa7115_write(client, 0xe1, (u8) ((VSCY >> 8) & 0xff));
927 /* write V fine-scaling (chrominance) */
928 saa7115_write(client, 0xe2, (u8) (VSCY & 0xff));
929 saa7115_write(client, 0xe3, (u8) ((VSCY >> 8) & 0xff));
930 } else {
931 if (is_50hz) {
Mauro Carvalho Chehabf167cb42006-01-11 19:41:49 -0200932 v4l_dbg(1, debug, client, "Setting full 50Hz height\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800933 saa7115_writeregs(client, saa7115_cfg_50hz_fullres_y);
934 } else {
Mauro Carvalho Chehabf167cb42006-01-11 19:41:49 -0200935 v4l_dbg(1, debug, client, "Setting full 60hz height\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800936 saa7115_writeregs(client, saa7115_cfg_60hz_fullres_y);
937 }
938 }
939
940 saa7115_writeregs(client, saa7115_cfg_reset_scaler);
941 return 0;
942}
943
944/* Decode the sliced VBI data stream as created by the saa7115.
945 The format is described in the saa7115 datasheet in Tables 25 and 26
946 and in Figure 33.
947 The current implementation uses SAV/EAV codes and not the ancillary data
948 headers. The vbi->p pointer points to the SDID byte right after the SAV
949 code. */
950static void saa7115_decode_vbi_line(struct i2c_client *client,
951 struct v4l2_decode_vbi_line *vbi)
952{
953 static const char vbi_no_data_pattern[] = {
954 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0
955 };
956 struct saa7115_state *state = i2c_get_clientdata(client);
957 u8 *p = vbi->p;
958 u32 wss;
959 int id1, id2; /* the ID1 and ID2 bytes from the internal header */
960
961 vbi->type = 0; /* mark result as a failure */
962 id1 = p[2];
963 id2 = p[3];
964 /* Note: the field bit is inverted for 60 Hz video */
965 if (state->std & V4L2_STD_525_60)
966 id1 ^= 0x40;
967
968 /* Skip internal header, p now points to the start of the payload */
969 p += 4;
970 vbi->p = p;
971
972 /* calculate field and line number of the VBI packet (1-23) */
973 vbi->is_second_field = ((id1 & 0x40) != 0);
974 vbi->line = (id1 & 0x3f) << 3;
975 vbi->line |= (id2 & 0x70) >> 4;
976
977 /* Obtain data type */
978 id2 &= 0xf;
979
980 /* If the VBI slicer does not detect any signal it will fill up
981 the payload buffer with 0xa0 bytes. */
982 if (!memcmp(p, vbi_no_data_pattern, sizeof(vbi_no_data_pattern)))
983 return;
984
985 /* decode payloads */
986 switch (id2) {
987 case 1:
Mauro Carvalho Chehab6ac48b42006-01-23 17:11:05 -0200988 vbi->type = V4L2_SLICED_TELETEXT_PAL_B;
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800989 break;
990 case 4:
991 if (!saa7115_odd_parity(p[0]) || !saa7115_odd_parity(p[1]))
992 return;
993 vbi->type = V4L2_SLICED_CAPTION_525;
994 break;
995 case 5:
996 wss = saa7115_decode_wss(p);
997 if (wss == -1)
998 return;
999 p[0] = wss & 0xff;
1000 p[1] = wss >> 8;
1001 vbi->type = V4L2_SLICED_WSS_625;
1002 break;
1003 case 7:
1004 if (saa7115_decode_vps(p, p) != 0)
1005 return;
1006 vbi->type = V4L2_SLICED_VPS;
1007 break;
1008 default:
1009 return;
1010 }
1011}
1012
1013/* ============ SAA7115 AUDIO settings (end) ============= */
1014
Hans Verkuilda4ae5a2006-01-09 15:32:41 -02001015static struct v4l2_queryctrl saa7115_qctrl[] = {
1016 {
1017 .id = V4L2_CID_BRIGHTNESS,
1018 .type = V4L2_CTRL_TYPE_INTEGER,
1019 .name = "Brightness",
1020 .minimum = 0,
1021 .maximum = 255,
1022 .step = 1,
1023 .default_value = 128,
1024 .flags = 0,
1025 }, {
1026 .id = V4L2_CID_CONTRAST,
1027 .type = V4L2_CTRL_TYPE_INTEGER,
1028 .name = "Contrast",
1029 .minimum = 0,
Hans Verkuilecc0b942006-02-27 00:08:20 -03001030 .maximum = 127,
Hans Verkuilda4ae5a2006-01-09 15:32:41 -02001031 .step = 1,
1032 .default_value = 64,
1033 .flags = 0,
1034 }, {
1035 .id = V4L2_CID_SATURATION,
1036 .type = V4L2_CTRL_TYPE_INTEGER,
1037 .name = "Saturation",
1038 .minimum = 0,
Hans Verkuilecc0b942006-02-27 00:08:20 -03001039 .maximum = 127,
Hans Verkuilda4ae5a2006-01-09 15:32:41 -02001040 .step = 1,
1041 .default_value = 64,
1042 .flags = 0,
1043 }, {
1044 .id = V4L2_CID_HUE,
1045 .type = V4L2_CTRL_TYPE_INTEGER,
1046 .name = "Hue",
1047 .minimum = -128,
1048 .maximum = 127,
1049 .step = 1,
1050 .default_value = 0,
1051 .flags = 0,
1052 },
1053};
1054
1055/* ----------------------------------------------------------------------- */
1056
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001057static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *arg)
1058{
1059 struct saa7115_state *state = i2c_get_clientdata(client);
1060 int *iarg = arg;
1061
1062 /* ioctls to allow direct access to the saa7115 registers for testing */
1063 switch (cmd) {
1064 case VIDIOC_S_FMT:
1065 return saa7115_set_v4lfmt(client, (struct v4l2_format *)arg);
1066
1067 case VIDIOC_G_FMT:
1068 return saa7115_get_v4lfmt(client, (struct v4l2_format *)arg);
1069
1070 case VIDIOC_INT_AUDIO_CLOCK_FREQ:
Hans Verkuil3578d3d2006-01-09 15:25:41 -02001071 return saa7115_set_audio_clock_freq(client, *(u32 *)arg);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001072
1073 case VIDIOC_G_TUNER:
1074 {
1075 struct v4l2_tuner *vt = arg;
1076 int status;
1077
Hans Verkuil3faeeae2006-01-09 15:25:44 -02001078 if (state->radio)
1079 break;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001080 status = saa7115_read(client, 0x1f);
1081
Mauro Carvalho Chehabf167cb42006-01-11 19:41:49 -02001082 v4l_dbg(1, debug, client, "status: 0x%02x\n", status);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001083 vt->signal = ((status & (1 << 6)) == 0) ? 0xffff : 0x0;
1084 break;
1085 }
1086
1087 case VIDIOC_LOG_STATUS:
1088 saa7115_log_status(client);
1089 break;
1090
1091 case VIDIOC_G_CTRL:
1092 return saa7115_get_v4lctrl(client, (struct v4l2_control *)arg);
1093
1094 case VIDIOC_S_CTRL:
1095 return saa7115_set_v4lctrl(client, (struct v4l2_control *)arg);
1096
Hans Verkuilda4ae5a2006-01-09 15:32:41 -02001097 case VIDIOC_QUERYCTRL:
1098 {
1099 struct v4l2_queryctrl *qc = arg;
1100 int i;
1101
1102 for (i = 0; i < ARRAY_SIZE(saa7115_qctrl); i++)
1103 if (qc->id && qc->id == saa7115_qctrl[i].id) {
1104 memcpy(qc, &saa7115_qctrl[i], sizeof(*qc));
1105 return 0;
1106 }
1107 return -EINVAL;
1108 }
1109
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001110 case VIDIOC_G_STD:
1111 *(v4l2_std_id *)arg = saa7115_get_v4lstd(client);
1112 break;
1113
1114 case VIDIOC_S_STD:
Hans Verkuil3faeeae2006-01-09 15:25:44 -02001115 state->radio = 0;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001116 saa7115_set_v4lstd(client, *(v4l2_std_id *)arg);
1117 break;
1118
Hans Verkuil3faeeae2006-01-09 15:25:44 -02001119 case AUDC_SET_RADIO:
1120 state->radio = 1;
1121 break;
1122
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001123 case VIDIOC_G_INPUT:
1124 *(int *)arg = state->input;
1125 break;
1126
1127 case VIDIOC_S_INPUT:
Mauro Carvalho Chehabf167cb42006-01-11 19:41:49 -02001128 v4l_dbg(1, debug, client, "decoder set input %d\n", *iarg);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001129 /* inputs from 0-9 are available */
1130 if (*iarg < 0 || *iarg > 9) {
1131 return -EINVAL;
1132 }
1133
1134 if (state->input == *iarg)
1135 break;
Mauro Carvalho Chehabf167cb42006-01-11 19:41:49 -02001136 v4l_dbg(1, debug, client, "now setting %s input\n",
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001137 *iarg >= 6 ? "S-Video" : "Composite");
1138 state->input = *iarg;
1139
1140 /* select mode */
1141 saa7115_write(client, 0x02,
1142 (saa7115_read(client, 0x02) & 0xf0) |
1143 state->input);
1144
1145 /* bypass chrominance trap for modes 6..9 */
1146 saa7115_write(client, 0x09,
1147 (saa7115_read(client, 0x09) & 0x7f) |
1148 (state->input < 6 ? 0x0 : 0x80));
1149 break;
1150
1151 case VIDIOC_STREAMON:
1152 case VIDIOC_STREAMOFF:
Mauro Carvalho Chehabf167cb42006-01-11 19:41:49 -02001153 v4l_dbg(1, debug, client, "%s output\n",
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001154 (cmd == VIDIOC_STREAMON) ? "enable" : "disable");
1155
1156 if (state->enable != (cmd == VIDIOC_STREAMON)) {
1157 state->enable = (cmd == VIDIOC_STREAMON);
1158 saa7115_write(client, 0x87, state->enable);
1159 }
1160 break;
1161
1162 case VIDIOC_INT_DECODE_VBI_LINE:
1163 saa7115_decode_vbi_line(client, arg);
1164 break;
1165
1166 case VIDIOC_INT_RESET:
Mauro Carvalho Chehabf167cb42006-01-11 19:41:49 -02001167 v4l_dbg(1, debug, client, "decoder RESET\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001168 saa7115_writeregs(client, saa7115_cfg_reset_scaler);
1169 break;
1170
1171 case VIDIOC_INT_G_VBI_DATA:
1172 {
1173 struct v4l2_sliced_vbi_data *data = arg;
1174
1175 switch (data->id) {
1176 case V4L2_SLICED_WSS_625:
1177 if (saa7115_read(client, 0x6b) & 0xc0)
1178 return -EIO;
1179 data->data[0] = saa7115_read(client, 0x6c);
1180 data->data[1] = saa7115_read(client, 0x6d);
1181 return 0;
1182 case V4L2_SLICED_CAPTION_525:
1183 if (data->field == 0) {
1184 /* CC */
1185 if (saa7115_read(client, 0x66) & 0xc0)
1186 return -EIO;
1187 data->data[0] = saa7115_read(client, 0x67);
1188 data->data[1] = saa7115_read(client, 0x68);
1189 return 0;
1190 }
1191 /* XDS */
1192 if (saa7115_read(client, 0x66) & 0x30)
1193 return -EIO;
1194 data->data[0] = saa7115_read(client, 0x69);
1195 data->data[1] = saa7115_read(client, 0x6a);
1196 return 0;
1197 default:
1198 return -EINVAL;
1199 }
1200 break;
1201 }
1202
1203#ifdef CONFIG_VIDEO_ADV_DEBUG
1204 case VIDIOC_INT_G_REGISTER:
1205 {
1206 struct v4l2_register *reg = arg;
1207
1208 if (reg->i2c_id != I2C_DRIVERID_SAA711X)
1209 return -EINVAL;
1210 reg->val = saa7115_read(client, reg->reg & 0xff);
1211 break;
1212 }
1213
1214 case VIDIOC_INT_S_REGISTER:
1215 {
1216 struct v4l2_register *reg = arg;
1217
1218 if (reg->i2c_id != I2C_DRIVERID_SAA711X)
1219 return -EINVAL;
1220 if (!capable(CAP_SYS_ADMIN))
1221 return -EPERM;
1222 saa7115_write(client, reg->reg & 0xff, reg->val & 0xff);
1223 break;
1224 }
1225#endif
1226
1227 case VIDIOC_INT_G_CHIP_IDENT:
1228 *iarg = state->ident;
1229 break;
1230
1231 default:
1232 return -EINVAL;
1233 }
1234
1235 return 0;
1236}
1237
1238/* ----------------------------------------------------------------------- */
1239
1240static struct i2c_driver i2c_driver_saa7115;
1241
1242static int saa7115_attach(struct i2c_adapter *adapter, int address, int kind)
1243{
1244 struct i2c_client *client;
1245 struct saa7115_state *state;
1246 u8 chip_id;
1247
1248 /* Check if the adapter supports the needed features */
1249 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
1250 return 0;
1251
Panagiotis Issaris74081872006-01-11 19:40:56 -02001252 client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001253 if (client == 0)
1254 return -ENOMEM;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001255 client->addr = address;
1256 client->adapter = adapter;
1257 client->driver = &i2c_driver_saa7115;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001258 snprintf(client->name, sizeof(client->name) - 1, "saa7115");
1259
Mauro Carvalho Chehabf167cb42006-01-11 19:41:49 -02001260 v4l_dbg(1, debug, client, "detecting saa7115 client on address 0x%x\n", address << 1);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001261
1262 saa7115_write(client, 0, 5);
1263 chip_id = saa7115_read(client, 0) & 0x0f;
1264 if (chip_id != 4 && chip_id != 5) {
Mauro Carvalho Chehabf167cb42006-01-11 19:41:49 -02001265 v4l_dbg(1, debug, client, "saa7115 not found\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001266 kfree(client);
1267 return 0;
1268 }
1269 if (chip_id == 4) {
1270 snprintf(client->name, sizeof(client->name) - 1, "saa7114");
1271 }
Hans Verkuilfac9e892006-01-09 15:32:40 -02001272 v4l_info(client, "saa711%d found @ 0x%x (%s)\n", chip_id, address << 1, adapter->name);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001273
Panagiotis Issaris74081872006-01-11 19:40:56 -02001274 state = kzalloc(sizeof(struct saa7115_state), GFP_KERNEL);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001275 i2c_set_clientdata(client, state);
1276 if (state == NULL) {
1277 kfree(client);
1278 return -ENOMEM;
1279 }
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001280 state->std = V4L2_STD_NTSC;
1281 state->input = -1;
1282 state->enable = 1;
Hans Verkuil3faeeae2006-01-09 15:25:44 -02001283 state->radio = 0;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001284 state->bright = 128;
1285 state->contrast = 64;
1286 state->hue = 0;
1287 state->sat = 64;
1288 state->ident = (chip_id == 4) ? V4L2_IDENT_SAA7114 : V4L2_IDENT_SAA7115;
Hans Verkuil3578d3d2006-01-09 15:25:41 -02001289 state->audclk_freq = 48000;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001290
Mauro Carvalho Chehabf167cb42006-01-11 19:41:49 -02001291 v4l_dbg(1, debug, client, "writing init values\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001292
1293 /* init to 60hz/48khz */
1294 saa7115_writeregs(client, saa7115_init_auto_input);
1295 saa7115_writeregs(client, saa7115_init_misc);
1296 saa7115_writeregs(client, saa7115_cfg_60hz_fullres_x);
1297 saa7115_writeregs(client, saa7115_cfg_60hz_fullres_y);
1298 saa7115_writeregs(client, saa7115_cfg_60hz_video);
Hans Verkuil3578d3d2006-01-09 15:25:41 -02001299 saa7115_set_audio_clock_freq(client, state->audclk_freq);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001300 saa7115_writeregs(client, saa7115_cfg_reset_scaler);
1301
1302 i2c_attach_client(client);
1303
Mauro Carvalho Chehabf167cb42006-01-11 19:41:49 -02001304 v4l_dbg(1, debug, client, "status: (1E) 0x%02x, (1F) 0x%02x\n",
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001305 saa7115_read(client, 0x1e), saa7115_read(client, 0x1f));
1306
1307 return 0;
1308}
1309
1310static int saa7115_probe(struct i2c_adapter *adapter)
1311{
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001312 if (adapter->class & I2C_CLASS_TV_ANALOG)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001313 return i2c_probe(adapter, &addr_data, &saa7115_attach);
1314 return 0;
1315}
1316
1317static int saa7115_detach(struct i2c_client *client)
1318{
1319 struct saa7115_state *state = i2c_get_clientdata(client);
1320 int err;
1321
1322 err = i2c_detach_client(client);
1323 if (err) {
1324 return err;
1325 }
1326
1327 kfree(state);
1328 kfree(client);
1329 return 0;
1330}
1331
1332/* ----------------------------------------------------------------------- */
1333
1334/* i2c implementation */
1335static struct i2c_driver i2c_driver_saa7115 = {
Laurent Riffard604f28e2005-11-26 20:43:39 +01001336 .driver = {
Laurent Riffard604f28e2005-11-26 20:43:39 +01001337 .name = "saa7115",
1338 },
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001339 .id = I2C_DRIVERID_SAA711X,
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001340 .attach_adapter = saa7115_probe,
1341 .detach_client = saa7115_detach,
1342 .command = saa7115_command,
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001343};
1344
1345
1346static int __init saa7115_init_module(void)
1347{
1348 return i2c_add_driver(&i2c_driver_saa7115);
1349}
1350
1351static void __exit saa7115_cleanup_module(void)
1352{
1353 i2c_del_driver(&i2c_driver_saa7115);
1354}
1355
1356module_init(saa7115_init_module);
1357module_exit(saa7115_cleanup_module);