1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21#include <linux/module.h>
22#include <linux/init.h>
23#include <linux/delay.h>
24#include <linux/types.h>
25#include <linux/slab.h>
26
27#include <linux/byteorder/swab.h>
28
29#include <asm/io.h>
30#include <asm/uaccess.h>
31
32#include <linux/i2c.h>
33
34#define I2C_NAME(x) (x)->name
35
36#include <linux/videodev.h>
37#include <media/v4l2-common.h>
38#include <linux/video_decoder.h>
39
40#define I2C_VPX3220 0x86
41#define VPX3220_DEBUG KERN_DEBUG "vpx3220: "
42
43static int debug = 0;
44module_param(debug, int, 0);
45MODULE_PARM_DESC(debug, "Debug level (0-1)");
46
47#define dprintk(num, format, args...) \
48 do { \
49 if (debug >= num) \
50 printk(format, ##args); \
51 } while (0)
52
53#define VPX_TIMEOUT_COUNT 10
54
55
56
57struct vpx3220 {
58 unsigned char reg[255];
59
60 int norm;
61 int input;
62 int enable;
63 int bright;
64 int contrast;
65 int hue;
66 int sat;
67};
68
69static char *inputs[] = { "internal", "composite", "svideo" };
70
71
72static inline int
73vpx3220_write (struct i2c_client *client,
74 u8 reg,
75 u8 value)
76{
77 struct vpx3220 *decoder = i2c_get_clientdata(client);
78
79 decoder->reg[reg] = value;
80 return i2c_smbus_write_byte_data(client, reg, value);
81}
82
83static inline int
84vpx3220_read (struct i2c_client *client,
85 u8 reg)
86{
87 return i2c_smbus_read_byte_data(client, reg);
88}
89
90static int
91vpx3220_fp_status (struct i2c_client *client)
92{
93 unsigned char status;
94 unsigned int i;
95
96 for (i = 0; i < VPX_TIMEOUT_COUNT; i++) {
97 status = vpx3220_read(client, 0x29);
98
99 if (!(status & 4))
100 return 0;
101
102 udelay(10);
103
104 if (need_resched())
105 cond_resched();
106 }
107
108 return -1;
109}
110
111static int
112vpx3220_fp_write (struct i2c_client *client,
113 u8 fpaddr,
114 u16 data)
115{
116
117 if (i2c_smbus_write_word_data(client, 0x27, swab16(fpaddr)) == -1) {
118 dprintk(1, VPX3220_DEBUG "%s: failed\n", __func__);
119 return -1;
120 }
121
122 if (vpx3220_fp_status(client) < 0)
123 return -1;
124
125
126 if (i2c_smbus_write_word_data(client, 0x28, swab16(data)) == -1) {
127 dprintk(1, VPX3220_DEBUG "%s: failed\n", __func__);
128 return -1;
129 }
130
131 return 0;
132}
133
134static u16
135vpx3220_fp_read (struct i2c_client *client,
136 u16 fpaddr)
137{
138 s16 data;
139
140
141 if (i2c_smbus_write_word_data(client, 0x26, swab16(fpaddr)) == -1) {
142 dprintk(1, VPX3220_DEBUG "%s: failed\n", __func__);
143 return -1;
144 }
145
146 if (vpx3220_fp_status(client) < 0)
147 return -1;
148
149
150 data = i2c_smbus_read_word_data(client, 0x28);
151 if (data == -1) {
152 dprintk(1, VPX3220_DEBUG "%s: failed\n", __func__);
153 return -1;
154 }
155
156 return swab16(data);
157}
158
159static int
160vpx3220_write_block (struct i2c_client *client,
161 const u8 *data,
162 unsigned int len)
163{
164 u8 reg;
165 int ret = -1;
166
167 while (len >= 2) {
168 reg = *data++;
169 if ((ret =
170 vpx3220_write(client, reg, *data++)) < 0)
171 break;
172 len -= 2;
173 }
174
175 return ret;
176}
177
178static int
179vpx3220_write_fp_block (struct i2c_client *client,
180 const u16 *data,
181 unsigned int len)
182{
183 u8 reg;
184 int ret = 0;
185
186 while (len > 1) {
187 reg = *data++;
188 ret |= vpx3220_fp_write(client, reg, *data++);
189 len -= 2;
190 }
191
192 return ret;
193}
194
195
196
197static const unsigned short init_ntsc[] = {
198 0x1c, 0x00,
199 0x88, 17,
200 0x89, 240,
201 0x8a, 240,
202 0x8b, 000,
203 0x8c, 640,
204 0x8d, 640,
205 0x8f, 0xc00,
206 0xf0, 0x73,
207
208 0xf2, 0x13,
209 0xe7, 0x1e1,
210
211};
212
213static const unsigned short init_pal[] = {
214 0x88, 23,
215 0x89, 288,
216
217 0x8a, 288,
218
219 0x8b, 16,
220 0x8c, 768,
221 0x8d, 784,
222
223 0x8f, 0xc00,
224 0xf0, 0x77,
225
226 0xf2, 0x3d1,
227 0xe7, 0x241,
228};
229
230static const unsigned short init_secam[] = {
231 0x88, 23,
232 0x89, 288,
233
234 0x8a, 288,
235
236 0x8b, 16,
237 0x8c, 768,
238 0x8d, 784,
239
240 0x8f, 0xc00,
241 0xf0, 0x77,
242
243 0xf2, 0x3d5,
244 0xe7, 0x241,
245};
246
247static const unsigned char init_common[] = {
248 0xf2, 0x00,
249 0x33, 0x0d,
250
251 0xd8, 0xa8,
252
253 0x20, 0x03,
254 0xe0, 0xff,
255 0xe1, 0x00,
256 0xe2, 0x7f,
257 0xe3, 0x80,
258 0xe4, 0x7f,
259 0xe5, 0x80,
260 0xe6, 0x00,
261 0xe7, 0xe0,
262
263 0xe8, 0xf8,
264
265 0xea, 0x18,
266
267 0xf0, 0x8a,
268
269 0xf1, 0x18,
270
271 0xf8, 0x12,
272
273 0xf9, 0x24,
274
275};
276
277static const unsigned short init_fp[] = {
278 0x59, 0,
279 0xa0, 2070,
280 0xa3, 0,
281 0xa4, 0,
282 0xa8, 30,
283 0xb2, 768,
284 0xbe, 27,
285 0x58, 0,
286 0x26, 0,
287 0x4b, 0x298,
288};
289
290static void
291vpx3220_dump_i2c (struct i2c_client *client)
292{
293 int len = sizeof(init_common);
294 const unsigned char *data = init_common;
295
296 while (len > 1) {
297 dprintk(1,
298 KERN_DEBUG "vpx3216b i2c reg 0x%02x data 0x%02x\n",
299 *data, vpx3220_read(client, *data));
300 data += 2;
301 len -= 2;
302 }
303}
304
305static int
306vpx3220_command (struct i2c_client *client,
307 unsigned int cmd,
308 void *arg)
309{
310 struct vpx3220 *decoder = i2c_get_clientdata(client);
311
312 switch (cmd) {
313 case 0:
314 {
315 vpx3220_write_block(client, init_common,
316 sizeof(init_common));
317 vpx3220_write_fp_block(client, init_fp,
318 sizeof(init_fp) >> 1);
319 switch (decoder->norm) {
320
321 case VIDEO_MODE_NTSC:
322 vpx3220_write_fp_block(client, init_ntsc,
323 sizeof(init_ntsc) >> 1);
324 break;
325
326 case VIDEO_MODE_PAL:
327 vpx3220_write_fp_block(client, init_pal,
328 sizeof(init_pal) >> 1);
329 break;
330 case VIDEO_MODE_SECAM:
331 vpx3220_write_fp_block(client, init_secam,
332 sizeof(init_secam) >> 1);
333 break;
334 default:
335 vpx3220_write_fp_block(client, init_pal,
336 sizeof(init_pal) >> 1);
337 break;
338 }
339 }
340 break;
341
342 case DECODER_DUMP:
343 {
344 vpx3220_dump_i2c(client);
345 }
346 break;
347
348 case DECODER_GET_CAPABILITIES:
349 {
350 struct video_decoder_capability *cap = arg;
351
352 dprintk(1, KERN_DEBUG "%s: DECODER_GET_CAPABILITIES\n",
353 I2C_NAME(client));
354
355 cap->flags = VIDEO_DECODER_PAL |
356 VIDEO_DECODER_NTSC |
357 VIDEO_DECODER_SECAM |
358 VIDEO_DECODER_AUTO |
359 VIDEO_DECODER_CCIR;
360 cap->inputs = 3;
361 cap->outputs = 1;
362 }
363 break;
364
365 case DECODER_GET_STATUS:
366 {
367 int res = 0, status;
368
369 dprintk(1, KERN_INFO "%s: DECODER_GET_STATUS\n",
370 I2C_NAME(client));
371
372 status = vpx3220_fp_read(client, 0x0f3);
373
374 dprintk(1, KERN_INFO "%s: status: 0x%04x\n", I2C_NAME(client),
375 status);
376
377 if (status < 0)
378 return status;
379
380 if ((status & 0x20) == 0) {
381 res |= DECODER_STATUS_GOOD | DECODER_STATUS_COLOR;
382
383 switch (status & 0x18) {
384
385 case 0x00:
386 case 0x10:
387 case 0x14:
388 case 0x18:
389 res |= DECODER_STATUS_PAL;
390 break;
391
392 case 0x08:
393 res |= DECODER_STATUS_SECAM;
394 break;
395
396 case 0x04:
397 case 0x0c:
398 case 0x1c:
399 res |= DECODER_STATUS_NTSC;
400 break;
401 }
402 }
403
404 *(int *) arg = res;
405 }
406 break;
407
408 case DECODER_SET_NORM:
409 {
410 int *iarg = arg, data;
411 int temp_input;
412
413
414
415
416 temp_input = vpx3220_fp_read(client, 0xf2);
417
418 dprintk(1, KERN_DEBUG "%s: DECODER_SET_NORM %d\n",
419 I2C_NAME(client), *iarg);
420 switch (*iarg) {
421
422 case VIDEO_MODE_NTSC:
423 vpx3220_write_fp_block(client, init_ntsc,
424 sizeof(init_ntsc) >> 1);
425 dprintk(1, KERN_INFO "%s: norm switched to NTSC\n",
426 I2C_NAME(client));
427 break;
428
429 case VIDEO_MODE_PAL:
430 vpx3220_write_fp_block(client, init_pal,
431 sizeof(init_pal) >> 1);
432 dprintk(1, KERN_INFO "%s: norm switched to PAL\n",
433 I2C_NAME(client));
434 break;
435
436 case VIDEO_MODE_SECAM:
437 vpx3220_write_fp_block(client, init_secam,
438 sizeof(init_secam) >> 1);
439 dprintk(1, KERN_INFO "%s: norm switched to SECAM\n",
440 I2C_NAME(client));
441 break;
442
443 case VIDEO_MODE_AUTO:
444
445 data = vpx3220_fp_read(client, 0xf2) & 0x20;
446 vpx3220_fp_write(client, 0xf2, 0x00c0 | data);
447 dprintk(1, KERN_INFO "%s: norm switched to Auto\n",
448 I2C_NAME(client));
449 break;
450
451 default:
452 return -EINVAL;
453
454 }
455 decoder->norm = *iarg;
456
457
458 vpx3220_fp_write(client, 0xf2, temp_input | 0x0010);
459 udelay(10);
460 }
461 break;
462
463 case DECODER_SET_INPUT:
464 {
465 int *iarg = arg, data;
466
467
468
469
470
471 const int input[3][2] = {
472 {0x0c, 0},
473 {0x0d, 0},
474 {0x0e, 1}
475 };
476
477 if (*iarg < 0 || *iarg > 2)
478 return -EINVAL;
479
480 dprintk(1, KERN_INFO "%s: input switched to %s\n",
481 I2C_NAME(client), inputs[*iarg]);
482
483 vpx3220_write(client, 0x33, input[*iarg][0]);
484
485 data = vpx3220_fp_read(client, 0xf2) & ~(0x0020);
486 if (data < 0)
487 return data;
488
489 vpx3220_fp_write(client, 0xf2,
490 data | (input[*iarg][1] << 5) | 0x0010);
491
492 udelay(10);
493 }
494 break;
495
496 case DECODER_SET_OUTPUT:
497 {
498 int *iarg = arg;
499
500
501 if (*iarg != 0) {
502 return -EINVAL;
503 }
504 }
505 break;
506
507 case DECODER_ENABLE_OUTPUT:
508 {
509 int *iarg = arg;
510
511 dprintk(1, KERN_DEBUG "%s: DECODER_ENABLE_OUTPUT %d\n",
512 I2C_NAME(client), *iarg);
513
514 vpx3220_write(client, 0xf2, (*iarg ? 0x1b : 0x00));
515 }
516 break;
517
518 case DECODER_SET_PICTURE:
519 {
520 struct video_picture *pic = arg;
521
522 if (decoder->bright != pic->brightness) {
523
524 decoder->bright = pic->brightness;
525 vpx3220_write(client, 0xe6,
526 (decoder->bright - 32768) >> 8);
527 }
528 if (decoder->contrast != pic->contrast) {
529
530
531 decoder->contrast = pic->contrast;
532 vpx3220_write(client, 0xe7,
533 (decoder->contrast >> 10) + 192);
534 }
535 if (decoder->sat != pic->colour) {
536
537 decoder->sat = pic->colour;
538 vpx3220_fp_write(client, 0xa0,
539 decoder->sat >> 4);
540 }
541 if (decoder->hue != pic->hue) {
542
543 decoder->hue = pic->hue;
544 vpx3220_fp_write(client, 0x1c,
545 ((decoder->hue - 32768) >> 6) & 0xFFF);
546 }
547 }
548 break;
549
550 default:
551 return -EINVAL;
552 }
553
554 return 0;
555}
556
557static int
558vpx3220_init_client (struct i2c_client *client)
559{
560 vpx3220_write_block(client, init_common, sizeof(init_common));
561 vpx3220_write_fp_block(client, init_fp, sizeof(init_fp) >> 1);
562
563 vpx3220_write_fp_block(client, init_pal, sizeof(init_pal) >> 1);
564
565 return 0;
566}
567
568
569
570
571
572
573
574
575
576static unsigned short normal_i2c[] =
577 { I2C_VPX3220 >> 1, (I2C_VPX3220 >> 1) + 4,
578 I2C_CLIENT_END
579};
580
581static unsigned short ignore = I2C_CLIENT_END;
582
583static struct i2c_client_address_data addr_data = {
584 .normal_i2c = normal_i2c,
585 .probe = &ignore,
586 .ignore = &ignore,
587};
588
589static struct i2c_driver vpx3220_i2c_driver;
590
591static int
592vpx3220_detach_client (struct i2c_client *client)
593{
594 struct vpx3220 *decoder = i2c_get_clientdata(client);
595 int err;
596
597 err = i2c_detach_client(client);
598 if (err) {
599 return err;
600 }
601
602 kfree(decoder);
603 kfree(client);
604
605 return 0;
606}
607
608static int
609vpx3220_detect_client (struct i2c_adapter *adapter,
610 int address,
611 int kind)
612{
613 int err;
614 struct i2c_client *client;
615 struct vpx3220 *decoder;
616
617 dprintk(1, VPX3220_DEBUG "%s\n", __func__);
618
619
620 if (!i2c_check_functionality
621 (adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
622 return 0;
623
624 client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
625 if (client == NULL) {
626 return -ENOMEM;
627 }
628
629 client->addr = address;
630 client->adapter = adapter;
631 client->driver = &vpx3220_i2c_driver;
632
633
634 if (kind < 0) {
635 u8 id;
636 u16 pn;
637
638 id = vpx3220_read(client, 0x00);
639 if (id != 0xec) {
640 dprintk(1,
641 KERN_INFO
642 "vpx3220_attach: Wrong manufacturer ID (0x%02x)\n",
643 id);
644 kfree(client);
645 return 0;
646 }
647
648 pn = (vpx3220_read(client, 0x02) << 8) +
649 vpx3220_read(client, 0x01);
650 switch (pn) {
651 case 0x4680:
652 strlcpy(I2C_NAME(client), "vpx3220a",
653 sizeof(I2C_NAME(client)));
654 break;
655 case 0x4260:
656 strlcpy(I2C_NAME(client), "vpx3216b",
657 sizeof(I2C_NAME(client)));
658 break;
659 case 0x4280:
660 strlcpy(I2C_NAME(client), "vpx3214c",
661 sizeof(I2C_NAME(client)));
662 break;
663 default:
664 dprintk(1,
665 KERN_INFO
666 "%s: Wrong part number (0x%04x)\n",
667 __func__, pn);
668 kfree(client);
669 return 0;
670 }
671 } else {
672 strlcpy(I2C_NAME(client), "forced vpx32xx",
673 sizeof(I2C_NAME(client)));
674 }
675
676 decoder = kzalloc(sizeof(struct vpx3220), GFP_KERNEL);
677 if (decoder == NULL) {
678 kfree(client);
679 return -ENOMEM;
680 }
681 decoder->norm = VIDEO_MODE_PAL;
682 decoder->input = 0;
683 decoder->enable = 1;
684 decoder->bright = 32768;
685 decoder->contrast = 32768;
686 decoder->hue = 32768;
687 decoder->sat = 32768;
688 i2c_set_clientdata(client, decoder);
689
690 err = i2c_attach_client(client);
691 if (err) {
692 kfree(client);
693 kfree(decoder);
694 return err;
695 }
696
697 dprintk(1, KERN_INFO "%s: vpx32xx client found at address 0x%02x\n",
698 I2C_NAME(client), client->addr << 1);
699
700 vpx3220_init_client(client);
701
702 return 0;
703}
704
705static int
706vpx3220_attach_adapter (struct i2c_adapter *adapter)
707{
708 int ret;
709
710 ret = i2c_probe(adapter, &addr_data, &vpx3220_detect_client);
711 dprintk(1, VPX3220_DEBUG "%s: i2c_probe returned %d\n",
712 __func__, ret);
713 return ret;
714}
715
716
717
718
719
720static struct i2c_driver vpx3220_i2c_driver = {
721 .driver = {
722 .name = "vpx3220",
723 },
724
725 .id = I2C_DRIVERID_VPX3220,
726
727 .attach_adapter = vpx3220_attach_adapter,
728 .detach_client = vpx3220_detach_client,
729 .command = vpx3220_command,
730};
731
732static int __init
733vpx3220_init (void)
734{
735 return i2c_add_driver(&vpx3220_i2c_driver);
736}
737
738static void __exit
739vpx3220_cleanup (void)
740{
741 i2c_del_driver(&vpx3220_i2c_driver);
742}
743
744module_init(vpx3220_init);
745module_exit(vpx3220_cleanup);
746
747MODULE_DESCRIPTION("vpx3220a/vpx3216b/vpx3214c video decoder driver");
748MODULE_AUTHOR("Laurent Pinchart");
749MODULE_LICENSE("GPL");
750