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