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-ctrls.h>
31
32MODULE_DESCRIPTION("vpx3220a/vpx3216b/vpx3214c video decoder driver");
33MODULE_AUTHOR("Laurent Pinchart");
34MODULE_LICENSE("GPL");
35
36static int debug;
37module_param(debug, int, 0);
38MODULE_PARM_DESC(debug, "Debug level (0-1)");
39
40
41#define VPX_TIMEOUT_COUNT 10
42
43
44
45struct vpx3220 {
46 struct v4l2_subdev sd;
47 struct v4l2_ctrl_handler hdl;
48 unsigned char reg[255];
49
50 v4l2_std_id norm;
51 int input;
52 int enable;
53};
54
55static inline struct vpx3220 *to_vpx3220(struct v4l2_subdev *sd)
56{
57 return container_of(sd, struct vpx3220, sd);
58}
59
60static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
61{
62 return &container_of(ctrl->handler, struct vpx3220, hdl)->sd;
63}
64
65static char *inputs[] = { "internal", "composite", "svideo" };
66
67
68
69static inline int vpx3220_write(struct v4l2_subdev *sd, u8 reg, u8 value)
70{
71 struct i2c_client *client = v4l2_get_subdevdata(sd);
72 struct vpx3220 *decoder = i2c_get_clientdata(client);
73
74 decoder->reg[reg] = value;
75 return i2c_smbus_write_byte_data(client, reg, value);
76}
77
78static inline int vpx3220_read(struct v4l2_subdev *sd, u8 reg)
79{
80 struct i2c_client *client = v4l2_get_subdevdata(sd);
81
82 return i2c_smbus_read_byte_data(client, reg);
83}
84
85static int vpx3220_fp_status(struct v4l2_subdev *sd)
86{
87 unsigned char status;
88 unsigned int i;
89
90 for (i = 0; i < VPX_TIMEOUT_COUNT; i++) {
91 status = vpx3220_read(sd, 0x29);
92
93 if (!(status & 4))
94 return 0;
95
96 udelay(10);
97
98 if (need_resched())
99 cond_resched();
100 }
101
102 return -1;
103}
104
105static int vpx3220_fp_write(struct v4l2_subdev *sd, u8 fpaddr, u16 data)
106{
107 struct i2c_client *client = v4l2_get_subdevdata(sd);
108
109
110 if (i2c_smbus_write_word_data(client, 0x27, swab16(fpaddr)) == -1) {
111 v4l2_dbg(1, debug, sd, "%s: failed\n", __func__);
112 return -1;
113 }
114
115 if (vpx3220_fp_status(sd) < 0)
116 return -1;
117
118
119 if (i2c_smbus_write_word_data(client, 0x28, swab16(data)) == -1) {
120 v4l2_dbg(1, debug, sd, "%s: failed\n", __func__);
121 return -1;
122 }
123
124 return 0;
125}
126
127static u16 vpx3220_fp_read(struct v4l2_subdev *sd, u16 fpaddr)
128{
129 struct i2c_client *client = v4l2_get_subdevdata(sd);
130 s16 data;
131
132
133 if (i2c_smbus_write_word_data(client, 0x26, swab16(fpaddr)) == -1) {
134 v4l2_dbg(1, debug, sd, "%s: failed\n", __func__);
135 return -1;
136 }
137
138 if (vpx3220_fp_status(sd) < 0)
139 return -1;
140
141
142 data = i2c_smbus_read_word_data(client, 0x28);
143 if (data == -1) {
144 v4l2_dbg(1, debug, sd, "%s: failed\n", __func__);
145 return -1;
146 }
147
148 return swab16(data);
149}
150
151static int vpx3220_write_block(struct v4l2_subdev *sd, const u8 *data, unsigned int len)
152{
153 u8 reg;
154 int ret = -1;
155
156 while (len >= 2) {
157 reg = *data++;
158 ret = vpx3220_write(sd, reg, *data++);
159 if (ret < 0)
160 break;
161 len -= 2;
162 }
163
164 return ret;
165}
166
167static int vpx3220_write_fp_block(struct v4l2_subdev *sd,
168 const u16 *data, unsigned int len)
169{
170 u8 reg;
171 int ret = 0;
172
173 while (len > 1) {
174 reg = *data++;
175 ret |= vpx3220_fp_write(sd, reg, *data++);
176 len -= 2;
177 }
178
179 return ret;
180}
181
182
183
184static const unsigned short init_ntsc[] = {
185 0x1c, 0x00,
186 0x88, 17,
187 0x89, 240,
188 0x8a, 240,
189 0x8b, 000,
190 0x8c, 640,
191 0x8d, 640,
192 0x8f, 0xc00,
193 0xf0, 0x73,
194
195 0xf2, 0x13,
196 0xe7, 0x1e1,
197
198};
199
200static const unsigned short init_pal[] = {
201 0x88, 23,
202 0x89, 288,
203
204 0x8a, 288,
205
206 0x8b, 16,
207 0x8c, 768,
208 0x8d, 784,
209
210 0x8f, 0xc00,
211 0xf0, 0x77,
212
213 0xf2, 0x3d1,
214 0xe7, 0x241,
215};
216
217static const unsigned short init_secam[] = {
218 0x88, 23,
219 0x89, 288,
220
221 0x8a, 288,
222
223 0x8b, 16,
224 0x8c, 768,
225 0x8d, 784,
226
227 0x8f, 0xc00,
228 0xf0, 0x77,
229
230 0xf2, 0x3d5,
231 0xe7, 0x241,
232};
233
234static const unsigned char init_common[] = {
235 0xf2, 0x00,
236 0x33, 0x0d,
237
238 0xd8, 0xa8,
239
240 0x20, 0x03,
241 0xe0, 0xff,
242 0xe1, 0x00,
243 0xe2, 0x7f,
244 0xe3, 0x80,
245 0xe4, 0x7f,
246 0xe5, 0x80,
247 0xe6, 0x00,
248 0xe7, 0xe0,
249
250 0xe8, 0xf8,
251
252 0xea, 0x18,
253
254 0xf0, 0x8a,
255
256 0xf1, 0x18,
257
258 0xf8, 0x12,
259
260 0xf9, 0x24,
261
262};
263
264static const unsigned short init_fp[] = {
265 0x59, 0,
266 0xa0, 2070,
267 0xa3, 0,
268 0xa4, 0,
269 0xa8, 30,
270 0xb2, 768,
271 0xbe, 27,
272 0x58, 0,
273 0x26, 0,
274 0x4b, 0x298,
275};
276
277
278static int vpx3220_init(struct v4l2_subdev *sd, u32 val)
279{
280 struct vpx3220 *decoder = to_vpx3220(sd);
281
282 vpx3220_write_block(sd, init_common, sizeof(init_common));
283 vpx3220_write_fp_block(sd, init_fp, sizeof(init_fp) >> 1);
284 if (decoder->norm & V4L2_STD_NTSC)
285 vpx3220_write_fp_block(sd, init_ntsc, sizeof(init_ntsc) >> 1);
286 else if (decoder->norm & V4L2_STD_PAL)
287 vpx3220_write_fp_block(sd, init_pal, sizeof(init_pal) >> 1);
288 else if (decoder->norm & V4L2_STD_SECAM)
289 vpx3220_write_fp_block(sd, init_secam, sizeof(init_secam) >> 1);
290 else
291 vpx3220_write_fp_block(sd, init_pal, sizeof(init_pal) >> 1);
292 return 0;
293}
294
295static int vpx3220_status(struct v4l2_subdev *sd, u32 *pstatus, v4l2_std_id *pstd)
296{
297 int res = V4L2_IN_ST_NO_SIGNAL, status;
298 v4l2_std_id std = pstd ? *pstd : V4L2_STD_ALL;
299
300 status = vpx3220_fp_read(sd, 0x0f3);
301
302 v4l2_dbg(1, debug, sd, "status: 0x%04x\n", status);
303
304 if (status < 0)
305 return status;
306
307 if ((status & 0x20) == 0) {
308 res = 0;
309
310 switch (status & 0x18) {
311 case 0x00:
312 case 0x10:
313 case 0x14:
314 case 0x18:
315 std &= V4L2_STD_PAL;
316 break;
317
318 case 0x08:
319 std &= V4L2_STD_SECAM;
320 break;
321
322 case 0x04:
323 case 0x0c:
324 case 0x1c:
325 std &= V4L2_STD_NTSC;
326 break;
327 }
328 } else {
329 std = V4L2_STD_UNKNOWN;
330 }
331 if (pstd)
332 *pstd = std;
333 if (pstatus)
334 *pstatus = res;
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
445
446
447static const struct v4l2_ctrl_ops vpx3220_ctrl_ops = {
448 .s_ctrl = vpx3220_s_ctrl,
449};
450
451static const struct v4l2_subdev_core_ops vpx3220_core_ops = {
452 .init = vpx3220_init,
453};
454
455static const struct v4l2_subdev_video_ops vpx3220_video_ops = {
456 .s_std = vpx3220_s_std,
457 .s_routing = vpx3220_s_routing,
458 .s_stream = vpx3220_s_stream,
459 .querystd = vpx3220_querystd,
460 .g_input_status = vpx3220_g_input_status,
461};
462
463static const struct v4l2_subdev_ops vpx3220_ops = {
464 .core = &vpx3220_core_ops,
465 .video = &vpx3220_video_ops,
466};
467
468
469
470
471
472static int vpx3220_probe(struct i2c_client *client,
473 const struct i2c_device_id *id)
474{
475 struct vpx3220 *decoder;
476 struct v4l2_subdev *sd;
477 const char *name = NULL;
478 u8 ver;
479 u16 pn;
480
481
482 if (!i2c_check_functionality(client->adapter,
483 I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
484 return -ENODEV;
485
486 decoder = devm_kzalloc(&client->dev, sizeof(*decoder), GFP_KERNEL);
487 if (decoder == NULL)
488 return -ENOMEM;
489 sd = &decoder->sd;
490 v4l2_i2c_subdev_init(sd, client, &vpx3220_ops);
491 decoder->norm = V4L2_STD_PAL;
492 decoder->input = 0;
493 decoder->enable = 1;
494 v4l2_ctrl_handler_init(&decoder->hdl, 4);
495 v4l2_ctrl_new_std(&decoder->hdl, &vpx3220_ctrl_ops,
496 V4L2_CID_BRIGHTNESS, -128, 127, 1, 0);
497 v4l2_ctrl_new_std(&decoder->hdl, &vpx3220_ctrl_ops,
498 V4L2_CID_CONTRAST, 0, 63, 1, 32);
499 v4l2_ctrl_new_std(&decoder->hdl, &vpx3220_ctrl_ops,
500 V4L2_CID_SATURATION, 0, 4095, 1, 2048);
501 v4l2_ctrl_new_std(&decoder->hdl, &vpx3220_ctrl_ops,
502 V4L2_CID_HUE, -512, 511, 1, 0);
503 sd->ctrl_handler = &decoder->hdl;
504 if (decoder->hdl.error) {
505 int err = decoder->hdl.error;
506
507 v4l2_ctrl_handler_free(&decoder->hdl);
508 return err;
509 }
510 v4l2_ctrl_handler_setup(&decoder->hdl);
511
512 ver = i2c_smbus_read_byte_data(client, 0x00);
513 pn = (i2c_smbus_read_byte_data(client, 0x02) << 8) +
514 i2c_smbus_read_byte_data(client, 0x01);
515 if (ver == 0xec) {
516 switch (pn) {
517 case 0x4680:
518 name = "vpx3220a";
519 break;
520 case 0x4260:
521 name = "vpx3216b";
522 break;
523 case 0x4280:
524 name = "vpx3214c";
525 break;
526 }
527 }
528 if (name)
529 v4l2_info(sd, "%s found @ 0x%x (%s)\n", name,
530 client->addr << 1, client->adapter->name);
531 else
532 v4l2_info(sd, "chip (%02x:%04x) found @ 0x%x (%s)\n",
533 ver, pn, client->addr << 1, client->adapter->name);
534
535 vpx3220_write_block(sd, init_common, sizeof(init_common));
536 vpx3220_write_fp_block(sd, init_fp, sizeof(init_fp) >> 1);
537
538 vpx3220_write_fp_block(sd, init_pal, sizeof(init_pal) >> 1);
539 return 0;
540}
541
542static int vpx3220_remove(struct i2c_client *client)
543{
544 struct v4l2_subdev *sd = i2c_get_clientdata(client);
545 struct vpx3220 *decoder = to_vpx3220(sd);
546
547 v4l2_device_unregister_subdev(sd);
548 v4l2_ctrl_handler_free(&decoder->hdl);
549
550 return 0;
551}
552
553static const struct i2c_device_id vpx3220_id[] = {
554 { "vpx3220a", 0 },
555 { "vpx3216b", 0 },
556 { "vpx3214c", 0 },
557 { }
558};
559MODULE_DEVICE_TABLE(i2c, vpx3220_id);
560
561static struct i2c_driver vpx3220_driver = {
562 .driver = {
563 .name = "vpx3220",
564 },
565 .probe = vpx3220_probe,
566 .remove = vpx3220_remove,
567 .id_table = vpx3220_id,
568};
569
570module_i2c_driver(vpx3220_driver);
571