blob: cf530b94cd12b4408f24ad7ee99bdba859ffebac [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;
50module_param(debug, int, 0644);
51
52MODULE_PARM_DESC(debug, "Debug level (0-1)");
53
54#define saa7115_dbg(fmt,arg...) \
55 do { \
56 if (debug) \
Laurent Riffard604f28e2005-11-26 20:43:39 +010057 printk(KERN_INFO "%s debug %d-%04x: " fmt, \
58 client->driver->driver.name, \
Hans Verkuile19b2fc2005-11-13 16:08:04 -080059 i2c_adapter_id(client->adapter), client->addr , ## arg); \
60 } while (0)
61
62#define saa7115_err(fmt, arg...) do { \
Laurent Riffard604f28e2005-11-26 20:43:39 +010063 printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->driver.name, \
Hans Verkuile19b2fc2005-11-13 16:08:04 -080064 i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
65#define saa7115_info(fmt, arg...) do { \
Laurent Riffard604f28e2005-11-26 20:43:39 +010066 printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->driver.name, \
Hans Verkuile19b2fc2005-11-13 16:08:04 -080067 i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
68
69static unsigned short normal_i2c[] = { 0x42 >> 1, 0x40 >> 1, I2C_CLIENT_END };
70
71
72I2C_CLIENT_INSMOD;
73
74struct saa7115_state {
75 v4l2_std_id std;
76 int input;
77 int enable;
Hans Verkuil3faeeae2006-01-09 15:25:44 -020078 int radio;
Hans Verkuile19b2fc2005-11-13 16:08:04 -080079 int bright;
80 int contrast;
81 int hue;
82 int sat;
83 enum v4l2_chip_ident ident;
Hans Verkuil3578d3d2006-01-09 15:25:41 -020084 u32 audclk_freq;
Hans Verkuile19b2fc2005-11-13 16:08:04 -080085};
86
87/* ----------------------------------------------------------------------- */
88
89static inline int saa7115_write(struct i2c_client *client, u8 reg, u8 value)
90{
91 return i2c_smbus_write_byte_data(client, reg, value);
92}
93
94static int saa7115_writeregs(struct i2c_client *client, const unsigned char *regs)
95{
96 unsigned char reg, data;
97
98 while (*regs != 0x00) {
99 reg = *(regs++);
100 data = *(regs++);
101 if (saa7115_write(client, reg, data) < 0)
102 return -1;
103 }
104 return 0;
105}
106
107static inline int saa7115_read(struct i2c_client *client, u8 reg)
108{
109 return i2c_smbus_read_byte_data(client, reg);
110}
111
112/* ----------------------------------------------------------------------- */
113
114/* If a value differs from the Hauppauge driver values, then the comment starts with
115 'was 0xXX' to denote the Hauppauge value. Otherwise the value is identical to what the
116 Hauppauge driver sets. */
117
118static const unsigned char saa7115_init_auto_input[] = {
119 0x01, 0x48, /* white peak control disabled */
120 0x03, 0x20, /* was 0x30. 0x20: long vertical blanking */
121 0x04, 0x90, /* analog gain set to 0 */
122 0x05, 0x90, /* analog gain set to 0 */
123 0x06, 0xeb, /* horiz sync begin = -21 */
124 0x07, 0xe0, /* horiz sync stop = -17 */
125 0x0a, 0x80, /* was 0x88. decoder brightness, 0x80 is itu standard */
126 0x0b, 0x44, /* was 0x48. decoder contrast, 0x44 is itu standard */
127 0x0c, 0x40, /* was 0x47. decoder saturation, 0x40 is itu standard */
128 0x0d, 0x00, /* chrominance hue control */
129 0x0f, 0x00, /* chrominance gain control: use automicatic mode */
130 0x10, 0x06, /* chrominance/luminance control: active adaptive combfilter */
131 0x11, 0x00, /* delay control */
132 0x12, 0x9d, /* RTS0 output control: VGATE */
133 0x13, 0x80, /* X-port output control: ITU656 standard mode, RTCO output enable RTCE */
134 0x14, 0x00, /* analog/ADC/auto compatibility control */
135 0x18, 0x40, /* raw data gain 0x00 = nominal */
136 0x19, 0x80, /* raw data offset 0x80 = 0 LSB */
137 0x1a, 0x77, /* color killer level control 0x77 = recommended */
138 0x1b, 0x42, /* misc chroma control 0x42 = recommended */
139 0x1c, 0xa9, /* combfilter control 0xA9 = recommended */
140 0x1d, 0x01, /* combfilter control 0x01 = recommended */
141 0x88, 0xd0, /* reset device */
142 0x88, 0xf0, /* set device programmed, all in operational mode */
143 0x00, 0x00
144};
145
146static const unsigned char saa7115_cfg_reset_scaler[] = {
147 0x87, 0x00, /* disable I-port output */
148 0x88, 0xd0, /* reset scaler */
149 0x88, 0xf0, /* activate scaler */
150 0x87, 0x01, /* enable I-port output */
151 0x00, 0x00
152};
153
154/* ============== SAA7715 VIDEO templates ============= */
155
156static const unsigned char saa7115_cfg_60hz_fullres_x[] = {
157 0xcc, 0xd0, /* hsize low (output), hor. output window size = 0x2d0 = 720 */
158 0xcd, 0x02, /* hsize hi (output) */
159
160 /* Why not in 60hz-Land, too? */
161 0xd0, 0x01, /* downscale = 1 */
162 0xd8, 0x00, /* hor lum scaling 0x0400 = 1 */
163 0xd9, 0x04,
164 0xdc, 0x00, /* hor chrom scaling 0x0200. must be hor lum scaling / 2 */
165 0xdd, 0x02, /* H-scaling incr chroma */
166
167 0x00, 0x00
168};
169static const unsigned char saa7115_cfg_60hz_fullres_y[] = {
170 0xce, 0xf8, /* vsize low (output), ver. output window size = 248 (but 60hz is 240?) */
171 0xcf, 0x00, /* vsize hi (output) */
172
173 /* Why not in 60hz-Land, too? */
174 0xd5, 0x40, /* Lum contrast, nominal value = 0x40 */
175 0xd6, 0x40, /* Chroma satur. nominal value = 0x80 */
176
177 0xe0, 0x00, /* V-scaling incr luma low */
178 0xe1, 0x04, /* " hi */
179 0xe2, 0x00, /* V-scaling incr chroma low */
180 0xe3, 0x04, /* " hi */
181
182 0x00, 0x00
183};
184
185static const unsigned char saa7115_cfg_60hz_video[] = {
186 0x80, 0x00, /* reset tasks */
187 0x88, 0xd0, /* reset scaler */
188
189 0x15, 0x03, /* VGATE pulse start */
190 0x16, 0x11, /* VGATE pulse stop */
191 0x17, 0x9c, /* VGATE MSB and other values */
192
193 0x08, 0x68, /* 0xBO: auto detection, 0x68 = NTSC */
194 0x0e, 0x07, /* lots of different stuff... video autodetection is on */
195
196 0x5a, 0x06, /* Vertical offset, standard 60hz value for ITU656 line counting */
197
198 /* Task A */
199 0x90, 0x80, /* Task Handling Control */
200 0x91, 0x48, /* X-port formats/config */
201 0x92, 0x40, /* Input Ref. signal Def. */
202 0x93, 0x84, /* I-port config */
203 0x94, 0x01, /* hoffset low (input), 0x0002 is minimum */
204 0x95, 0x00, /* hoffset hi (input) */
205 0x96, 0xd0, /* hsize low (input), 0x02d0 = 720 */
206 0x97, 0x02, /* hsize hi (input) */
207 0x98, 0x05, /* voffset low (input) */
208 0x99, 0x00, /* voffset hi (input) */
209 0x9a, 0x0c, /* vsize low (input), 0x0c = 12 */
210 0x9b, 0x00, /* vsize hi (input) */
211 0x9c, 0xa0, /* hsize low (output), 0x05a0 = 1440 */
212 0x9d, 0x05, /* hsize hi (output) */
213 0x9e, 0x0c, /* vsize low (output), 0x0c = 12 */
214 0x9f, 0x00, /* vsize hi (output) */
215
216 /* Task B */
217 0xc0, 0x00, /* Task Handling Control */
218 0xc1, 0x08, /* X-port formats/config */
219 0xc2, 0x00, /* Input Ref. signal Def. */
220 0xc3, 0x80, /* I-port config */
221 0xc4, 0x02, /* hoffset low (input), 0x0002 is minimum */
222 0xc5, 0x00, /* hoffset hi (input) */
223 0xc6, 0xd0, /* hsize low (input), 0x02d0 = 720 */
224 0xc7, 0x02, /* hsize hi (input) */
225 0xc8, 0x12, /* voffset low (input), 0x12 = 18 */
226 0xc9, 0x00, /* voffset hi (input) */
227 0xca, 0xf8, /* vsize low (input), 0xf8 = 248 */
228 0xcb, 0x00, /* vsize hi (input) */
229 0xcc, 0xd0, /* hsize low (output), 0x02d0 = 720 */
230 0xcd, 0x02, /* hsize hi (output) */
231
232 0xf0, 0xad, /* Set PLL Register. 60hz 525 lines per frame, 27 MHz */
233 0xf1, 0x05, /* low bit with 0xF0 */
234 0xf5, 0xad, /* Set pulse generator register */
235 0xf6, 0x01,
236
237 0x87, 0x00, /* Disable I-port output */
238 0x88, 0xd0, /* reset scaler */
239 0x80, 0x20, /* Activate only task "B", continuous mode (was 0xA0) */
240 0x88, 0xf0, /* activate scaler */
241 0x87, 0x01, /* Enable I-port output */
242 0x00, 0x00
243};
244
245static const unsigned char saa7115_cfg_50hz_fullres_x[] = {
246 0xcc, 0xd0, /* hsize low (output), 720 same as 60hz */
247 0xcd, 0x02, /* hsize hi (output) */
248
249 0xd0, 0x01, /* down scale = 1 */
250 0xd8, 0x00, /* hor lum scaling 0x0400 = 1 */
251 0xd9, 0x04,
252 0xdc, 0x00, /* hor chrom scaling 0x0200. must be hor lum scaling / 2 */
253 0xdd, 0x02, /* H-scaling incr chroma */
254
255 0x00, 0x00
256};
257static const unsigned char saa7115_cfg_50hz_fullres_y[] = {
258 0xce, 0x20, /* vsize low (output), 0x0120 = 288 */
259 0xcf, 0x01, /* vsize hi (output) */
260
261 0xd5, 0x40, /* Lum contrast, nominal value = 0x40 */
262 0xd6, 0x40, /* Chroma satur. nominal value = 0x80 */
263
264 0xe0, 0x00, /* V-scaling incr luma low */
265 0xe1, 0x04, /* " hi */
266 0xe2, 0x00, /* V-scaling incr chroma low */
267 0xe3, 0x04, /* " hi */
268
269 0x00, 0x00
270};
271
272static const unsigned char saa7115_cfg_50hz_video[] = {
273 0x80, 0x00, /* reset tasks */
274 0x88, 0xd0, /* reset scaler */
275
276 0x15, 0x37, /* VGATE start */
277 0x16, 0x16, /* VGATE stop */
278 0x17, 0x99, /* VGATE MSB and other values */
279
280 0x08, 0x28, /* 0x28 = PAL */
281 0x0e, 0x07, /* chrominance control 1 */
282
283 0x5a, 0x03, /* Vertical offset, standard 50hz value */
284
285 /* Task A */
286 0x90, 0x81, /* Task Handling Control */
287 0x91, 0x48, /* X-port formats/config */
288 0x92, 0x40, /* Input Ref. signal Def. */
289 0x93, 0x84, /* I-port config */
290 /* This is weird: the datasheet says that you should use 2 as the minimum value, */
291 /* but Hauppauge uses 0, and changing that to 2 causes indeed problems (for 50hz) */
292 0x94, 0x00, /* hoffset low (input), 0x0002 is minimum */
293 0x95, 0x00, /* hoffset hi (input) */
294 0x96, 0xd0, /* hsize low (input), 0x02d0 = 720 */
295 0x97, 0x02, /* hsize hi (input) */
296 0x98, 0x03, /* voffset low (input) */
297 0x99, 0x00, /* voffset hi (input) */
298 0x9a, 0x12, /* vsize low (input), 0x12 = 18 */
299 0x9b, 0x00, /* vsize hi (input) */
300 0x9c, 0xa0, /* hsize low (output), 0x05a0 = 1440 */
301 0x9d, 0x05, /* hsize hi (output) */
302 0x9e, 0x12, /* vsize low (output), 0x12 = 18 */
303 0x9f, 0x00, /* vsize hi (output) */
304
305 /* Task B */
306 0xc0, 0x00, /* Task Handling Control */
307 0xc1, 0x08, /* X-port formats/config */
308 0xc2, 0x00, /* Input Ref. signal Def. */
309 0xc3, 0x80, /* I-port config */
310 0xc4, 0x00, /* hoffset low (input), 0x0002 is minimum. See comment at 0x94 above. */
311 0xc5, 0x00, /* hoffset hi (input) */
312 0xc6, 0xd0, /* hsize low (input), 0x02d0 = 720 */
313 0xc7, 0x02, /* hsize hi (input) */
314 0xc8, 0x16, /* voffset low (input), 0x16 = 22 */
315 0xc9, 0x00, /* voffset hi (input) */
316 0xca, 0x20, /* vsize low (input), 0x0120 = 288 */
317 0xcb, 0x01, /* vsize hi (input) */
318 0xcc, 0xd0, /* hsize low (output), 0x02d0 = 720 */
319 0xcd, 0x02, /* hsize hi (output) */
320 0xce, 0x20, /* vsize low (output), 0x0120 = 288 */
321 0xcf, 0x01, /* vsize hi (output) */
322
323 0xf0, 0xb0, /* Set PLL Register. 50hz 625 lines per frame, 27 MHz */
324 0xf1, 0x05, /* low bit with 0xF0, (was 0x05) */
325 0xf5, 0xb0, /* Set pulse generator register */
326 0xf6, 0x01,
327
328 0x87, 0x00, /* Disable I-port output */
329 0x88, 0xd0, /* reset scaler (was 0xD0) */
330 0x80, 0x20, /* Activate only task "B" */
331 0x88, 0xf0, /* activate scaler */
332 0x87, 0x01, /* Enable I-port output */
333 0x00, 0x00
334};
335
336/* ============== SAA7715 VIDEO templates (end) ======= */
337
338static const unsigned char saa7115_cfg_vbi_on[] = {
339 0x80, 0x00, /* reset tasks */
340 0x88, 0xd0, /* reset scaler */
341 0x80, 0x30, /* Activate both tasks */
342 0x88, 0xf0, /* activate scaler */
343 0x87, 0x01, /* Enable I-port output */
344 0x00, 0x00
345};
346
347static const unsigned char saa7115_cfg_vbi_off[] = {
348 0x80, 0x00, /* reset tasks */
349 0x88, 0xd0, /* reset scaler */
350 0x80, 0x20, /* Activate only task "B" */
351 0x88, 0xf0, /* activate scaler */
352 0x87, 0x01, /* Enable I-port output */
353 0x00, 0x00
354};
355
356static const unsigned char saa7115_init_misc[] = {
357 0x38, 0x03, /* audio stuff */
358 0x39, 0x10,
359 0x3a, 0x08,
360
361 0x81, 0x01, /* reg 0x15,0x16 define blanking window */
362 0x82, 0x00,
363 0x83, 0x01, /* I port settings */
364 0x84, 0x20,
365 0x85, 0x21,
366 0x86, 0xc5,
367 0x87, 0x01,
368
369 /* Task A */
370 0xa0, 0x01, /* down scale = 1 */
371 0xa1, 0x00, /* prescale accumulation length = 1 */
372 0xa2, 0x00, /* dc gain and fir prefilter control */
373 0xa4, 0x80, /* Lum Brightness, nominal value = 0x80 */
374 0xa5, 0x40, /* Lum contrast, nominal value = 0x40 */
375 0xa6, 0x40, /* Chroma satur. nominal value = 0x80 */
376 0xa8, 0x00, /* hor lum scaling 0x0200 = 2 zoom */
377 0xa9, 0x02, /* note: 2 x zoom ensures that VBI lines have same length as video lines. */
378 0xaa, 0x00, /* H-phase offset Luma = 0 */
379 0xac, 0x00, /* hor chrom scaling 0x0200. must be hor lum scaling / 2 */
380 0xad, 0x01, /* H-scaling incr chroma */
381 0xae, 0x00, /* H-phase offset chroma. must be offset luma / 2 */
382
383 0xb0, 0x00, /* V-scaling incr luma low */
384 0xb1, 0x04, /* " hi */
385 0xb2, 0x00, /* V-scaling incr chroma low */
386 0xb3, 0x04, /* " hi */
387 0xb4, 0x01, /* V-scaling mode control */
388 0xb8, 0x00, /* V-phase offset chroma 00 */
389 0xb9, 0x00, /* V-phase offset chroma 01 */
390 0xba, 0x00, /* V-phase offset chroma 10 */
391 0xbb, 0x00, /* V-phase offset chroma 11 */
392 0xbc, 0x00, /* V-phase offset luma 00 */
393 0xbd, 0x00, /* V-phase offset luma 01 */
394 0xbe, 0x00, /* V-phase offset luma 10 */
395 0xbf, 0x00, /* V-phase offset luma 11 */
396
397 /* Task B */
398 0xd0, 0x01, /* down scale = 1 */
399 0xd1, 0x00, /* prescale accumulation length = 1 */
400 0xd2, 0x00, /* dc gain and fir prefilter control */
401 0xd4, 0x80, /* Lum Brightness, nominal value = 0x80 */
402 0xd5, 0x40, /* Lum contrast, nominal value = 0x40 */
403 0xd6, 0x40, /* Chroma satur. nominal value = 0x80 */
404 0xd8, 0x00, /* hor lum scaling 0x0400 = 1 */
405 0xd9, 0x04,
406 0xda, 0x00, /* H-phase offset Luma = 0 */
407 0xdc, 0x00, /* hor chrom scaling 0x0200. must be hor lum scaling / 2 */
408 0xdd, 0x02, /* H-scaling incr chroma */
409 0xde, 0x00, /* H-phase offset chroma. must be offset luma / 2 */
410
411 0xe0, 0x00, /* V-scaling incr luma low */
412 0xe1, 0x04, /* " hi */
413 0xe2, 0x00, /* V-scaling incr chroma low */
414 0xe3, 0x04, /* " hi */
415 0xe4, 0x01, /* V-scaling mode control */
416 0xe8, 0x00, /* V-phase offset chroma 00 */
417 0xe9, 0x00, /* V-phase offset chroma 01 */
418 0xea, 0x00, /* V-phase offset chroma 10 */
419 0xeb, 0x00, /* V-phase offset chroma 11 */
420 0xec, 0x00, /* V-phase offset luma 00 */
421 0xed, 0x00, /* V-phase offset luma 01 */
422 0xee, 0x00, /* V-phase offset luma 10 */
423 0xef, 0x00, /* V-phase offset luma 11 */
424
425 0xf2, 0x50, /* crystal clock = 24.576 MHz, target = 27MHz */
426 0xf3, 0x46,
427 0xf4, 0x00,
428 0xf7, 0x4b, /* not the recommended settings! */
429 0xf8, 0x00,
430 0xf9, 0x4b,
431 0xfa, 0x00,
432 0xfb, 0x4b,
433 0xff, 0x88, /* PLL2 lock detection settings: 71 lines 50% phase error */
434
435 /* Turn off VBI */
436 0x40, 0x20, /* No framing code errors allowed. */
437 0x41, 0xff,
438 0x42, 0xff,
439 0x43, 0xff,
440 0x44, 0xff,
441 0x45, 0xff,
442 0x46, 0xff,
443 0x47, 0xff,
444 0x48, 0xff,
445 0x49, 0xff,
446 0x4a, 0xff,
447 0x4b, 0xff,
448 0x4c, 0xff,
449 0x4d, 0xff,
450 0x4e, 0xff,
451 0x4f, 0xff,
452 0x50, 0xff,
453 0x51, 0xff,
454 0x52, 0xff,
455 0x53, 0xff,
456 0x54, 0xff,
457 0x55, 0xff,
458 0x56, 0xff,
459 0x57, 0xff,
460 0x58, 0x40,
461 0x59, 0x47,
462 0x5b, 0x83,
463 0x5d, 0xbd,
464 0x5e, 0x35,
465
466 0x02, 0x84, /* input tuner -> input 4, amplifier active */
467 0x09, 0x53, /* 0x53, was 0x56 for 60hz. luminance control */
468
469 0x80, 0x20, /* enable task B */
470 0x88, 0xd0,
471 0x88, 0xf0,
472 0x00, 0x00
473};
474
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800475static int saa7115_odd_parity(u8 c)
476{
477 c ^= (c >> 4);
478 c ^= (c >> 2);
479 c ^= (c >> 1);
480
481 return c & 1;
482}
483
484static int saa7115_decode_vps(u8 * dst, u8 * p)
485{
486 static const u8 biphase_tbl[] = {
487 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
488 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
489 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96,
490 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2,
491 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94,
492 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0,
493 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
494 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
495 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5,
496 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1,
497 0xc3, 0x4b, 0x43, 0xc3, 0x87, 0x0f, 0x07, 0x87,
498 0x83, 0x0b, 0x03, 0x83, 0xc3, 0x4b, 0x43, 0xc3,
499 0xc1, 0x49, 0x41, 0xc1, 0x85, 0x0d, 0x05, 0x85,
500 0x81, 0x09, 0x01, 0x81, 0xc1, 0x49, 0x41, 0xc1,
501 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5,
502 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1,
503 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4,
504 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0,
505 0xc2, 0x4a, 0x42, 0xc2, 0x86, 0x0e, 0x06, 0x86,
506 0x82, 0x0a, 0x02, 0x82, 0xc2, 0x4a, 0x42, 0xc2,
507 0xc0, 0x48, 0x40, 0xc0, 0x84, 0x0c, 0x04, 0x84,
508 0x80, 0x08, 0x00, 0x80, 0xc0, 0x48, 0x40, 0xc0,
509 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4,
510 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0,
511 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
512 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
513 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96,
514 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2,
515 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94,
516 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0,
517 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
518 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
519 };
520 int i;
521 u8 c, err = 0;
522
523 for (i = 0; i < 2 * 13; i += 2) {
524 err |= biphase_tbl[p[i]] | biphase_tbl[p[i + 1]];
525 c = (biphase_tbl[p[i + 1]] & 0xf) | ((biphase_tbl[p[i]] & 0xf) << 4);
526 dst[i / 2] = c;
527 }
528 return err & 0xf0;
529}
530
531static int saa7115_decode_wss(u8 * p)
532{
533 static const int wss_bits[8] = {
534 0, 0, 0, 1, 0, 1, 1, 1
535 };
536 unsigned char parity;
537 int wss = 0;
538 int i;
539
540 for (i = 0; i < 16; i++) {
541 int b1 = wss_bits[p[i] & 7];
542 int b2 = wss_bits[(p[i] >> 3) & 7];
543
544 if (b1 == b2)
545 return -1;
546 wss |= b2 << i;
547 }
548 parity = wss & 15;
549 parity ^= parity >> 2;
550 parity ^= parity >> 1;
551
552 if (!(parity & 1))
553 return -1;
554
555 return wss;
556}
557
558
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200559static int saa7115_set_audio_clock_freq(struct i2c_client *client, u32 freq)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800560{
561 struct saa7115_state *state = i2c_get_clientdata(client);
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200562 u32 acpf;
563 u32 acni;
564 u32 hz;
565 u64 f;
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800566
567 saa7115_dbg("set audio clock freq: %d\n", freq);
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200568
569 /* sanity check */
570 if (freq < 32000 || freq > 48000)
571 return -EINVAL;
572
573 /* hz is the refresh rate times 100 */
574 hz = (state->std & V4L2_STD_525_60) ? 5994 : 5000;
575 /* acpf = (256 * freq) / field_frequency == (256 * 100 * freq) / hz */
576 acpf = (25600 * freq) / hz;
577 /* acni = (256 * freq * 2^23) / crystal_frequency =
578 (freq * 2^(8+23)) / crystal_frequency =
579 (freq << 31) / 32.11 MHz */
580 f = freq;
581 f = f << 31;
582 do_div(f, 32110000);
583 acni = f;
584
585 saa7115_write(client, 0x30, acpf & 0xff);
586 saa7115_write(client, 0x31, (acpf >> 8) & 0xff);
587 saa7115_write(client, 0x32, (acpf >> 16) & 0x03);
588 saa7115_write(client, 0x34, acni & 0xff);
589 saa7115_write(client, 0x35, (acni >> 8) & 0xff);
590 saa7115_write(client, 0x36, (acni >> 16) & 0x3f);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800591 state->audclk_freq = freq;
592 return 0;
593}
594
595static int saa7115_set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
596{
597 struct saa7115_state *state = i2c_get_clientdata(client);
598
599 switch (ctrl->id) {
600 case V4L2_CID_BRIGHTNESS:
601 if (ctrl->value < 0 || ctrl->value > 255) {
602 saa7115_err("invalid brightness setting %d\n", ctrl->value);
603 return -ERANGE;
604 }
605
606 state->bright = ctrl->value;
607 saa7115_write(client, 0x0a, state->bright);
608 break;
609
610 case V4L2_CID_CONTRAST:
611 if (ctrl->value < 0 || ctrl->value > 127) {
612 saa7115_err("invalid contrast setting %d\n", ctrl->value);
613 return -ERANGE;
614 }
615
616 state->contrast = ctrl->value;
617 saa7115_write(client, 0x0b, state->contrast);
618 break;
619
620 case V4L2_CID_SATURATION:
621 if (ctrl->value < 0 || ctrl->value > 127) {
622 saa7115_err("invalid saturation setting %d\n", ctrl->value);
623 return -ERANGE;
624 }
625
626 state->sat = ctrl->value;
627 saa7115_write(client, 0x0c, state->sat);
628 break;
629
630 case V4L2_CID_HUE:
631 if (ctrl->value < -127 || ctrl->value > 127) {
632 saa7115_err("invalid hue setting %d\n", ctrl->value);
633 return -ERANGE;
634 }
635
636 state->hue = ctrl->value;
637 saa7115_write(client, 0x0d, state->hue);
638 break;
Hans Verkuil3faeeae2006-01-09 15:25:44 -0200639
640 default:
641 return -EINVAL;
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800642 }
643
644 return 0;
645}
646
647static int saa7115_get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
648{
649 struct saa7115_state *state = i2c_get_clientdata(client);
650
651 switch (ctrl->id) {
652 case V4L2_CID_BRIGHTNESS:
653 ctrl->value = state->bright;
654 break;
655 case V4L2_CID_CONTRAST:
656 ctrl->value = state->contrast;
657 break;
658 case V4L2_CID_SATURATION:
659 ctrl->value = state->sat;
660 break;
661 case V4L2_CID_HUE:
662 ctrl->value = state->hue;
663 break;
664 default:
665 return -EINVAL;
666 }
667
668 return 0;
669}
670
671static void saa7115_set_v4lstd(struct i2c_client *client, v4l2_std_id std)
672{
673 struct saa7115_state *state = i2c_get_clientdata(client);
674 int taskb = saa7115_read(client, 0x80) & 0x10;
675
Hans Verkuil30b54d52006-01-09 15:25:43 -0200676 /* Prevent unnecessary standard changes. During a standard
677 change the I-Port is temporarily disabled. Any devices
678 reading from that port can get confused.
679 Note that VIDIOC_S_STD is also used to switch from
680 radio to TV mode, so if a VIDIOC_S_STD is broadcast to
681 all I2C devices then you do not want to have an unwanted
682 side-effect here. */
683 if (std == state->std)
684 return;
685
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800686 // This works for NTSC-M, SECAM-L and the 50Hz PAL variants.
687 if (std & V4L2_STD_525_60) {
688 saa7115_dbg("decoder set standard 60 Hz\n");
689 saa7115_writeregs(client, saa7115_cfg_60hz_video);
690 } else {
691 saa7115_dbg("decoder set standard 50 Hz\n");
692 saa7115_writeregs(client, saa7115_cfg_50hz_video);
693 }
694
695 state->std = std;
696
697 /* restart task B if needed */
698 if (taskb && state->ident == V4L2_IDENT_SAA7114) {
699 saa7115_writeregs(client, saa7115_cfg_vbi_on);
700 }
701
702 /* switch audio mode too! */
703 saa7115_set_audio_clock_freq(client, state->audclk_freq);
704}
705
706static v4l2_std_id saa7115_get_v4lstd(struct i2c_client *client)
707{
708 struct saa7115_state *state = i2c_get_clientdata(client);
709
710 return state->std;
711}
712
713static void saa7115_log_status(struct i2c_client *client)
714{
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800715 struct saa7115_state *state = i2c_get_clientdata(client);
716 int reg1e, reg1f;
717 int signalOk;
718 int vcr;
719
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200720 saa7115_info("Audio frequency: %d Hz\n", state->audclk_freq);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800721 if (client->name[6] == '4') {
722 /* status for the saa7114 */
723 reg1f = saa7115_read(client, 0x1f);
724 signalOk = (reg1f & 0xc1) == 0x81;
725 saa7115_info("Video signal: %s\n", signalOk ? "ok" : "bad");
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200726 saa7115_info("Frequency: %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz");
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800727 return;
728 }
729
730 /* status for the saa7115 */
731 reg1e = saa7115_read(client, 0x1e);
732 reg1f = saa7115_read(client, 0x1f);
733
734 signalOk = (reg1f & 0xc1) == 0x81 && (reg1e & 0xc0) == 0x80;
735 vcr = !(reg1f & 0x10);
736
Hans Verkuil21fa7152006-01-09 15:25:41 -0200737 if (state->input >= 6) {
738 saa7115_info("Input: S-Video %d\n", state->input - 6);
739 } else {
740 saa7115_info("Input: Composite %d\n", state->input);
741 }
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800742 saa7115_info("Video signal: %s\n", signalOk ? (vcr ? "VCR" : "broadcast/DVD") : "bad");
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200743 saa7115_info("Frequency: %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz");
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800744
745 switch (reg1e & 0x03) {
746 case 1:
747 saa7115_info("Detected format: NTSC\n");
748 break;
749 case 2:
750 saa7115_info("Detected format: PAL\n");
751 break;
752 case 3:
753 saa7115_info("Detected format: SECAM\n");
754 break;
755 default:
756 saa7115_info("Detected format: BW/No color\n");
757 break;
758 }
759}
760
761/* setup the sliced VBI lcr registers according to the sliced VBI format */
762static void saa7115_set_lcr(struct i2c_client *client, struct v4l2_sliced_vbi_format *fmt)
763{
764 struct saa7115_state *state = i2c_get_clientdata(client);
765 int is_50hz = (state->std & V4L2_STD_625_50);
766 u8 lcr[24];
767 int i, x;
768
769 /* saa7114 doesn't yet support VBI */
770 if (state->ident == V4L2_IDENT_SAA7114)
771 return;
772
773 for (i = 0; i <= 23; i++)
774 lcr[i] = 0xff;
775
776 if (fmt->service_set == 0) {
777 /* raw VBI */
778 if (is_50hz)
779 for (i = 6; i <= 23; i++)
780 lcr[i] = 0xdd;
781 else
782 for (i = 10; i <= 21; i++)
783 lcr[i] = 0xdd;
784 } else {
785 /* sliced VBI */
786 /* first clear lines that cannot be captured */
787 if (is_50hz) {
788 for (i = 0; i <= 5; i++)
789 fmt->service_lines[0][i] =
790 fmt->service_lines[1][i] = 0;
791 }
792 else {
793 for (i = 0; i <= 9; i++)
794 fmt->service_lines[0][i] =
795 fmt->service_lines[1][i] = 0;
796 for (i = 22; i <= 23; i++)
797 fmt->service_lines[0][i] =
798 fmt->service_lines[1][i] = 0;
799 }
800
801 /* Now set the lcr values according to the specified service */
802 for (i = 6; i <= 23; i++) {
803 lcr[i] = 0;
804 for (x = 0; x <= 1; x++) {
805 switch (fmt->service_lines[1-x][i]) {
806 case 0:
807 lcr[i] |= 0xf << (4 * x);
808 break;
809 case V4L2_SLICED_TELETEXT_B:
810 lcr[i] |= 1 << (4 * x);
811 break;
812 case V4L2_SLICED_CAPTION_525:
813 lcr[i] |= 4 << (4 * x);
814 break;
815 case V4L2_SLICED_WSS_625:
816 lcr[i] |= 5 << (4 * x);
817 break;
818 case V4L2_SLICED_VPS:
819 lcr[i] |= 7 << (4 * x);
820 break;
821 }
822 }
823 }
824 }
825
826 /* write the lcr registers */
827 for (i = 2; i <= 23; i++) {
828 saa7115_write(client, i - 2 + 0x41, lcr[i]);
829 }
830
831 /* enable/disable raw VBI capturing */
832 saa7115_writeregs(client, fmt->service_set == 0 ? saa7115_cfg_vbi_on : saa7115_cfg_vbi_off);
833}
834
835static int saa7115_get_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
836{
837 static u16 lcr2vbi[] = {
838 0, V4L2_SLICED_TELETEXT_B, 0, /* 1 */
839 0, V4L2_SLICED_CAPTION_525, /* 4 */
840 V4L2_SLICED_WSS_625, 0, /* 5 */
841 V4L2_SLICED_VPS, 0, 0, 0, 0, /* 7 */
842 0, 0, 0, 0
843 };
844 struct v4l2_sliced_vbi_format *sliced = &fmt->fmt.sliced;
845 int i;
846
847 if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
848 return -EINVAL;
849 memset(sliced, 0, sizeof(*sliced));
850 /* done if using raw VBI */
851 if (saa7115_read(client, 0x80) & 0x10)
852 return 0;
853 for (i = 2; i <= 23; i++) {
854 u8 v = saa7115_read(client, i - 2 + 0x41);
855
856 sliced->service_lines[0][i] = lcr2vbi[v >> 4];
857 sliced->service_lines[1][i] = lcr2vbi[v & 0xf];
858 sliced->service_set |=
859 sliced->service_lines[0][i] | sliced->service_lines[1][i];
860 }
861 return 0;
862}
863
864static int saa7115_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
865{
866 struct saa7115_state *state = i2c_get_clientdata(client);
867 struct v4l2_pix_format *pix;
868 int HPSC, HFSC;
869 int VSCY, Vsrc;
870 int is_50hz = state->std & V4L2_STD_625_50;
871
872 if (fmt->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
873 saa7115_set_lcr(client, &fmt->fmt.sliced);
874 return 0;
875 }
876 if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
877 return -EINVAL;
878
879 pix = &(fmt->fmt.pix);
880
881 saa7115_dbg("decoder set size\n");
882
883 /* FIXME need better bounds checking here */
884 if ((pix->width < 1) || (pix->width > 1440))
885 return -EINVAL;
886 if ((pix->height < 1) || (pix->height > 960))
887 return -EINVAL;
888
889 /* probably have a valid size, let's set it */
890 /* Set output width/height */
891 /* width */
892 saa7115_write(client, 0xcc, (u8) (pix->width & 0xff));
893 saa7115_write(client, 0xcd, (u8) ((pix->width >> 8) & 0xff));
894 /* height */
895 saa7115_write(client, 0xce, (u8) (pix->height & 0xff));
896 saa7115_write(client, 0xcf, (u8) ((pix->height >> 8) & 0xff));
897
898 /* Scaling settings */
899 /* Hprescaler is floor(inres/outres) */
900 /* FIXME hardcoding input res */
901 if (pix->width != 720) {
902 HPSC = (int)(720 / pix->width);
903 /* 0 is not allowed (div. by zero) */
904 HPSC = HPSC ? HPSC : 1;
905 HFSC = (int)((1024 * 720) / (HPSC * pix->width));
906
907 saa7115_dbg("Hpsc: 0x%05x, Hfsc: 0x%05x\n", HPSC, HFSC);
908 /* FIXME hardcodes to "Task B"
909 * write H prescaler integer */
910 saa7115_write(client, 0xd0, (u8) (HPSC & 0x3f));
911
912 /* write H fine-scaling (luminance) */
913 saa7115_write(client, 0xd8, (u8) (HFSC & 0xff));
914 saa7115_write(client, 0xd9, (u8) ((HFSC >> 8) & 0xff));
915 /* write H fine-scaling (chrominance)
916 * must be lum/2, so i'll just bitshift :) */
917 saa7115_write(client, 0xDC, (u8) ((HFSC >> 1) & 0xff));
918 saa7115_write(client, 0xDD, (u8) ((HFSC >> 9) & 0xff));
919 } else {
920 if (is_50hz) {
921 saa7115_dbg("Setting full 50hz width\n");
922 saa7115_writeregs(client, saa7115_cfg_50hz_fullres_x);
923 } else {
924 saa7115_dbg("Setting full 60hz width\n");
925 saa7115_writeregs(client, saa7115_cfg_60hz_fullres_x);
926 }
927 }
928
929 Vsrc = is_50hz ? 576 : 480;
930
931 if (pix->height != Vsrc) {
932 VSCY = (int)((1024 * Vsrc) / pix->height);
933 saa7115_dbg("Vsrc: %d, Vscy: 0x%05x\n", Vsrc, VSCY);
934
935 /* Correct Contrast and Luminance */
936 saa7115_write(client, 0xd5, (u8) (64 * 1024 / VSCY));
937 saa7115_write(client, 0xd6, (u8) (64 * 1024 / VSCY));
938
939 /* write V fine-scaling (luminance) */
940 saa7115_write(client, 0xe0, (u8) (VSCY & 0xff));
941 saa7115_write(client, 0xe1, (u8) ((VSCY >> 8) & 0xff));
942 /* write V fine-scaling (chrominance) */
943 saa7115_write(client, 0xe2, (u8) (VSCY & 0xff));
944 saa7115_write(client, 0xe3, (u8) ((VSCY >> 8) & 0xff));
945 } else {
946 if (is_50hz) {
947 saa7115_dbg("Setting full 50Hz height\n");
948 saa7115_writeregs(client, saa7115_cfg_50hz_fullres_y);
949 } else {
950 saa7115_dbg("Setting full 60hz height\n");
951 saa7115_writeregs(client, saa7115_cfg_60hz_fullres_y);
952 }
953 }
954
955 saa7115_writeregs(client, saa7115_cfg_reset_scaler);
956 return 0;
957}
958
959/* Decode the sliced VBI data stream as created by the saa7115.
960 The format is described in the saa7115 datasheet in Tables 25 and 26
961 and in Figure 33.
962 The current implementation uses SAV/EAV codes and not the ancillary data
963 headers. The vbi->p pointer points to the SDID byte right after the SAV
964 code. */
965static void saa7115_decode_vbi_line(struct i2c_client *client,
966 struct v4l2_decode_vbi_line *vbi)
967{
968 static const char vbi_no_data_pattern[] = {
969 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0
970 };
971 struct saa7115_state *state = i2c_get_clientdata(client);
972 u8 *p = vbi->p;
973 u32 wss;
974 int id1, id2; /* the ID1 and ID2 bytes from the internal header */
975
976 vbi->type = 0; /* mark result as a failure */
977 id1 = p[2];
978 id2 = p[3];
979 /* Note: the field bit is inverted for 60 Hz video */
980 if (state->std & V4L2_STD_525_60)
981 id1 ^= 0x40;
982
983 /* Skip internal header, p now points to the start of the payload */
984 p += 4;
985 vbi->p = p;
986
987 /* calculate field and line number of the VBI packet (1-23) */
988 vbi->is_second_field = ((id1 & 0x40) != 0);
989 vbi->line = (id1 & 0x3f) << 3;
990 vbi->line |= (id2 & 0x70) >> 4;
991
992 /* Obtain data type */
993 id2 &= 0xf;
994
995 /* If the VBI slicer does not detect any signal it will fill up
996 the payload buffer with 0xa0 bytes. */
997 if (!memcmp(p, vbi_no_data_pattern, sizeof(vbi_no_data_pattern)))
998 return;
999
1000 /* decode payloads */
1001 switch (id2) {
1002 case 1:
1003 vbi->type = V4L2_SLICED_TELETEXT_B;
1004 break;
1005 case 4:
1006 if (!saa7115_odd_parity(p[0]) || !saa7115_odd_parity(p[1]))
1007 return;
1008 vbi->type = V4L2_SLICED_CAPTION_525;
1009 break;
1010 case 5:
1011 wss = saa7115_decode_wss(p);
1012 if (wss == -1)
1013 return;
1014 p[0] = wss & 0xff;
1015 p[1] = wss >> 8;
1016 vbi->type = V4L2_SLICED_WSS_625;
1017 break;
1018 case 7:
1019 if (saa7115_decode_vps(p, p) != 0)
1020 return;
1021 vbi->type = V4L2_SLICED_VPS;
1022 break;
1023 default:
1024 return;
1025 }
1026}
1027
1028/* ============ SAA7115 AUDIO settings (end) ============= */
1029
1030static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *arg)
1031{
1032 struct saa7115_state *state = i2c_get_clientdata(client);
1033 int *iarg = arg;
1034
1035 /* ioctls to allow direct access to the saa7115 registers for testing */
1036 switch (cmd) {
1037 case VIDIOC_S_FMT:
1038 return saa7115_set_v4lfmt(client, (struct v4l2_format *)arg);
1039
1040 case VIDIOC_G_FMT:
1041 return saa7115_get_v4lfmt(client, (struct v4l2_format *)arg);
1042
1043 case VIDIOC_INT_AUDIO_CLOCK_FREQ:
Hans Verkuil3578d3d2006-01-09 15:25:41 -02001044 return saa7115_set_audio_clock_freq(client, *(u32 *)arg);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001045
1046 case VIDIOC_G_TUNER:
1047 {
1048 struct v4l2_tuner *vt = arg;
1049 int status;
1050
Hans Verkuil3faeeae2006-01-09 15:25:44 -02001051 if (state->radio)
1052 break;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001053 status = saa7115_read(client, 0x1f);
1054
1055 saa7115_dbg("status: 0x%02x\n", status);
1056 vt->signal = ((status & (1 << 6)) == 0) ? 0xffff : 0x0;
1057 break;
1058 }
1059
1060 case VIDIOC_LOG_STATUS:
1061 saa7115_log_status(client);
1062 break;
1063
1064 case VIDIOC_G_CTRL:
1065 return saa7115_get_v4lctrl(client, (struct v4l2_control *)arg);
1066
1067 case VIDIOC_S_CTRL:
1068 return saa7115_set_v4lctrl(client, (struct v4l2_control *)arg);
1069
1070 case VIDIOC_G_STD:
1071 *(v4l2_std_id *)arg = saa7115_get_v4lstd(client);
1072 break;
1073
1074 case VIDIOC_S_STD:
Hans Verkuil3faeeae2006-01-09 15:25:44 -02001075 state->radio = 0;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001076 saa7115_set_v4lstd(client, *(v4l2_std_id *)arg);
1077 break;
1078
Hans Verkuil3faeeae2006-01-09 15:25:44 -02001079 case AUDC_SET_RADIO:
1080 state->radio = 1;
1081 break;
1082
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001083 case VIDIOC_G_INPUT:
1084 *(int *)arg = state->input;
1085 break;
1086
1087 case VIDIOC_S_INPUT:
1088 saa7115_dbg("decoder set input %d\n", *iarg);
1089 /* inputs from 0-9 are available */
1090 if (*iarg < 0 || *iarg > 9) {
1091 return -EINVAL;
1092 }
1093
1094 if (state->input == *iarg)
1095 break;
1096 saa7115_dbg("now setting %s input\n",
1097 *iarg >= 6 ? "S-Video" : "Composite");
1098 state->input = *iarg;
1099
1100 /* select mode */
1101 saa7115_write(client, 0x02,
1102 (saa7115_read(client, 0x02) & 0xf0) |
1103 state->input);
1104
1105 /* bypass chrominance trap for modes 6..9 */
1106 saa7115_write(client, 0x09,
1107 (saa7115_read(client, 0x09) & 0x7f) |
1108 (state->input < 6 ? 0x0 : 0x80));
1109 break;
1110
1111 case VIDIOC_STREAMON:
1112 case VIDIOC_STREAMOFF:
1113 saa7115_dbg("%s output\n",
1114 (cmd == VIDIOC_STREAMON) ? "enable" : "disable");
1115
1116 if (state->enable != (cmd == VIDIOC_STREAMON)) {
1117 state->enable = (cmd == VIDIOC_STREAMON);
1118 saa7115_write(client, 0x87, state->enable);
1119 }
1120 break;
1121
1122 case VIDIOC_INT_DECODE_VBI_LINE:
1123 saa7115_decode_vbi_line(client, arg);
1124 break;
1125
1126 case VIDIOC_INT_RESET:
1127 saa7115_dbg("decoder RESET\n");
1128 saa7115_writeregs(client, saa7115_cfg_reset_scaler);
1129 break;
1130
1131 case VIDIOC_INT_G_VBI_DATA:
1132 {
1133 struct v4l2_sliced_vbi_data *data = arg;
1134
1135 switch (data->id) {
1136 case V4L2_SLICED_WSS_625:
1137 if (saa7115_read(client, 0x6b) & 0xc0)
1138 return -EIO;
1139 data->data[0] = saa7115_read(client, 0x6c);
1140 data->data[1] = saa7115_read(client, 0x6d);
1141 return 0;
1142 case V4L2_SLICED_CAPTION_525:
1143 if (data->field == 0) {
1144 /* CC */
1145 if (saa7115_read(client, 0x66) & 0xc0)
1146 return -EIO;
1147 data->data[0] = saa7115_read(client, 0x67);
1148 data->data[1] = saa7115_read(client, 0x68);
1149 return 0;
1150 }
1151 /* XDS */
1152 if (saa7115_read(client, 0x66) & 0x30)
1153 return -EIO;
1154 data->data[0] = saa7115_read(client, 0x69);
1155 data->data[1] = saa7115_read(client, 0x6a);
1156 return 0;
1157 default:
1158 return -EINVAL;
1159 }
1160 break;
1161 }
1162
1163#ifdef CONFIG_VIDEO_ADV_DEBUG
1164 case VIDIOC_INT_G_REGISTER:
1165 {
1166 struct v4l2_register *reg = arg;
1167
1168 if (reg->i2c_id != I2C_DRIVERID_SAA711X)
1169 return -EINVAL;
1170 reg->val = saa7115_read(client, reg->reg & 0xff);
1171 break;
1172 }
1173
1174 case VIDIOC_INT_S_REGISTER:
1175 {
1176 struct v4l2_register *reg = arg;
1177
1178 if (reg->i2c_id != I2C_DRIVERID_SAA711X)
1179 return -EINVAL;
1180 if (!capable(CAP_SYS_ADMIN))
1181 return -EPERM;
1182 saa7115_write(client, reg->reg & 0xff, reg->val & 0xff);
1183 break;
1184 }
1185#endif
1186
1187 case VIDIOC_INT_G_CHIP_IDENT:
1188 *iarg = state->ident;
1189 break;
1190
1191 default:
1192 return -EINVAL;
1193 }
1194
1195 return 0;
1196}
1197
1198/* ----------------------------------------------------------------------- */
1199
1200static struct i2c_driver i2c_driver_saa7115;
1201
1202static int saa7115_attach(struct i2c_adapter *adapter, int address, int kind)
1203{
1204 struct i2c_client *client;
1205 struct saa7115_state *state;
1206 u8 chip_id;
1207
1208 /* Check if the adapter supports the needed features */
1209 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
1210 return 0;
1211
1212 client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
1213 if (client == 0)
1214 return -ENOMEM;
1215 memset(client, 0, sizeof(struct i2c_client));
1216 client->addr = address;
1217 client->adapter = adapter;
1218 client->driver = &i2c_driver_saa7115;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001219 snprintf(client->name, sizeof(client->name) - 1, "saa7115");
1220
1221 saa7115_dbg("detecting saa7115 client on address 0x%x\n", address << 1);
1222
1223 saa7115_write(client, 0, 5);
1224 chip_id = saa7115_read(client, 0) & 0x0f;
1225 if (chip_id != 4 && chip_id != 5) {
1226 saa7115_dbg("saa7115 not found\n");
1227 kfree(client);
1228 return 0;
1229 }
1230 if (chip_id == 4) {
1231 snprintf(client->name, sizeof(client->name) - 1, "saa7114");
1232 }
1233 saa7115_info("saa711%d found @ 0x%x (%s)\n", chip_id, address << 1, adapter->name);
1234
1235 state = kmalloc(sizeof(struct saa7115_state), GFP_KERNEL);
1236 i2c_set_clientdata(client, state);
1237 if (state == NULL) {
1238 kfree(client);
1239 return -ENOMEM;
1240 }
1241 memset(state, 0, sizeof(struct saa7115_state));
1242 state->std = V4L2_STD_NTSC;
1243 state->input = -1;
1244 state->enable = 1;
Hans Verkuil3faeeae2006-01-09 15:25:44 -02001245 state->radio = 0;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001246 state->bright = 128;
1247 state->contrast = 64;
1248 state->hue = 0;
1249 state->sat = 64;
1250 state->ident = (chip_id == 4) ? V4L2_IDENT_SAA7114 : V4L2_IDENT_SAA7115;
Hans Verkuil3578d3d2006-01-09 15:25:41 -02001251 state->audclk_freq = 48000;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001252
1253 saa7115_dbg("writing init values\n");
1254
1255 /* init to 60hz/48khz */
1256 saa7115_writeregs(client, saa7115_init_auto_input);
1257 saa7115_writeregs(client, saa7115_init_misc);
1258 saa7115_writeregs(client, saa7115_cfg_60hz_fullres_x);
1259 saa7115_writeregs(client, saa7115_cfg_60hz_fullres_y);
1260 saa7115_writeregs(client, saa7115_cfg_60hz_video);
Hans Verkuil3578d3d2006-01-09 15:25:41 -02001261 saa7115_set_audio_clock_freq(client, state->audclk_freq);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001262 saa7115_writeregs(client, saa7115_cfg_reset_scaler);
1263
1264 i2c_attach_client(client);
1265
1266 saa7115_dbg("status: (1E) 0x%02x, (1F) 0x%02x\n",
1267 saa7115_read(client, 0x1e), saa7115_read(client, 0x1f));
1268
1269 return 0;
1270}
1271
1272static int saa7115_probe(struct i2c_adapter *adapter)
1273{
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001274 if (adapter->class & I2C_CLASS_TV_ANALOG)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001275 return i2c_probe(adapter, &addr_data, &saa7115_attach);
1276 return 0;
1277}
1278
1279static int saa7115_detach(struct i2c_client *client)
1280{
1281 struct saa7115_state *state = i2c_get_clientdata(client);
1282 int err;
1283
1284 err = i2c_detach_client(client);
1285 if (err) {
1286 return err;
1287 }
1288
1289 kfree(state);
1290 kfree(client);
1291 return 0;
1292}
1293
1294/* ----------------------------------------------------------------------- */
1295
1296/* i2c implementation */
1297static struct i2c_driver i2c_driver_saa7115 = {
Laurent Riffard604f28e2005-11-26 20:43:39 +01001298 .driver = {
Laurent Riffard604f28e2005-11-26 20:43:39 +01001299 .name = "saa7115",
1300 },
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001301 .id = I2C_DRIVERID_SAA711X,
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001302 .attach_adapter = saa7115_probe,
1303 .detach_client = saa7115_detach,
1304 .command = saa7115_command,
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001305};
1306
1307
1308static int __init saa7115_init_module(void)
1309{
1310 return i2c_add_driver(&i2c_driver_saa7115);
1311}
1312
1313static void __exit saa7115_cleanup_module(void)
1314{
1315 i2c_del_driver(&i2c_driver_saa7115);
1316}
1317
1318module_init(saa7115_init_module);
1319module_exit(saa7115_cleanup_module);