aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media
diff options
context:
space:
mode:
authorHans Verkuil <hverkuil@xs4all.nl>2005-11-13 19:07:53 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2005-11-13 21:14:18 -0500
commitcfbb5b8cb059609696ba38a9a87eafb93b3de43c (patch)
treeaaabafd0fb2f08714a7fb0393c8d7290b39498f9 /drivers/media
parent6c6c0b2c27e70c3593e023882fabb1cebcbd077e (diff)
[PATCH] v4l: (944) added driver for saa7127 video decoder
- Added driver for saa7127 video decoder. Driver authors:Hans Verkuil, Chris Kennedy, Kevin Thayer Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Chris Kennedy <c@groovy.org> Signed-off-by: Kevin Thayer <nufan_wfk@yahoo.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@brturbo.com.br> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/media')
-rw-r--r--drivers/media/video/saa7127.c852
1 files changed, 852 insertions, 0 deletions
diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c
new file mode 100644
index 000000000000..2e8b6f2c6e34
--- /dev/null
+++ b/drivers/media/video/saa7127.c
@@ -0,0 +1,852 @@
1/*
2 * saa7127 - Philips SAA7127/SAA7129 video encoder driver
3 *
4 * Copyright (C) 2003 Roy Bulter <rbulter@hetnet.nl>
5 *
6 * Based on SAA7126 video encoder driver by Gillem & Andreas Oberritter
7 *
8 * Copyright (C) 2000-2001 Gillem <htoa@gmx.net>
9 * Copyright (C) 2002 Andreas Oberritter <obi@saftware.de>
10 *
11 * Based on Stadis 4:2:2 MPEG-2 Decoder Driver by Nathan Laredo
12 *
13 * Copyright (C) 1999 Nathan Laredo <laredo@gnu.org>
14 *
15 * This driver is designed for the Hauppauge 250/350 Linux driver
16 * from the ivtv Project
17 *
18 * Copyright (C) 2003 Kevin Thayer <nufan_wfk@yahoo.com>
19 *
20 * Dual output support:
21 * Copyright (C) 2004 Eric Varsanyi
22 *
23 * NTSC Tuning and 7.5 IRE Setup
24 * Copyright (C) 2004 Chris Kennedy <c@groovy.org>
25 *
26 * VBI additions & cleanup:
27 * Copyright (C) 2004, 2005 Hans Verkuil <hverkuil@xs4all.nl>
28 *
29 * Note: the saa7126 is identical to the saa7127, and the saa7128 is
30 * identical to the saa7129, except that the saa7126 and saa7128 have
31 * macrovision anti-taping support. This driver will almost certainly
32 * work find for those chips, except of course for the missing anti-taping
33 * support.
34 *
35 * This program is free software; you can redistribute it and/or modify
36 * it under the terms of the GNU General Public License as published by
37 * the Free Software Foundation; either version 2 of the License, or
38 * (at your option) any later version.
39 *
40 * This program is distributed in the hope that it will be useful,
41 * but WITHOUT ANY WARRANTY; without even the implied warranty of
42 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
43 * GNU General Public License for more details.
44 *
45 * You should have received a copy of the GNU General Public License
46 * along with this program; if not, write to the Free Software
47 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
48 */
49
50
51#include <linux/kernel.h>
52#include <linux/module.h>
53#include <linux/slab.h>
54#include <linux/i2c.h>
55#include <linux/videodev2.h>
56#include <media/i2c-compat.h>
57#include <media/v4l2-common.h>
58
59static int debug = 0;
60static int test_image = 0;
61
62MODULE_DESCRIPTION("Philips SAA7127/9 video encoder driver");
63MODULE_AUTHOR("Kevin Thayer <nufan_wfk@yahoo.com>");
64MODULE_AUTHOR("Chris Kennedy <c@groovy.org>");
65MODULE_AUTHOR("Hans Verkuil <hverkuil@xs4all.nl>");
66MODULE_LICENSE("GPL");
67module_param(debug, int, 0644);
68module_param(test_image, int, 0644);
69MODULE_PARM_DESC(debug, "debug level (0-2)");
70MODULE_PARM_DESC(test_image, "test_image (0-1)");
71
72#define saa7127_dbg(fmt, arg...) \
73 do { \
74 if (debug >= 1) \
75 printk(KERN_INFO "%s debug %d-%04x: " fmt, client->driver->name, \
76 i2c_adapter_id(client->adapter), client->addr , ## arg); \
77 } while (0)
78
79/* High volume debug. Use with care. */
80#define saa7127_dbg_highvol(fmt, arg...) \
81 do { \
82 if (debug == 2) \
83 printk(KERN_INFO "%s debug %d-%04x: " fmt, client->driver->name, \
84 i2c_adapter_id(client->adapter), client->addr , ## arg); \
85 } while (0)
86
87#define saa7127_err(fmt, arg...) do { \
88 printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->name, \
89 i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
90#define saa7127_info(fmt, arg...) do { \
91 printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->name, \
92 i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
93
94static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END };
95
96
97I2C_CLIENT_INSMOD;
98
99/*
100 * SAA7127 registers
101 */
102
103#define SAA7127_REG_STATUS 0x00
104#define SAA7127_REG_WIDESCREEN_CONFIG 0x26
105#define SAA7127_REG_WIDESCREEN_ENABLE 0x27
106#define SAA7127_REG_BURST_START 0x28
107#define SAA7127_REG_BURST_END 0x29
108#define SAA7127_REG_COPYGEN_0 0x2a
109#define SAA7127_REG_COPYGEN_1 0x2b
110#define SAA7127_REG_COPYGEN_2 0x2c
111#define SAA7127_REG_OUTPUT_PORT_CONTROL 0x2d
112#define SAA7127_REG_GAIN_LUMINANCE_RGB 0x38
113#define SAA7127_REG_GAIN_COLORDIFF_RGB 0x39
114#define SAA7127_REG_INPUT_PORT_CONTROL_1 0x3a
115#define SAA7129_REG_FADE_KEY_COL2 0x4f
116#define SAA7127_REG_CHROMA_PHASE 0x5a
117#define SAA7127_REG_GAINU 0x5b
118#define SAA7127_REG_GAINV 0x5c
119#define SAA7127_REG_BLACK_LEVEL 0x5d
120#define SAA7127_REG_BLANKING_LEVEL 0x5e
121#define SAA7127_REG_VBI_BLANKING 0x5f
122#define SAA7127_REG_DAC_CONTROL 0x61
123#define SAA7127_REG_BURST_AMP 0x62
124#define SAA7127_REG_SUBC3 0x63
125#define SAA7127_REG_SUBC2 0x64
126#define SAA7127_REG_SUBC1 0x65
127#define SAA7127_REG_SUBC0 0x66
128#define SAA7127_REG_LINE_21_ODD_0 0x67
129#define SAA7127_REG_LINE_21_ODD_1 0x68
130#define SAA7127_REG_LINE_21_EVEN_0 0x69
131#define SAA7127_REG_LINE_21_EVEN_1 0x6a
132#define SAA7127_REG_RCV_PORT_CONTROL 0x6b
133#define SAA7127_REG_VTRIG 0x6c
134#define SAA7127_REG_HTRIG_HI 0x6d
135#define SAA7127_REG_MULTI 0x6e
136#define SAA7127_REG_CLOSED_CAPTION 0x6f
137#define SAA7127_REG_RCV2_OUTPUT_START 0x70
138#define SAA7127_REG_RCV2_OUTPUT_END 0x71
139#define SAA7127_REG_RCV2_OUTPUT_MSBS 0x72
140#define SAA7127_REG_TTX_REQUEST_H_START 0x73
141#define SAA7127_REG_TTX_REQUEST_H_DELAY_LENGTH 0x74
142#define SAA7127_REG_CSYNC_ADVANCE_VSYNC_SHIFT 0x75
143#define SAA7127_REG_TTX_ODD_REQ_VERT_START 0x76
144#define SAA7127_REG_TTX_ODD_REQ_VERT_END 0x77
145#define SAA7127_REG_TTX_EVEN_REQ_VERT_START 0x78
146#define SAA7127_REG_TTX_EVEN_REQ_VERT_END 0x79
147#define SAA7127_REG_FIRST_ACTIVE 0x7a
148#define SAA7127_REG_LAST_ACTIVE 0x7b
149#define SAA7127_REG_MSB_VERTICAL 0x7c
150#define SAA7127_REG_DISABLE_TTX_LINE_LO_0 0x7e
151#define SAA7127_REG_DISABLE_TTX_LINE_LO_1 0x7f
152
153/*
154 **********************************************************************
155 *
156 * Arrays with configuration parameters for the SAA7127
157 *
158 **********************************************************************
159 */
160
161struct i2c_reg_value {
162 unsigned char reg;
163 unsigned char value;
164};
165
166static const struct i2c_reg_value saa7129_init_config_extra[] = {
167 { SAA7127_REG_OUTPUT_PORT_CONTROL, 0x38 },
168 { SAA7127_REG_VTRIG, 0xfa },
169};
170
171static const struct i2c_reg_value saa7127_init_config_common[] = {
172 { SAA7127_REG_WIDESCREEN_CONFIG, 0x0d },
173 { SAA7127_REG_WIDESCREEN_ENABLE, 0x00 },
174 { SAA7127_REG_COPYGEN_0, 0x77 },
175 { SAA7127_REG_COPYGEN_1, 0x41 },
176 { SAA7127_REG_COPYGEN_2, 0x00 }, /* Macrovision enable/disable */
177 { SAA7127_REG_OUTPUT_PORT_CONTROL, 0x9e },
178 { SAA7127_REG_GAIN_LUMINANCE_RGB, 0x00 },
179 { SAA7127_REG_GAIN_COLORDIFF_RGB, 0x00 },
180 { SAA7127_REG_INPUT_PORT_CONTROL_1, 0x80 }, /* for color bars */
181 { SAA7127_REG_LINE_21_ODD_0, 0x77 },
182 { SAA7127_REG_LINE_21_ODD_1, 0x41 },
183 { SAA7127_REG_LINE_21_EVEN_0, 0x88 },
184 { SAA7127_REG_LINE_21_EVEN_1, 0x41 },
185 { SAA7127_REG_RCV_PORT_CONTROL, 0x12 },
186 { SAA7127_REG_VTRIG, 0xf9 },
187 { SAA7127_REG_HTRIG_HI, 0x00 },
188 { SAA7127_REG_RCV2_OUTPUT_START, 0x41 },
189 { SAA7127_REG_RCV2_OUTPUT_END, 0xc3 },
190 { SAA7127_REG_RCV2_OUTPUT_MSBS, 0x00 },
191 { SAA7127_REG_TTX_REQUEST_H_START, 0x3e },
192 { SAA7127_REG_TTX_REQUEST_H_DELAY_LENGTH, 0xb8 },
193 { SAA7127_REG_CSYNC_ADVANCE_VSYNC_SHIFT, 0x03 },
194 { SAA7127_REG_TTX_ODD_REQ_VERT_START, 0x15 },
195 { SAA7127_REG_TTX_ODD_REQ_VERT_END, 0x16 },
196 { SAA7127_REG_TTX_EVEN_REQ_VERT_START, 0x15 },
197 { SAA7127_REG_TTX_EVEN_REQ_VERT_END, 0x16 },
198 { SAA7127_REG_FIRST_ACTIVE, 0x1a },
199 { SAA7127_REG_LAST_ACTIVE, 0x01 },
200 { SAA7127_REG_MSB_VERTICAL, 0xc0 },
201 { SAA7127_REG_DISABLE_TTX_LINE_LO_0, 0x00 },
202 { SAA7127_REG_DISABLE_TTX_LINE_LO_1, 0x00 },
203 { 0, 0 }
204};
205
206#define SAA7127_60HZ_DAC_CONTROL 0x15
207static const struct i2c_reg_value saa7127_init_config_60hz[] = {
208 { SAA7127_REG_BURST_START, 0x19 },
209 /* BURST_END is also used as a chip ID in saa7127_detect_client */
210 { SAA7127_REG_BURST_END, 0x1d },
211 { SAA7127_REG_CHROMA_PHASE, 0xa3 },
212 { SAA7127_REG_GAINU, 0x98 },
213 { SAA7127_REG_GAINV, 0xd3 },
214 { SAA7127_REG_BLACK_LEVEL, 0x39 },
215 { SAA7127_REG_BLANKING_LEVEL, 0x2e },
216 { SAA7127_REG_VBI_BLANKING, 0x2e },
217 { SAA7127_REG_DAC_CONTROL, 0x15 },
218 { SAA7127_REG_BURST_AMP, 0x4d },
219 { SAA7127_REG_SUBC3, 0x1f },
220 { SAA7127_REG_SUBC2, 0x7c },
221 { SAA7127_REG_SUBC1, 0xf0 },
222 { SAA7127_REG_SUBC0, 0x21 },
223 { SAA7127_REG_MULTI, 0x90 },
224 { SAA7127_REG_CLOSED_CAPTION, 0x11 },
225 { 0, 0 }
226};
227
228#define SAA7127_50HZ_DAC_CONTROL 0x02
229struct i2c_reg_value saa7127_init_config_50hz[] = {
230 { SAA7127_REG_BURST_START, 0x21 },
231 /* BURST_END is also used as a chip ID in saa7127_detect_client */
232 { SAA7127_REG_BURST_END, 0x1d },
233 { SAA7127_REG_CHROMA_PHASE, 0x3f },
234 { SAA7127_REG_GAINU, 0x7d },
235 { SAA7127_REG_GAINV, 0xaf },
236 { SAA7127_REG_BLACK_LEVEL, 0x33 },
237 { SAA7127_REG_BLANKING_LEVEL, 0x35 },
238 { SAA7127_REG_VBI_BLANKING, 0x35 },
239 { SAA7127_REG_DAC_CONTROL, 0x02 },
240 { SAA7127_REG_BURST_AMP, 0x2f },
241 { SAA7127_REG_SUBC3, 0xcb },
242 { SAA7127_REG_SUBC2, 0x8a },
243 { SAA7127_REG_SUBC1, 0x09 },
244 { SAA7127_REG_SUBC0, 0x2a },
245 { SAA7127_REG_MULTI, 0xa0 },
246 { SAA7127_REG_CLOSED_CAPTION, 0x00 },
247 { 0, 0 }
248};
249
250/* Enumeration for the Supported input types */
251enum saa7127_input_type {
252 SAA7127_INPUT_TYPE_NORMAL,
253 SAA7127_INPUT_TYPE_TEST_IMAGE
254};
255
256/* Enumeration for the Supported Output signal types */
257enum saa7127_output_type {
258 SAA7127_OUTPUT_TYPE_BOTH,
259 SAA7127_OUTPUT_TYPE_COMPOSITE,
260 SAA7127_OUTPUT_TYPE_SVIDEO,
261 SAA7127_OUTPUT_TYPE_RGB,
262 SAA7127_OUTPUT_TYPE_YUV_C,
263 SAA7127_OUTPUT_TYPE_YUV_V
264};
265
266/*
267 **********************************************************************
268 *
269 * Encoder Struct, holds the configuration state of the encoder
270 *
271 **********************************************************************
272 */
273
274struct saa7127_state {
275 v4l2_std_id std;
276 enum v4l2_chip_ident ident;
277 enum saa7127_input_type input_type;
278 enum saa7127_output_type output_type;
279 int video_enable;
280 int wss_enable;
281 u16 wss_mode;
282 int cc_enable;
283 u16 cc_data;
284 int xds_enable;
285 u16 xds_data;
286 int vps_enable;
287 u8 vps_data[5];
288 u8 reg_2d;
289 u8 reg_3a;
290 u8 reg_3a_cb; /* colorbar bit */
291 u8 reg_61;
292};
293
294static const char * const output_strs[] =
295{
296 "S-Video + Composite",
297 "Composite",
298 "S-Video",
299 "RGB",
300 "YUV C",
301 "YUV V"
302};
303
304static const char * const wss_strs[] = {
305 "invalid",
306 "letterbox 14:9 center",
307 "letterbox 14:9 top",
308 "invalid",
309 "letterbox 16:9 top",
310 "invalid",
311 "invalid",
312 "16:9 full format anamorphic"
313 "4:3 full format",
314 "invalid",
315 "invalid",
316 "letterbox 16:9 center",
317 "invalid",
318 "letterbox >16:9 center",
319 "14:9 full format center",
320 "invalid",
321};
322
323/* ----------------------------------------------------------------------- */
324
325static int saa7127_read(struct i2c_client *client, u8 reg)
326{
327 return i2c_smbus_read_byte_data(client, reg);
328}
329
330/* ----------------------------------------------------------------------- */
331
332static int saa7127_write(struct i2c_client *client, u8 reg, u8 val)
333{
334 int i;
335
336 for (i = 0; i < 3; i++) {
337 if (i2c_smbus_write_byte_data(client, reg, val) == 0)
338 return 0;
339 }
340 saa7127_err("I2C Write Problem\n");
341 return -1;
342}
343
344/* ----------------------------------------------------------------------- */
345
346static int saa7127_write_inittab(struct i2c_client *client,
347 const struct i2c_reg_value *regs)
348{
349 while (regs->reg != 0) {
350 saa7127_write(client, regs->reg, regs->value);
351 regs++;
352 }
353 return 0;
354}
355
356/* ----------------------------------------------------------------------- */
357
358static int saa7127_set_vps(struct i2c_client *client, struct v4l2_sliced_vbi_data *data)
359{
360 struct saa7127_state *state = (struct saa7127_state *)i2c_get_clientdata(client);
361 int enable = (data->line != 0);
362
363 if (enable && (data->field != 0 || data->line != 16))
364 return -EINVAL;
365 if (state->vps_enable != enable) {
366 saa7127_dbg("Turn VPS Signal %s\n", enable ? "on" : "off");
367 saa7127_write(client, 0x54, enable << 7);
368 state->vps_enable = enable;
369 }
370 if (!enable)
371 return 0;
372
373 state->vps_data[0] = data->data[4];
374 state->vps_data[1] = data->data[10];
375 state->vps_data[2] = data->data[11];
376 state->vps_data[3] = data->data[12];
377 state->vps_data[4] = data->data[13];
378 saa7127_dbg("Set VPS data %02x %02x %02x %02x %02x\n",
379 state->vps_data[0], state->vps_data[1],
380 state->vps_data[2], state->vps_data[3],
381 state->vps_data[4]);
382 saa7127_write(client, 0x55, state->vps_data[0]);
383 saa7127_write(client, 0x56, state->vps_data[1]);
384 saa7127_write(client, 0x57, state->vps_data[2]);
385 saa7127_write(client, 0x58, state->vps_data[3]);
386 saa7127_write(client, 0x59, state->vps_data[4]);
387 return 0;
388}
389
390/* ----------------------------------------------------------------------- */
391
392static int saa7127_set_cc(struct i2c_client *client, struct v4l2_sliced_vbi_data *data)
393{
394 struct saa7127_state *state = (struct saa7127_state *)i2c_get_clientdata(client);
395 u16 cc = data->data[0] << 8 | data->data[1];
396 int enable = (data->line != 0);
397
398 if (enable && (data->field != 0 || data->line != 21))
399 return -EINVAL;
400 if (state->cc_enable != enable) {
401 saa7127_dbg("Turn CC %s\n", enable ? "on" : "off");
402 saa7127_write(client, SAA7127_REG_CLOSED_CAPTION,
403 (enable << 6) | 0x11);
404 state->cc_enable = enable;
405 }
406 if (!enable)
407 return 0;
408
409 saa7127_dbg_highvol("CC data: %04x\n", cc);
410 saa7127_write(client, SAA7127_REG_LINE_21_ODD_0, cc & 0xff);
411 saa7127_write(client, SAA7127_REG_LINE_21_ODD_1, cc >> 8);
412 state->cc_data = cc;
413 return 0;
414}
415
416/* ----------------------------------------------------------------------- */
417
418static int saa7127_set_xds(struct i2c_client *client, struct v4l2_sliced_vbi_data *data)
419{
420 struct saa7127_state *state = (struct saa7127_state *)i2c_get_clientdata(client);
421 u16 xds = data->data[1] << 8 | data->data[0];
422 int enable = (data->line != 0);
423
424 if (enable && (data->field != 1 || data->line != 21))
425 return -EINVAL;
426 if (state->xds_enable != enable) {
427 saa7127_dbg("Turn XDS %s\n", enable ? "on" : "off");
428 saa7127_write(client, SAA7127_REG_CLOSED_CAPTION,
429 (enable << 7) | 0x11);
430 state->xds_enable = enable;
431 }
432 if (!enable)
433 return 0;
434
435 saa7127_dbg_highvol("XDS data: %04x\n", xds);
436 saa7127_write(client, SAA7127_REG_LINE_21_EVEN_0, xds & 0xff);
437 saa7127_write(client, SAA7127_REG_LINE_21_EVEN_1, xds >> 8);
438 state->xds_data = xds;
439 return 0;
440}
441
442/* ----------------------------------------------------------------------- */
443
444static int saa7127_set_wss(struct i2c_client *client, struct v4l2_sliced_vbi_data *data)
445{
446 struct saa7127_state *state = (struct saa7127_state *)i2c_get_clientdata(client);
447 int enable = (data->line != 0);
448
449 if (enable && (data->field != 0 || data->line != 23))
450 return -EINVAL;
451 if (state->wss_enable != enable) {
452 saa7127_dbg("Turn WSS %s\n", enable ? "on" : "off");
453 saa7127_write(client, 0x27, enable << 7);
454 state->wss_enable = enable;
455 }
456 if (!enable)
457 return 0;
458
459 saa7127_write(client, 0x26, data->data[0]);
460 saa7127_write(client, 0x27, 0x80 | (data->data[1] & 0x3f));
461 saa7127_dbg("WSS mode: %s\n", wss_strs[data->data[0] & 0xf]);
462 state->wss_mode = (data->data[1] & 0x3f) << 8 | data->data[0];
463 return 0;
464}
465
466/* ----------------------------------------------------------------------- */
467
468static int saa7127_set_video_enable(struct i2c_client *client, int enable)
469{
470 struct saa7127_state *state = (struct saa7127_state *)i2c_get_clientdata(client);
471
472 if (enable) {
473 saa7127_dbg("Enable Video Output\n");
474 saa7127_write(client, 0x2d, state->reg_2d);
475 saa7127_write(client, 0x61, state->reg_61);
476 } else {
477 saa7127_dbg("Disable Video Output\n");
478 saa7127_write(client, 0x2d, (state->reg_2d & 0xf0));
479 saa7127_write(client, 0x61, (state->reg_61 | 0xc0));
480 }
481 state->video_enable = enable;
482 return 0;
483}
484
485/* ----------------------------------------------------------------------- */
486
487static int saa7127_set_std(struct i2c_client *client, v4l2_std_id std)
488{
489 struct saa7127_state *state = (struct saa7127_state *)i2c_get_clientdata(client);
490 const struct i2c_reg_value *inittab;
491
492 if (std & V4L2_STD_525_60) {
493 saa7127_dbg("Selecting 60 Hz video Standard\n");
494 inittab = saa7127_init_config_60hz;
495 state->reg_61 = SAA7127_60HZ_DAC_CONTROL;
496 } else {
497 saa7127_dbg("Selecting 50 Hz video Standard\n");
498 inittab = saa7127_init_config_50hz;
499 state->reg_61 = SAA7127_50HZ_DAC_CONTROL;
500 }
501
502 /* Write Table */
503 saa7127_write_inittab(client, inittab);
504 state->std = std;
505 return 0;
506}
507
508/* ----------------------------------------------------------------------- */
509
510static int saa7127_set_output_type(struct i2c_client *client, int output)
511{
512 struct saa7127_state *state = (struct saa7127_state *)i2c_get_clientdata(client);
513
514 switch (output) {
515 case SAA7127_OUTPUT_TYPE_RGB:
516 state->reg_2d = 0x0f; /* RGB + CVBS (for sync) */
517 state->reg_3a = 0x13; /* by default switch YUV to RGB-matrix on */
518 break;
519
520 case SAA7127_OUTPUT_TYPE_COMPOSITE:
521 state->reg_2d = 0x08; /* 00001000 CVBS only, RGB DAC's off (high impedance mode) */
522 state->reg_3a = 0x13; /* by default switch YUV to RGB-matrix on */
523 break;
524
525 case SAA7127_OUTPUT_TYPE_SVIDEO:
526 state->reg_2d = 0xff; /* 11111111 croma -> R, luma -> CVBS + G + B */
527 state->reg_3a = 0x13; /* by default switch YUV to RGB-matrix on */
528 break;
529
530 case SAA7127_OUTPUT_TYPE_YUV_V:
531 state->reg_2d = 0x4f; /* reg 2D = 01001111, all DAC's on, RGB + VBS */
532 state->reg_3a = 0x0b; /* reg 3A = 00001011, bypass RGB-matrix */
533 break;
534
535 case SAA7127_OUTPUT_TYPE_YUV_C:
536 state->reg_2d = 0x0f; /* reg 2D = 00001111, all DAC's on, RGB + CVBS */
537 state->reg_3a = 0x0b; /* reg 3A = 00001011, bypass RGB-matrix */
538 break;
539
540 case SAA7127_OUTPUT_TYPE_BOTH:
541 state->reg_2d = 0xbf;
542 state->reg_3a = 0x13; /* by default switch YUV to RGB-matrix on */
543 break;
544
545 default:
546 return -EINVAL;
547 }
548 saa7127_dbg("Selecting %s output type\n", output_strs[output]);
549
550 /* Configure Encoder */
551 saa7127_write(client, 0x2d, state->reg_2d);
552 saa7127_write(client, 0x3a, state->reg_3a | state->reg_3a_cb);
553 state->output_type = output;
554 return 0;
555}
556
557/* ----------------------------------------------------------------------- */
558
559static int saa7127_set_input_type(struct i2c_client *client, int input)
560{
561 struct saa7127_state *state = (struct saa7127_state *)i2c_get_clientdata(client);
562
563 switch (input) {
564 case SAA7127_INPUT_TYPE_NORMAL: /* avia */
565 saa7127_dbg("Selecting Normal Encoder Input\n");
566 state->reg_3a_cb = 0;
567 break;
568
569 case SAA7127_INPUT_TYPE_TEST_IMAGE: /* color bar */
570 saa7127_dbg("Selecting Color Bar generator\n");
571 state->reg_3a_cb = 0x80;
572 break;
573
574 default:
575 return -EINVAL;
576 }
577 saa7127_write(client, 0x3a, state->reg_3a | state->reg_3a_cb);
578 state->input_type = input;
579 return 0;
580}
581
582/* ----------------------------------------------------------------------- */
583
584static int saa7127_command(struct i2c_client *client,
585 unsigned int cmd, void *arg)
586{
587 struct saa7127_state *state = i2c_get_clientdata(client);
588 struct v4l2_format *fmt = arg;
589 int *iarg = arg;
590
591 switch (cmd) {
592 case VIDIOC_S_STD:
593 if (state->std == *(v4l2_std_id *)arg)
594 break;
595 return saa7127_set_std(client, *(v4l2_std_id *)arg);
596
597 case VIDIOC_G_STD:
598 *(v4l2_std_id *)arg = state->std;
599 break;
600
601 case VIDIOC_S_INPUT:
602 if (state->input_type == *iarg)
603 break;
604 return saa7127_set_input_type(client, *iarg);
605
606 case VIDIOC_S_OUTPUT:
607 if (state->output_type == *iarg)
608 break;
609 return saa7127_set_output_type(client, *iarg);
610
611 case VIDIOC_STREAMON:
612 case VIDIOC_STREAMOFF:
613 if (state->video_enable == (cmd == VIDIOC_STREAMON))
614 break;
615 return saa7127_set_video_enable(client, cmd == VIDIOC_STREAMON);
616
617 case VIDIOC_G_FMT:
618 if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
619 return -EINVAL;
620
621 memset(&fmt->fmt.sliced, 0, sizeof(fmt->fmt.sliced));
622 if (state->vps_enable)
623 fmt->fmt.sliced.service_lines[0][16] = V4L2_SLICED_VPS;
624 if (state->wss_enable)
625 fmt->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625;
626 if (state->cc_enable) {
627 fmt->fmt.sliced.service_lines[0][21] = V4L2_SLICED_CAPTION_525;
628 fmt->fmt.sliced.service_lines[1][21] = V4L2_SLICED_CAPTION_525;
629 }
630 fmt->fmt.sliced.service_set =
631 (state->vps_enable ? V4L2_SLICED_VPS : 0) |
632 (state->wss_enable ? V4L2_SLICED_WSS_625 : 0) |
633 (state->cc_enable ? V4L2_SLICED_CAPTION_525 : 0);
634 break;
635
636 case VIDIOC_LOG_STATUS:
637 saa7127_info("Standard: %s\n", (state->std & V4L2_STD_525_60) ? "60 Hz" : "50 Hz");
638 saa7127_info("Input: %s\n", state->input_type ? "color bars" : "normal");
639 saa7127_info("Output: %s\n", state->video_enable ?
640 output_strs[state->output_type] : "disabled");
641 saa7127_info("WSS: %s\n", state->wss_enable ?
642 wss_strs[state->wss_mode] : "disabled");
643 saa7127_info("VPS: %s\n", state->vps_enable ? "enabled" : "disabled");
644 saa7127_info("CC: %s\n", state->cc_enable ? "enabled" : "disabled");
645 break;
646
647#ifdef CONFIG_VIDEO_ADV_DEBUG
648 case VIDIOC_INT_G_REGISTER:
649 {
650 struct v4l2_register *reg = arg;
651
652 if (reg->i2c_id != I2C_DRIVERID_SAA7127)
653 return -EINVAL;
654 reg->val = saa7127_read(client, reg->reg & 0xff);
655 break;
656 }
657
658 case VIDIOC_INT_S_REGISTER:
659 {
660 struct v4l2_register *reg = arg;
661
662 if (reg->i2c_id != I2C_DRIVERID_SAA7127)
663 return -EINVAL;
664 if (!capable(CAP_SYS_ADMIN))
665 return -EPERM;
666 saa7127_write(client, reg->reg & 0xff, reg->val & 0xff);
667 break;
668 }
669#endif
670
671 case VIDIOC_INT_S_VBI_DATA:
672 {
673 struct v4l2_sliced_vbi_data *data = arg;
674
675 switch (data->id) {
676 case V4L2_SLICED_WSS_625:
677 return saa7127_set_wss(client, data);
678 case V4L2_SLICED_VPS:
679 return saa7127_set_vps(client, data);
680 case V4L2_SLICED_CAPTION_525:
681 if (data->field == 0)
682 return saa7127_set_cc(client, data);
683 return saa7127_set_xds(client, data);
684 default:
685 return -EINVAL;
686 }
687 break;
688 }
689
690 case VIDIOC_INT_G_CHIP_IDENT:
691 *(enum v4l2_chip_ident *)arg = state->ident;
692 break;
693
694 default:
695 return -EINVAL;
696 }
697 return 0;
698}
699
700/* ----------------------------------------------------------------------- */
701
702struct i2c_driver i2c_driver_saa7127;
703
704/* ----------------------------------------------------------------------- */
705
706static int saa7127_attach(struct i2c_adapter *adapter, int address, int kind)
707{
708 struct i2c_client *client;
709 struct saa7127_state *state;
710 struct v4l2_sliced_vbi_data vbi = { 0, 0, 0, 0 }; /* set to disabled */
711 int read_result = 0;
712
713 /* Check if the adapter supports the needed features */
714 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
715 return 0;
716
717 client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
718 if (client == 0)
719 return -ENOMEM;
720
721 memset(client, 0, sizeof(struct i2c_client));
722 client->addr = address;
723 client->adapter = adapter;
724 client->driver = &i2c_driver_saa7127;
725 client->flags = I2C_CLIENT_ALLOW_USE;
726 snprintf(client->name, sizeof(client->name) - 1, "saa7127");
727
728 saa7127_dbg("detecting saa7127 client on address 0x%x\n", address << 1);
729
730 /* First test register 0: Bits 5-7 are a version ID (should be 0),
731 and bit 2 should also be 0.
732 This is rather general, so the second test is more specific and
733 looks at the 'ending point of burst in clock cycles' which is
734 0x1d after a reset and not expected to ever change. */
735 if ((saa7127_read(client, 0) & 0xe4) != 0 ||
736 (saa7127_read(client, 0x29) & 0x3f) != 0x1d) {
737 saa7127_dbg("saa7127 not found\n");
738 kfree(client);
739 return 0;
740 }
741 state = kmalloc(sizeof(struct saa7127_state), GFP_KERNEL);
742
743 if (state == NULL) {
744 kfree(client);
745 return (-ENOMEM);
746 }
747
748 i2c_set_clientdata(client, state);
749 memset(state, 0, sizeof(struct saa7127_state));
750
751 /* Configure Encoder */
752
753 saa7127_dbg("Configuring encoder\n");
754 saa7127_write_inittab(client, saa7127_init_config_common);
755 saa7127_set_std(client, V4L2_STD_NTSC);
756 saa7127_set_output_type(client, SAA7127_OUTPUT_TYPE_BOTH);
757 saa7127_set_vps(client, &vbi);
758 saa7127_set_wss(client, &vbi);
759 saa7127_set_cc(client, &vbi);
760 saa7127_set_xds(client, &vbi);
761 if (test_image == 1) {
762 /* The Encoder has an internal Colorbar generator */
763 /* This can be used for debugging */
764 saa7127_set_input_type(client, SAA7127_INPUT_TYPE_TEST_IMAGE);
765 } else {
766 saa7127_set_input_type(client, SAA7127_INPUT_TYPE_NORMAL);
767 }
768 saa7127_set_video_enable(client, 1);
769
770 /* Detect if it's an saa7129 */
771 read_result = saa7127_read(client, SAA7129_REG_FADE_KEY_COL2);
772 saa7127_write(client, SAA7129_REG_FADE_KEY_COL2, 0xaa);
773 if (saa7127_read(client, SAA7129_REG_FADE_KEY_COL2) == 0xaa) {
774 saa7127_info("saa7129 found @ 0x%x (%s)\n", address << 1, adapter->name);
775 saa7127_write(client, SAA7129_REG_FADE_KEY_COL2, read_result);
776 saa7127_write_inittab(client, saa7129_init_config_extra);
777 state->ident = V4L2_IDENT_SAA7129;
778 } else {
779 saa7127_info("saa7127 found @ 0x%x (%s)\n", address << 1, adapter->name);
780 state->ident = V4L2_IDENT_SAA7127;
781 }
782
783 i2c_attach_client(client);
784
785 return 0;
786}
787
788/* ----------------------------------------------------------------------- */
789
790static int saa7127_probe(struct i2c_adapter *adapter)
791{
792#ifdef I2C_CLASS_TV_ANALOG
793 if (adapter->class & I2C_CLASS_TV_ANALOG)
794#else
795 if (adapter->id == I2C_HW_B_BT848)
796#endif
797 return i2c_probe(adapter, &addr_data, saa7127_attach);
798 return 0;
799}
800
801/* ----------------------------------------------------------------------- */
802
803static int saa7127_detach(struct i2c_client *client)
804{
805 struct saa7127_state *state = i2c_get_clientdata(client);
806 int err;
807
808 /* Turn off TV output */
809 saa7127_set_video_enable(client, 0);
810
811 err = i2c_detach_client(client);
812
813 if (err) {
814 return err;
815 }
816
817 kfree(state);
818 kfree(client);
819 return 0;
820}
821
822/* ----------------------------------------------------------------------- */
823
824struct i2c_driver i2c_driver_saa7127 = {
825 .name = "saa7127",
826 .id = I2C_DRIVERID_SAA7127,
827 .flags = I2C_DF_NOTIFY,
828 .attach_adapter = saa7127_probe,
829 .detach_client = saa7127_detach,
830 .command = saa7127_command,
831 .owner = THIS_MODULE,
832};
833
834
835/* ----------------------------------------------------------------------- */
836
837static int __init saa7127_init_module(void)
838{
839 return i2c_add_driver(&i2c_driver_saa7127);
840}
841
842/* ----------------------------------------------------------------------- */
843
844static void __exit saa7127_cleanup_module(void)
845{
846 i2c_del_driver(&i2c_driver_saa7127);
847}
848
849/* ----------------------------------------------------------------------- */
850
851module_init(saa7127_init_module);
852module_exit(saa7127_cleanup_module);