1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47#include <linux/kernel.h>
48#include <linux/module.h>
49#include <linux/slab.h>
50#include <linux/i2c.h>
51#include <linux/videodev2.h>
52#include <media/v4l2-device.h>
53#include <media/i2c/saa7127.h>
54
55static int debug;
56static int test_image;
57
58MODULE_DESCRIPTION("Philips SAA7127/9 video encoder driver");
59MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil");
60MODULE_LICENSE("GPL");
61module_param(debug, int, 0644);
62module_param(test_image, int, 0644);
63MODULE_PARM_DESC(debug, "debug level (0-2)");
64MODULE_PARM_DESC(test_image, "test_image (0-1)");
65
66
67
68
69
70
71#define SAA7127_REG_STATUS 0x00
72#define SAA7127_REG_WIDESCREEN_CONFIG 0x26
73#define SAA7127_REG_WIDESCREEN_ENABLE 0x27
74#define SAA7127_REG_BURST_START 0x28
75#define SAA7127_REG_BURST_END 0x29
76#define SAA7127_REG_COPYGEN_0 0x2a
77#define SAA7127_REG_COPYGEN_1 0x2b
78#define SAA7127_REG_COPYGEN_2 0x2c
79#define SAA7127_REG_OUTPUT_PORT_CONTROL 0x2d
80#define SAA7127_REG_GAIN_LUMINANCE_RGB 0x38
81#define SAA7127_REG_GAIN_COLORDIFF_RGB 0x39
82#define SAA7127_REG_INPUT_PORT_CONTROL_1 0x3a
83#define SAA7129_REG_FADE_KEY_COL2 0x4f
84#define SAA7127_REG_CHROMA_PHASE 0x5a
85#define SAA7127_REG_GAINU 0x5b
86#define SAA7127_REG_GAINV 0x5c
87#define SAA7127_REG_BLACK_LEVEL 0x5d
88#define SAA7127_REG_BLANKING_LEVEL 0x5e
89#define SAA7127_REG_VBI_BLANKING 0x5f
90#define SAA7127_REG_DAC_CONTROL 0x61
91#define SAA7127_REG_BURST_AMP 0x62
92#define SAA7127_REG_SUBC3 0x63
93#define SAA7127_REG_SUBC2 0x64
94#define SAA7127_REG_SUBC1 0x65
95#define SAA7127_REG_SUBC0 0x66
96#define SAA7127_REG_LINE_21_ODD_0 0x67
97#define SAA7127_REG_LINE_21_ODD_1 0x68
98#define SAA7127_REG_LINE_21_EVEN_0 0x69
99#define SAA7127_REG_LINE_21_EVEN_1 0x6a
100#define SAA7127_REG_RCV_PORT_CONTROL 0x6b
101#define SAA7127_REG_VTRIG 0x6c
102#define SAA7127_REG_HTRIG_HI 0x6d
103#define SAA7127_REG_MULTI 0x6e
104#define SAA7127_REG_CLOSED_CAPTION 0x6f
105#define SAA7127_REG_RCV2_OUTPUT_START 0x70
106#define SAA7127_REG_RCV2_OUTPUT_END 0x71
107#define SAA7127_REG_RCV2_OUTPUT_MSBS 0x72
108#define SAA7127_REG_TTX_REQUEST_H_START 0x73
109#define SAA7127_REG_TTX_REQUEST_H_DELAY_LENGTH 0x74
110#define SAA7127_REG_CSYNC_ADVANCE_VSYNC_SHIFT 0x75
111#define SAA7127_REG_TTX_ODD_REQ_VERT_START 0x76
112#define SAA7127_REG_TTX_ODD_REQ_VERT_END 0x77
113#define SAA7127_REG_TTX_EVEN_REQ_VERT_START 0x78
114#define SAA7127_REG_TTX_EVEN_REQ_VERT_END 0x79
115#define SAA7127_REG_FIRST_ACTIVE 0x7a
116#define SAA7127_REG_LAST_ACTIVE 0x7b
117#define SAA7127_REG_MSB_VERTICAL 0x7c
118#define SAA7127_REG_DISABLE_TTX_LINE_LO_0 0x7e
119#define SAA7127_REG_DISABLE_TTX_LINE_LO_1 0x7f
120
121
122
123
124
125
126
127
128
129struct i2c_reg_value {
130 unsigned char reg;
131 unsigned char value;
132};
133
134static const struct i2c_reg_value saa7129_init_config_extra[] = {
135 { SAA7127_REG_OUTPUT_PORT_CONTROL, 0x38 },
136 { SAA7127_REG_VTRIG, 0xfa },
137 { 0, 0 }
138};
139
140static const struct i2c_reg_value saa7127_init_config_common[] = {
141 { SAA7127_REG_WIDESCREEN_CONFIG, 0x0d },
142 { SAA7127_REG_WIDESCREEN_ENABLE, 0x00 },
143 { SAA7127_REG_COPYGEN_0, 0x77 },
144 { SAA7127_REG_COPYGEN_1, 0x41 },
145 { SAA7127_REG_COPYGEN_2, 0x00 },
146 { SAA7127_REG_OUTPUT_PORT_CONTROL, 0xbf },
147 { SAA7127_REG_GAIN_LUMINANCE_RGB, 0x00 },
148 { SAA7127_REG_GAIN_COLORDIFF_RGB, 0x00 },
149 { SAA7127_REG_INPUT_PORT_CONTROL_1, 0x80 },
150 { SAA7127_REG_LINE_21_ODD_0, 0x77 },
151 { SAA7127_REG_LINE_21_ODD_1, 0x41 },
152 { SAA7127_REG_LINE_21_EVEN_0, 0x88 },
153 { SAA7127_REG_LINE_21_EVEN_1, 0x41 },
154 { SAA7127_REG_RCV_PORT_CONTROL, 0x12 },
155 { SAA7127_REG_VTRIG, 0xf9 },
156 { SAA7127_REG_HTRIG_HI, 0x00 },
157 { SAA7127_REG_RCV2_OUTPUT_START, 0x41 },
158 { SAA7127_REG_RCV2_OUTPUT_END, 0xc3 },
159 { SAA7127_REG_RCV2_OUTPUT_MSBS, 0x00 },
160 { SAA7127_REG_TTX_REQUEST_H_START, 0x3e },
161 { SAA7127_REG_TTX_REQUEST_H_DELAY_LENGTH, 0xb8 },
162 { SAA7127_REG_CSYNC_ADVANCE_VSYNC_SHIFT, 0x03 },
163 { SAA7127_REG_TTX_ODD_REQ_VERT_START, 0x15 },
164 { SAA7127_REG_TTX_ODD_REQ_VERT_END, 0x16 },
165 { SAA7127_REG_TTX_EVEN_REQ_VERT_START, 0x15 },
166 { SAA7127_REG_TTX_EVEN_REQ_VERT_END, 0x16 },
167 { SAA7127_REG_FIRST_ACTIVE, 0x1a },
168 { SAA7127_REG_LAST_ACTIVE, 0x01 },
169 { SAA7127_REG_MSB_VERTICAL, 0xc0 },
170 { SAA7127_REG_DISABLE_TTX_LINE_LO_0, 0x00 },
171 { SAA7127_REG_DISABLE_TTX_LINE_LO_1, 0x00 },
172 { 0, 0 }
173};
174
175#define SAA7127_60HZ_DAC_CONTROL 0x15
176static const struct i2c_reg_value saa7127_init_config_60hz[] = {
177 { SAA7127_REG_BURST_START, 0x19 },
178
179 { SAA7127_REG_BURST_END, 0x1d },
180 { SAA7127_REG_CHROMA_PHASE, 0xa3 },
181 { SAA7127_REG_GAINU, 0x98 },
182 { SAA7127_REG_GAINV, 0xd3 },
183 { SAA7127_REG_BLACK_LEVEL, 0x39 },
184 { SAA7127_REG_BLANKING_LEVEL, 0x2e },
185 { SAA7127_REG_VBI_BLANKING, 0x2e },
186 { SAA7127_REG_DAC_CONTROL, 0x15 },
187 { SAA7127_REG_BURST_AMP, 0x4d },
188 { SAA7127_REG_SUBC3, 0x1f },
189 { SAA7127_REG_SUBC2, 0x7c },
190 { SAA7127_REG_SUBC1, 0xf0 },
191 { SAA7127_REG_SUBC0, 0x21 },
192 { SAA7127_REG_MULTI, 0x90 },
193 { SAA7127_REG_CLOSED_CAPTION, 0x11 },
194 { 0, 0 }
195};
196
197#define SAA7127_50HZ_PAL_DAC_CONTROL 0x02
198static struct i2c_reg_value saa7127_init_config_50hz_pal[] = {
199 { SAA7127_REG_BURST_START, 0x21 },
200
201 { SAA7127_REG_BURST_END, 0x1d },
202 { SAA7127_REG_CHROMA_PHASE, 0x3f },
203 { SAA7127_REG_GAINU, 0x7d },
204 { SAA7127_REG_GAINV, 0xaf },
205 { SAA7127_REG_BLACK_LEVEL, 0x33 },
206 { SAA7127_REG_BLANKING_LEVEL, 0x35 },
207 { SAA7127_REG_VBI_BLANKING, 0x35 },
208 { SAA7127_REG_DAC_CONTROL, 0x02 },
209 { SAA7127_REG_BURST_AMP, 0x2f },
210 { SAA7127_REG_SUBC3, 0xcb },
211 { SAA7127_REG_SUBC2, 0x8a },
212 { SAA7127_REG_SUBC1, 0x09 },
213 { SAA7127_REG_SUBC0, 0x2a },
214 { SAA7127_REG_MULTI, 0xa0 },
215 { SAA7127_REG_CLOSED_CAPTION, 0x00 },
216 { 0, 0 }
217};
218
219#define SAA7127_50HZ_SECAM_DAC_CONTROL 0x08
220static struct i2c_reg_value saa7127_init_config_50hz_secam[] = {
221 { SAA7127_REG_BURST_START, 0x21 },
222
223 { SAA7127_REG_BURST_END, 0x1d },
224 { SAA7127_REG_CHROMA_PHASE, 0x3f },
225 { SAA7127_REG_GAINU, 0x6a },
226 { SAA7127_REG_GAINV, 0x81 },
227 { SAA7127_REG_BLACK_LEVEL, 0x33 },
228 { SAA7127_REG_BLANKING_LEVEL, 0x35 },
229 { SAA7127_REG_VBI_BLANKING, 0x35 },
230 { SAA7127_REG_DAC_CONTROL, 0x08 },
231 { SAA7127_REG_BURST_AMP, 0x2f },
232 { SAA7127_REG_SUBC3, 0xb2 },
233 { SAA7127_REG_SUBC2, 0x3b },
234 { SAA7127_REG_SUBC1, 0xa3 },
235 { SAA7127_REG_SUBC0, 0x28 },
236 { SAA7127_REG_MULTI, 0x90 },
237 { SAA7127_REG_CLOSED_CAPTION, 0x00 },
238 { 0, 0 }
239};
240
241
242
243
244
245
246
247
248
249enum saa712x_model {
250 SAA7127,
251 SAA7129,
252};
253
254struct saa7127_state {
255 struct v4l2_subdev sd;
256 v4l2_std_id std;
257 enum saa712x_model ident;
258 enum saa7127_input_type input_type;
259 enum saa7127_output_type output_type;
260 int video_enable;
261 int wss_enable;
262 u16 wss_mode;
263 int cc_enable;
264 u16 cc_data;
265 int xds_enable;
266 u16 xds_data;
267 int vps_enable;
268 u8 vps_data[5];
269 u8 reg_2d;
270 u8 reg_3a;
271 u8 reg_3a_cb;
272 u8 reg_61;
273};
274
275static inline struct saa7127_state *to_state(struct v4l2_subdev *sd)
276{
277 return container_of(sd, struct saa7127_state, sd);
278}
279
280static const char * const output_strs[] =
281{
282 "S-Video + Composite",
283 "Composite",
284 "S-Video",
285 "RGB",
286 "YUV C",
287 "YUV V"
288};
289
290static const char * const wss_strs[] = {
291 "invalid",
292 "letterbox 14:9 center",
293 "letterbox 14:9 top",
294 "invalid",
295 "letterbox 16:9 top",
296 "invalid",
297 "invalid",
298 "16:9 full format anamorphic",
299 "4:3 full format",
300 "invalid",
301 "invalid",
302 "letterbox 16:9 center",
303 "invalid",
304 "letterbox >16:9 center",
305 "14:9 full format center",
306 "invalid",
307};
308
309
310
311static int saa7127_read(struct v4l2_subdev *sd, u8 reg)
312{
313 struct i2c_client *client = v4l2_get_subdevdata(sd);
314
315 return i2c_smbus_read_byte_data(client, reg);
316}
317
318
319
320static int saa7127_write(struct v4l2_subdev *sd, u8 reg, u8 val)
321{
322 struct i2c_client *client = v4l2_get_subdevdata(sd);
323 int i;
324
325 for (i = 0; i < 3; i++) {
326 if (i2c_smbus_write_byte_data(client, reg, val) == 0)
327 return 0;
328 }
329 v4l2_err(sd, "I2C Write Problem\n");
330 return -1;
331}
332
333
334
335static int saa7127_write_inittab(struct v4l2_subdev *sd,
336 const struct i2c_reg_value *regs)
337{
338 while (regs->reg != 0) {
339 saa7127_write(sd, regs->reg, regs->value);
340 regs++;
341 }
342 return 0;
343}
344
345
346
347static int saa7127_set_vps(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data)
348{
349 struct saa7127_state *state = to_state(sd);
350 int enable = (data->line != 0);
351
352 if (enable && (data->field != 0 || data->line != 16))
353 return -EINVAL;
354 if (state->vps_enable != enable) {
355 v4l2_dbg(1, debug, sd, "Turn VPS Signal %s\n", enable ? "on" : "off");
356 saa7127_write(sd, 0x54, enable << 7);
357 state->vps_enable = enable;
358 }
359 if (!enable)
360 return 0;
361
362 state->vps_data[0] = data->data[2];
363 state->vps_data[1] = data->data[8];
364 state->vps_data[2] = data->data[9];
365 state->vps_data[3] = data->data[10];
366 state->vps_data[4] = data->data[11];
367 v4l2_dbg(1, debug, sd, "Set VPS data %*ph\n", 5, state->vps_data);
368 saa7127_write(sd, 0x55, state->vps_data[0]);
369 saa7127_write(sd, 0x56, state->vps_data[1]);
370 saa7127_write(sd, 0x57, state->vps_data[2]);
371 saa7127_write(sd, 0x58, state->vps_data[3]);
372 saa7127_write(sd, 0x59, state->vps_data[4]);
373 return 0;
374}
375
376
377
378static int saa7127_set_cc(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data)
379{
380 struct saa7127_state *state = to_state(sd);
381 u16 cc = data->data[1] << 8 | data->data[0];
382 int enable = (data->line != 0);
383
384 if (enable && (data->field != 0 || data->line != 21))
385 return -EINVAL;
386 if (state->cc_enable != enable) {
387 v4l2_dbg(1, debug, sd,
388 "Turn CC %s\n", enable ? "on" : "off");
389 saa7127_write(sd, SAA7127_REG_CLOSED_CAPTION,
390 (state->xds_enable << 7) | (enable << 6) | 0x11);
391 state->cc_enable = enable;
392 }
393 if (!enable)
394 return 0;
395
396 v4l2_dbg(2, debug, sd, "CC data: %04x\n", cc);
397 saa7127_write(sd, SAA7127_REG_LINE_21_ODD_0, cc & 0xff);
398 saa7127_write(sd, SAA7127_REG_LINE_21_ODD_1, cc >> 8);
399 state->cc_data = cc;
400 return 0;
401}
402
403
404
405static int saa7127_set_xds(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data)
406{
407 struct saa7127_state *state = to_state(sd);
408 u16 xds = data->data[1] << 8 | data->data[0];
409 int enable = (data->line != 0);
410
411 if (enable && (data->field != 1 || data->line != 21))
412 return -EINVAL;
413 if (state->xds_enable != enable) {
414 v4l2_dbg(1, debug, sd, "Turn XDS %s\n", enable ? "on" : "off");
415 saa7127_write(sd, SAA7127_REG_CLOSED_CAPTION,
416 (enable << 7) | (state->cc_enable << 6) | 0x11);
417 state->xds_enable = enable;
418 }
419 if (!enable)
420 return 0;
421
422 v4l2_dbg(2, debug, sd, "XDS data: %04x\n", xds);
423 saa7127_write(sd, SAA7127_REG_LINE_21_EVEN_0, xds & 0xff);
424 saa7127_write(sd, SAA7127_REG_LINE_21_EVEN_1, xds >> 8);
425 state->xds_data = xds;
426 return 0;
427}
428
429
430
431static int saa7127_set_wss(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data)
432{
433 struct saa7127_state *state = to_state(sd);
434 int enable = (data->line != 0);
435
436 if (enable && (data->field != 0 || data->line != 23))
437 return -EINVAL;
438 if (state->wss_enable != enable) {
439 v4l2_dbg(1, debug, sd, "Turn WSS %s\n", enable ? "on" : "off");
440 saa7127_write(sd, 0x27, enable << 7);
441 state->wss_enable = enable;
442 }
443 if (!enable)
444 return 0;
445
446 saa7127_write(sd, 0x26, data->data[0]);
447 saa7127_write(sd, 0x27, 0x80 | (data->data[1] & 0x3f));
448 v4l2_dbg(1, debug, sd,
449 "WSS mode: %s\n", wss_strs[data->data[0] & 0xf]);
450 state->wss_mode = (data->data[1] & 0x3f) << 8 | data->data[0];
451 return 0;
452}
453
454
455
456static int saa7127_set_video_enable(struct v4l2_subdev *sd, int enable)
457{
458 struct saa7127_state *state = to_state(sd);
459
460 if (enable) {
461 v4l2_dbg(1, debug, sd, "Enable Video Output\n");
462 saa7127_write(sd, 0x2d, state->reg_2d);
463 saa7127_write(sd, 0x61, state->reg_61);
464 } else {
465 v4l2_dbg(1, debug, sd, "Disable Video Output\n");
466 saa7127_write(sd, 0x2d, (state->reg_2d & 0xf0));
467 saa7127_write(sd, 0x61, (state->reg_61 | 0xc0));
468 }
469 state->video_enable = enable;
470 return 0;
471}
472
473
474
475static int saa7127_set_std(struct v4l2_subdev *sd, v4l2_std_id std)
476{
477 struct saa7127_state *state = to_state(sd);
478 const struct i2c_reg_value *inittab;
479
480 if (std & V4L2_STD_525_60) {
481 v4l2_dbg(1, debug, sd, "Selecting 60 Hz video Standard\n");
482 inittab = saa7127_init_config_60hz;
483 state->reg_61 = SAA7127_60HZ_DAC_CONTROL;
484
485 } else if (state->ident == SAA7129 &&
486 (std & V4L2_STD_SECAM) &&
487 !(std & (V4L2_STD_625_50 & ~V4L2_STD_SECAM))) {
488
489
490 v4l2_dbg(1, debug, sd,
491 "Selecting 50 Hz SECAM video Standard\n");
492 inittab = saa7127_init_config_50hz_secam;
493 state->reg_61 = SAA7127_50HZ_SECAM_DAC_CONTROL;
494
495 } else {
496 v4l2_dbg(1, debug, sd, "Selecting 50 Hz PAL video Standard\n");
497 inittab = saa7127_init_config_50hz_pal;
498 state->reg_61 = SAA7127_50HZ_PAL_DAC_CONTROL;
499 }
500
501
502 saa7127_write_inittab(sd, inittab);
503 state->std = std;
504 return 0;
505}
506
507
508
509static int saa7127_set_output_type(struct v4l2_subdev *sd, int output)
510{
511 struct saa7127_state *state = to_state(sd);
512
513 switch (output) {
514 case SAA7127_OUTPUT_TYPE_RGB:
515 state->reg_2d = 0x0f;
516 state->reg_3a = 0x13;
517 break;
518
519 case SAA7127_OUTPUT_TYPE_COMPOSITE:
520 if (state->ident == SAA7129)
521 state->reg_2d = 0x20;
522 else
523 state->reg_2d = 0x08;
524 state->reg_3a = 0x13;
525 break;
526
527 case SAA7127_OUTPUT_TYPE_SVIDEO:
528 if (state->ident == SAA7129)
529 state->reg_2d = 0x18;
530 else
531 state->reg_2d = 0xff;
532 state->reg_3a = 0x13;
533 break;
534
535 case SAA7127_OUTPUT_TYPE_YUV_V:
536 state->reg_2d = 0x4f;
537 state->reg_3a = 0x0b;
538 break;
539
540 case SAA7127_OUTPUT_TYPE_YUV_C:
541 state->reg_2d = 0x0f;
542 state->reg_3a = 0x0b;
543 break;
544
545 case SAA7127_OUTPUT_TYPE_BOTH:
546 if (state->ident == SAA7129)
547 state->reg_2d = 0x38;
548 else
549 state->reg_2d = 0xbf;
550 state->reg_3a = 0x13;
551 break;
552
553 default:
554 return -EINVAL;
555 }
556 v4l2_dbg(1, debug, sd,
557 "Selecting %s output type\n", output_strs[output]);
558
559
560 saa7127_write(sd, 0x2d, state->reg_2d);
561 saa7127_write(sd, 0x3a, state->reg_3a | state->reg_3a_cb);
562 state->output_type = output;
563 return 0;
564}
565
566
567
568static int saa7127_set_input_type(struct v4l2_subdev *sd, int input)
569{
570 struct saa7127_state *state = to_state(sd);
571
572 switch (input) {
573 case SAA7127_INPUT_TYPE_NORMAL:
574 v4l2_dbg(1, debug, sd, "Selecting Normal Encoder Input\n");
575 state->reg_3a_cb = 0;
576 break;
577
578 case SAA7127_INPUT_TYPE_TEST_IMAGE:
579 v4l2_dbg(1, debug, sd, "Selecting Color Bar generator\n");
580 state->reg_3a_cb = 0x80;
581 break;
582
583 default:
584 return -EINVAL;
585 }
586 saa7127_write(sd, 0x3a, state->reg_3a | state->reg_3a_cb);
587 state->input_type = input;
588 return 0;
589}
590
591
592
593static int saa7127_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
594{
595 struct saa7127_state *state = to_state(sd);
596
597 if (state->std == std)
598 return 0;
599 return saa7127_set_std(sd, std);
600}
601
602static int saa7127_s_routing(struct v4l2_subdev *sd,
603 u32 input, u32 output, u32 config)
604{
605 struct saa7127_state *state = to_state(sd);
606 int rc = 0;
607
608 if (state->input_type != input)
609 rc = saa7127_set_input_type(sd, input);
610 if (rc == 0 && state->output_type != output)
611 rc = saa7127_set_output_type(sd, output);
612 return rc;
613}
614
615static int saa7127_s_stream(struct v4l2_subdev *sd, int enable)
616{
617 struct saa7127_state *state = to_state(sd);
618
619 if (state->video_enable == enable)
620 return 0;
621 return saa7127_set_video_enable(sd, enable);
622}
623
624static int saa7127_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *fmt)
625{
626 struct saa7127_state *state = to_state(sd);
627
628 memset(fmt->service_lines, 0, sizeof(fmt->service_lines));
629 if (state->vps_enable)
630 fmt->service_lines[0][16] = V4L2_SLICED_VPS;
631 if (state->wss_enable)
632 fmt->service_lines[0][23] = V4L2_SLICED_WSS_625;
633 if (state->cc_enable) {
634 fmt->service_lines[0][21] = V4L2_SLICED_CAPTION_525;
635 fmt->service_lines[1][21] = V4L2_SLICED_CAPTION_525;
636 }
637 fmt->service_set =
638 (state->vps_enable ? V4L2_SLICED_VPS : 0) |
639 (state->wss_enable ? V4L2_SLICED_WSS_625 : 0) |
640 (state->cc_enable ? V4L2_SLICED_CAPTION_525 : 0);
641 return 0;
642}
643
644static int saa7127_s_vbi_data(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data)
645{
646 switch (data->id) {
647 case V4L2_SLICED_WSS_625:
648 return saa7127_set_wss(sd, data);
649 case V4L2_SLICED_VPS:
650 return saa7127_set_vps(sd, data);
651 case V4L2_SLICED_CAPTION_525:
652 if (data->field == 0)
653 return saa7127_set_cc(sd, data);
654 return saa7127_set_xds(sd, data);
655 default:
656 return -EINVAL;
657 }
658 return 0;
659}
660
661#ifdef CONFIG_VIDEO_ADV_DEBUG
662static int saa7127_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
663{
664 reg->val = saa7127_read(sd, reg->reg & 0xff);
665 reg->size = 1;
666 return 0;
667}
668
669static int saa7127_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
670{
671 saa7127_write(sd, reg->reg & 0xff, reg->val & 0xff);
672 return 0;
673}
674#endif
675
676static int saa7127_log_status(struct v4l2_subdev *sd)
677{
678 struct saa7127_state *state = to_state(sd);
679
680 v4l2_info(sd, "Standard: %s\n", (state->std & V4L2_STD_525_60) ? "60 Hz" : "50 Hz");
681 v4l2_info(sd, "Input: %s\n", state->input_type ? "color bars" : "normal");
682 v4l2_info(sd, "Output: %s\n", state->video_enable ?
683 output_strs[state->output_type] : "disabled");
684 v4l2_info(sd, "WSS: %s\n", state->wss_enable ?
685 wss_strs[state->wss_mode] : "disabled");
686 v4l2_info(sd, "VPS: %s\n", state->vps_enable ? "enabled" : "disabled");
687 v4l2_info(sd, "CC: %s\n", state->cc_enable ? "enabled" : "disabled");
688 return 0;
689}
690
691
692
693static const struct v4l2_subdev_core_ops saa7127_core_ops = {
694 .log_status = saa7127_log_status,
695#ifdef CONFIG_VIDEO_ADV_DEBUG
696 .g_register = saa7127_g_register,
697 .s_register = saa7127_s_register,
698#endif
699};
700
701static const struct v4l2_subdev_video_ops saa7127_video_ops = {
702 .s_std_output = saa7127_s_std_output,
703 .s_routing = saa7127_s_routing,
704 .s_stream = saa7127_s_stream,
705};
706
707static const struct v4l2_subdev_vbi_ops saa7127_vbi_ops = {
708 .s_vbi_data = saa7127_s_vbi_data,
709 .g_sliced_fmt = saa7127_g_sliced_fmt,
710};
711
712static const struct v4l2_subdev_ops saa7127_ops = {
713 .core = &saa7127_core_ops,
714 .video = &saa7127_video_ops,
715 .vbi = &saa7127_vbi_ops,
716};
717
718
719
720static int saa7127_probe(struct i2c_client *client,
721 const struct i2c_device_id *id)
722{
723 struct saa7127_state *state;
724 struct v4l2_subdev *sd;
725 struct v4l2_sliced_vbi_data vbi = { 0, 0, 0, 0 };
726
727
728 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
729 return -EIO;
730
731 v4l_dbg(1, debug, client, "detecting saa7127 client on address 0x%x\n",
732 client->addr << 1);
733
734 state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
735 if (state == NULL)
736 return -ENOMEM;
737
738 sd = &state->sd;
739 v4l2_i2c_subdev_init(sd, client, &saa7127_ops);
740
741
742
743
744
745
746 if ((saa7127_read(sd, 0) & 0xe4) != 0 ||
747 (saa7127_read(sd, 0x29) & 0x3f) != 0x1d) {
748 v4l2_dbg(1, debug, sd, "saa7127 not found\n");
749 return -ENODEV;
750 }
751
752 if (id->driver_data) {
753 state->ident = id->driver_data;
754 } else {
755 int read_result;
756
757
758 read_result = saa7127_read(sd, SAA7129_REG_FADE_KEY_COL2);
759 saa7127_write(sd, SAA7129_REG_FADE_KEY_COL2, 0xaa);
760 if (saa7127_read(sd, SAA7129_REG_FADE_KEY_COL2) == 0xaa) {
761 saa7127_write(sd, SAA7129_REG_FADE_KEY_COL2,
762 read_result);
763 state->ident = SAA7129;
764 strscpy(client->name, "saa7129", I2C_NAME_SIZE);
765 } else {
766 state->ident = SAA7127;
767 strscpy(client->name, "saa7127", I2C_NAME_SIZE);
768 }
769 }
770
771 v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name,
772 client->addr << 1, client->adapter->name);
773
774 v4l2_dbg(1, debug, sd, "Configuring encoder\n");
775 saa7127_write_inittab(sd, saa7127_init_config_common);
776 saa7127_set_std(sd, V4L2_STD_NTSC);
777 saa7127_set_output_type(sd, SAA7127_OUTPUT_TYPE_BOTH);
778 saa7127_set_vps(sd, &vbi);
779 saa7127_set_wss(sd, &vbi);
780 saa7127_set_cc(sd, &vbi);
781 saa7127_set_xds(sd, &vbi);
782 if (test_image == 1)
783
784
785 saa7127_set_input_type(sd, SAA7127_INPUT_TYPE_TEST_IMAGE);
786 else
787 saa7127_set_input_type(sd, SAA7127_INPUT_TYPE_NORMAL);
788 saa7127_set_video_enable(sd, 1);
789
790 if (state->ident == SAA7129)
791 saa7127_write_inittab(sd, saa7129_init_config_extra);
792 return 0;
793}
794
795
796
797static int saa7127_remove(struct i2c_client *client)
798{
799 struct v4l2_subdev *sd = i2c_get_clientdata(client);
800
801 v4l2_device_unregister_subdev(sd);
802
803 saa7127_set_video_enable(sd, 0);
804 return 0;
805}
806
807
808
809static const struct i2c_device_id saa7127_id[] = {
810 { "saa7127_auto", 0 },
811 { "saa7126", SAA7127 },
812 { "saa7127", SAA7127 },
813 { "saa7128", SAA7129 },
814 { "saa7129", SAA7129 },
815 { }
816};
817MODULE_DEVICE_TABLE(i2c, saa7127_id);
818
819static struct i2c_driver saa7127_driver = {
820 .driver = {
821 .name = "saa7127",
822 },
823 .probe = saa7127_probe,
824 .remove = saa7127_remove,
825 .id_table = saa7127_id,
826};
827
828module_i2c_driver(saa7127_driver);
829