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