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#include <asm/uaccess.h>
27#include <linux/i2c.h>
28#include <linux/videodev2.h>
29#include <media/v4l2-device.h>
30#include <media/v4l2-chip-ident.h>
31#include <media/v4l2-ctrls.h>
32
33MODULE_DESCRIPTION("vpx3220a/vpx3216b/vpx3214c video decoder driver");
34MODULE_AUTHOR("Laurent Pinchart");
35MODULE_LICENSE("GPL");
36
37static int debug;
38module_param(debug, int, 0);
39MODULE_PARM_DESC(debug, "Debug level (0-1)");
40
41
42#define VPX_TIMEOUT_COUNT 10
43
44
45
46struct vpx3220 {
47 struct v4l2_subdev sd;
48 struct v4l2_ctrl_handler hdl;
49 unsigned char reg[255];
50
51 v4l2_std_id norm;
52 int ident;
53 int input;
54 int enable;
55};
56
57static inline struct vpx3220 *to_vpx3220(struct v4l2_subdev *sd)
58{
59 return container_of(sd, struct vpx3220, sd);
60}
61
62static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
63{
64 return &container_of(ctrl->handler, struct vpx3220, hdl)->sd;
65}
66
67static char *inputs[] = { "internal", "composite", "svideo" };
68
69
70
71static inline int vpx3220_write(struct v4l2_subdev *sd, u8 reg, u8 value)
72{
73 struct i2c_client *client = v4l2_get_subdevdata(sd);
74 struct vpx3220 *decoder = i2c_get_clientdata(client);
75
76 decoder->reg[reg] = value;
77 return i2c_smbus_write_byte_data(client, reg, value);
78}
79
80static inline int vpx3220_read(struct v4l2_subdev *sd, u8 reg)
81{
82 struct i2c_client *client = v4l2_get_subdevdata(sd);
83
84 return i2c_smbus_read_byte_data(client, reg);
85}
86
87static int vpx3220_fp_status(struct v4l2_subdev *sd)
88{
89 unsigned char status;
90 unsigned int i;
91
92 for (i = 0; i < VPX_TIMEOUT_COUNT; i++) {
93 status = vpx3220_read(sd, 0x29);
94
95 if (!(status & 4))
96 return 0;
97
98 udelay(10);
99
100 if (need_resched())
101 cond_resched();
102 }
103
104 return -1;
105}
106
107static int vpx3220_fp_write(struct v4l2_subdev *sd, u8 fpaddr, u16 data)
108{
109 struct i2c_client *client = v4l2_get_subdevdata(sd);
110
111
112 if (i2c_smbus_write_word_data(client, 0x27, swab16(fpaddr)) == -1) {
113 v4l2_dbg(1, debug, sd, "%s: failed\n", __func__);
114 return -1;
115 }
116
117 if (vpx3220_fp_status(sd) < 0)
118 return -1;
119
120
121 if (i2c_smbus_write_word_data(client, 0x28, swab16(data)) == -1) {
122 v4l2_dbg(1, debug, sd, "%s: failed\n", __func__);
123 return -1;
124 }
125
126 return 0;
127}
128
129static u16 vpx3220_fp_read(struct v4l2_subdev *sd, u16 fpaddr)
130{
131 struct i2c_client *client = v4l2_get_subdevdata(sd);
132 s16 data;
133
134
135 if (i2c_smbus_write_word_data(client, 0x26, swab16(fpaddr)) == -1) {
136 v4l2_dbg(1, debug, sd, "%s: failed\n", __func__);
137 return -1;
138 }
139
140 if (vpx3220_fp_status(sd) < 0)
141 return -1;
142
143
144 data = i2c_smbus_read_word_data(client, 0x28);
145 if (data == -1) {
146 v4l2_dbg(1, debug, sd, "%s: failed\n", __func__);
147 return -1;
148 }
149
150 return swab16(data);
151}
152
153static int vpx3220_write_block(struct v4l2_subdev *sd, const u8 *data, unsigned int len)
154{
155 u8 reg;
156 int ret = -1;
157
158 while (len >= 2) {
159 reg = *data++;
160 ret = vpx3220_write(sd, reg, *data++);
161 if (ret < 0)
162 break;
163 len -= 2;
164 }
165
166 return ret;
167}
168
169static int vpx3220_write_fp_block(struct v4l2_subdev *sd,
170 const u16 *data, unsigned int len)
171{
172 u8 reg;
173 int ret = 0;
174
175 while (len > 1) {
176 reg = *data++;
177 ret |= vpx3220_fp_write(sd, reg, *data++);
178 len -= 2;
179 }
180
181 return ret;
182}
183
184
185
186static const unsigned short init_ntsc[] = {
187 0x1c, 0x00,
188 0x88, 17,
189 0x89, 240,
190 0x8a, 240,
191 0x8b, 000,
192 0x8c, 640,
193 0x8d, 640,
194 0x8f, 0xc00,
195 0xf0, 0x73,
196
197 0xf2, 0x13,
198 0xe7, 0x1e1,
199
200};
201
202static const unsigned short init_pal[] = {
203 0x88, 23,
204 0x89, 288,
205
206 0x8a, 288,
207
208 0x8b, 16,
209 0x8c, 768,
210 0x8d, 784,
211
212 0x8f, 0xc00,
213 0xf0, 0x77,
214
215 0xf2, 0x3d1,
216 0xe7, 0x241,
217};
218
219static const unsigned short init_secam[] = {
220 0x88, 23,
221 0x89, 288,
222
223 0x8a, 288,
224
225 0x8b, 16,
226 0x8c, 768,
227 0x8d, 784,
228
229 0x8f, 0xc00,
230 0xf0, 0x77,
231
232 0xf2, 0x3d5,
233 0xe7, 0x241,
234};
235
236static const unsigned char init_common[] = {
237 0xf2, 0x00,
238 0x33, 0x0d,
239
240 0xd8, 0xa8,
241
242 0x20, 0x03,
243 0xe0, 0xff,
244 0xe1, 0x00,
245 0xe2, 0x7f,
246 0xe3, 0x80,
247 0xe4, 0x7f,
248 0xe5, 0x80,
249 0xe6, 0x00,
250 0xe7, 0xe0,
251
252 0xe8, 0xf8,
253
254 0xea, 0x18,
255
256 0xf0, 0x8a,
257
258 0xf1, 0x18,
259
260 0xf8, 0x12,
261
262 0xf9, 0x24,
263
264};
265
266static const unsigned short init_fp[] = {
267 0x59, 0,
268 0xa0, 2070,
269 0xa3, 0,
270 0xa4, 0,
271 0xa8, 30,
272 0xb2, 768,
273 0xbe, 27,
274 0x58, 0,
275 0x26, 0,
276 0x4b, 0x298,
277};
278
279
280static int vpx3220_init(struct v4l2_subdev *sd, u32 val)
281{
282 struct vpx3220 *decoder = to_vpx3220(sd);
283
284 vpx3220_write_block(sd, init_common, sizeof(init_common));
285 vpx3220_write_fp_block(sd, init_fp, sizeof(init_fp) >> 1);
286 if (decoder->norm & V4L2_STD_NTSC)
287 vpx3220_write_fp_block(sd, init_ntsc, sizeof(init_ntsc) >> 1);
288 else if (decoder->norm & V4L2_STD_PAL)
289 vpx3220_write_fp_block(sd, init_pal, sizeof(init_pal) >> 1);
290 else if (decoder->norm & V4L2_STD_SECAM)
291 vpx3220_write_fp_block(sd, init_secam, sizeof(init_secam) >> 1);
292 else
293 vpx3220_write_fp_block(sd, init_pal, sizeof(init_pal) >> 1);
294 return 0;
295}
296
297static int vpx3220_status(struct v4l2_subdev *sd, u32 *pstatus, v4l2_std_id *pstd)
298{
299 int res = V4L2_IN_ST_NO_SIGNAL, status;
300 v4l2_std_id std = 0;
301
302 status = vpx3220_fp_read(sd, 0x0f3);
303
304 v4l2_dbg(1, debug, sd, "status: 0x%04x\n", status);
305
306 if (status < 0)
307 return status;
308
309 if ((status & 0x20) == 0) {
310 res = 0;
311
312 switch (status & 0x18) {
313 case 0x00:
314 case 0x10:
315 case 0x14:
316 case 0x18:
317 std = V4L2_STD_PAL;
318 break;
319
320 case 0x08:
321 std = V4L2_STD_SECAM;
322 break;
323
324 case 0x04:
325 case 0x0c:
326 case 0x1c:
327 std = V4L2_STD_NTSC;
328 break;
329 }
330 }
331 if (pstd)
332 *pstd = std;
333 if (pstatus)
334 *pstatus = status;
335 return 0;
336}
337
338static int vpx3220_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
339{
340 v4l2_dbg(1, debug, sd, "querystd\n");
341 return vpx3220_status(sd, NULL, std);
342}
343
344static int vpx3220_g_input_status(struct v4l2_subdev *sd, u32 *status)
345{
346 v4l2_dbg(1, debug, sd, "g_input_status\n");
347 return vpx3220_status(sd, status, NULL);
348}
349
350static int vpx3220_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
351{
352 struct vpx3220 *decoder = to_vpx3220(sd);
353 int temp_input;
354
355
356
357
358 temp_input = vpx3220_fp_read(sd, 0xf2);
359
360 v4l2_dbg(1, debug, sd, "s_std %llx\n", (unsigned long long)std);
361 if (std & V4L2_STD_NTSC) {
362 vpx3220_write_fp_block(sd, init_ntsc, sizeof(init_ntsc) >> 1);
363 v4l2_dbg(1, debug, sd, "norm switched to NTSC\n");
364 } else if (std & V4L2_STD_PAL) {
365 vpx3220_write_fp_block(sd, init_pal, sizeof(init_pal) >> 1);
366 v4l2_dbg(1, debug, sd, "norm switched to PAL\n");
367 } else if (std & V4L2_STD_SECAM) {
368 vpx3220_write_fp_block(sd, init_secam, sizeof(init_secam) >> 1);
369 v4l2_dbg(1, debug, sd, "norm switched to SECAM\n");
370 } else {
371 return -EINVAL;
372 }
373
374 decoder->norm = std;
375
376
377 vpx3220_fp_write(sd, 0xf2, temp_input | 0x0010);
378 udelay(10);
379 return 0;
380}
381
382static int vpx3220_s_routing(struct v4l2_subdev *sd,
383 u32 input, u32 output, u32 config)
384{
385 int data;
386
387
388
389
390
391 const int input_vals[3][2] = {
392 {0x0c, 0},
393 {0x0d, 0},
394 {0x0e, 1}
395 };
396
397 if (input > 2)
398 return -EINVAL;
399
400 v4l2_dbg(1, debug, sd, "input switched to %s\n", inputs[input]);
401
402 vpx3220_write(sd, 0x33, input_vals[input][0]);
403
404 data = vpx3220_fp_read(sd, 0xf2) & ~(0x0020);
405 if (data < 0)
406 return data;
407
408 vpx3220_fp_write(sd, 0xf2,
409 data | (input_vals[input][1] << 5) | 0x0010);
410
411 udelay(10);
412 return 0;
413}
414
415static int vpx3220_s_stream(struct v4l2_subdev *sd, int enable)
416{
417 v4l2_dbg(1, debug, sd, "s_stream %s\n", enable ? "on" : "off");
418
419 vpx3220_write(sd, 0xf2, (enable ? 0x1b : 0x00));
420 return 0;
421}
422
423static int vpx3220_s_ctrl(struct v4l2_ctrl *ctrl)
424{
425 struct v4l2_subdev *sd = to_sd(ctrl);
426
427 switch (ctrl->id) {
428 case V4L2_CID_BRIGHTNESS:
429 vpx3220_write(sd, 0xe6, ctrl->val);
430 return 0;
431 case V4L2_CID_CONTRAST:
432
433 vpx3220_write(sd, 0xe7, ctrl->val + 192);
434 return 0;
435 case V4L2_CID_SATURATION:
436 vpx3220_fp_write(sd, 0xa0, ctrl->val);
437 return 0;
438 case V4L2_CID_HUE:
439 vpx3220_fp_write(sd, 0x1c, ctrl->val);
440 return 0;
441 }
442 return -EINVAL;
443}
444
445static int vpx3220_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
446{
447 struct vpx3220 *decoder = to_vpx3220(sd);
448 struct i2c_client *client = v4l2_get_subdevdata(sd);
449
450 return v4l2_chip_ident_i2c_client(client, chip, decoder->ident, 0);
451}
452
453
454
455static const struct v4l2_ctrl_ops vpx3220_ctrl_ops = {
456 .s_ctrl = vpx3220_s_ctrl,
457};
458
459static const struct v4l2_subdev_core_ops vpx3220_core_ops = {
460 .g_chip_ident = vpx3220_g_chip_ident,
461 .init = vpx3220_init,
462 .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
463 .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
464 .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
465 .g_ctrl = v4l2_subdev_g_ctrl,
466 .s_ctrl = v4l2_subdev_s_ctrl,
467 .queryctrl = v4l2_subdev_queryctrl,
468 .querymenu = v4l2_subdev_querymenu,
469 .s_std = vpx3220_s_std,
470};
471
472static const struct v4l2_subdev_video_ops vpx3220_video_ops = {
473 .s_routing = vpx3220_s_routing,
474 .s_stream = vpx3220_s_stream,
475 .querystd = vpx3220_querystd,
476 .g_input_status = vpx3220_g_input_status,
477};
478
479static const struct v4l2_subdev_ops vpx3220_ops = {
480 .core = &vpx3220_core_ops,
481 .video = &vpx3220_video_ops,
482};
483
484
485
486
487
488static int vpx3220_probe(struct i2c_client *client,
489 const struct i2c_device_id *id)
490{
491 struct vpx3220 *decoder;
492 struct v4l2_subdev *sd;
493 const char *name = NULL;
494 u8 ver;
495 u16 pn;
496
497
498 if (!i2c_check_functionality(client->adapter,
499 I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
500 return -ENODEV;
501
502 decoder = kzalloc(sizeof(struct vpx3220), GFP_KERNEL);
503 if (decoder == NULL)
504 return -ENOMEM;
505 sd = &decoder->sd;
506 v4l2_i2c_subdev_init(sd, client, &vpx3220_ops);
507 decoder->norm = V4L2_STD_PAL;
508 decoder->input = 0;
509 decoder->enable = 1;
510 v4l2_ctrl_handler_init(&decoder->hdl, 4);
511 v4l2_ctrl_new_std(&decoder->hdl, &vpx3220_ctrl_ops,
512 V4L2_CID_BRIGHTNESS, -128, 127, 1, 0);
513 v4l2_ctrl_new_std(&decoder->hdl, &vpx3220_ctrl_ops,
514 V4L2_CID_CONTRAST, 0, 63, 1, 32);
515 v4l2_ctrl_new_std(&decoder->hdl, &vpx3220_ctrl_ops,
516 V4L2_CID_SATURATION, 0, 4095, 1, 2048);
517 v4l2_ctrl_new_std(&decoder->hdl, &vpx3220_ctrl_ops,
518 V4L2_CID_HUE, -512, 511, 1, 0);
519 sd->ctrl_handler = &decoder->hdl;
520 if (decoder->hdl.error) {
521 int err = decoder->hdl.error;
522
523 v4l2_ctrl_handler_free(&decoder->hdl);
524 kfree(decoder);
525 return err;
526 }
527 v4l2_ctrl_handler_setup(&decoder->hdl);
528
529 ver = i2c_smbus_read_byte_data(client, 0x00);
530 pn = (i2c_smbus_read_byte_data(client, 0x02) << 8) +
531 i2c_smbus_read_byte_data(client, 0x01);
532 decoder->ident = V4L2_IDENT_VPX3220A;
533 if (ver == 0xec) {
534 switch (pn) {
535 case 0x4680:
536 name = "vpx3220a";
537 break;
538 case 0x4260:
539 name = "vpx3216b";
540 decoder->ident = V4L2_IDENT_VPX3216B;
541 break;
542 case 0x4280:
543 name = "vpx3214c";
544 decoder->ident = V4L2_IDENT_VPX3214C;
545 break;
546 }
547 }
548 if (name)
549 v4l2_info(sd, "%s found @ 0x%x (%s)\n", name,
550 client->addr << 1, client->adapter->name);
551 else
552 v4l2_info(sd, "chip (%02x:%04x) found @ 0x%x (%s)\n",
553 ver, pn, client->addr << 1, client->adapter->name);
554
555 vpx3220_write_block(sd, init_common, sizeof(init_common));
556 vpx3220_write_fp_block(sd, init_fp, sizeof(init_fp) >> 1);
557
558 vpx3220_write_fp_block(sd, init_pal, sizeof(init_pal) >> 1);
559 return 0;
560}
561
562static int vpx3220_remove(struct i2c_client *client)
563{
564 struct v4l2_subdev *sd = i2c_get_clientdata(client);
565 struct vpx3220 *decoder = to_vpx3220(sd);
566
567 v4l2_device_unregister_subdev(sd);
568 v4l2_ctrl_handler_free(&decoder->hdl);
569 kfree(decoder);
570 return 0;
571}
572
573static const struct i2c_device_id vpx3220_id[] = {
574 { "vpx3220a", 0 },
575 { "vpx3216b", 0 },
576 { "vpx3214c", 0 },
577 { }
578};
579MODULE_DEVICE_TABLE(i2c, vpx3220_id);
580
581static struct i2c_driver vpx3220_driver = {
582 .driver = {
583 .owner = THIS_MODULE,
584 .name = "vpx3220",
585 },
586 .probe = vpx3220_probe,
587 .remove = vpx3220_remove,
588 .id_table = vpx3220_id,
589};
590
591static __init int init_vpx3220(void)
592{
593 return i2c_add_driver(&vpx3220_driver);
594}
595
596static __exit void exit_vpx3220(void)
597{
598 i2c_del_driver(&vpx3220_driver);
599}
600
601module_init(init_vpx3220);
602module_exit(exit_vpx3220);
603