diff options
Diffstat (limited to 'drivers/media/video/vpx3220.c')
-rw-r--r-- | drivers/media/video/vpx3220.c | 137 |
1 files changed, 51 insertions, 86 deletions
diff --git a/drivers/media/video/vpx3220.c b/drivers/media/video/vpx3220.c index 91a01b3cdf8c..75301d10a838 100644 --- a/drivers/media/video/vpx3220.c +++ b/drivers/media/video/vpx3220.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/videodev2.h> | 28 | #include <linux/videodev2.h> |
29 | #include <media/v4l2-device.h> | 29 | #include <media/v4l2-device.h> |
30 | #include <media/v4l2-chip-ident.h> | 30 | #include <media/v4l2-chip-ident.h> |
31 | #include <media/v4l2-ctrls.h> | ||
31 | 32 | ||
32 | MODULE_DESCRIPTION("vpx3220a/vpx3216b/vpx3214c video decoder driver"); | 33 | MODULE_DESCRIPTION("vpx3220a/vpx3216b/vpx3214c video decoder driver"); |
33 | MODULE_AUTHOR("Laurent Pinchart"); | 34 | MODULE_AUTHOR("Laurent Pinchart"); |
@@ -44,16 +45,13 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)"); | |||
44 | 45 | ||
45 | struct vpx3220 { | 46 | struct vpx3220 { |
46 | struct v4l2_subdev sd; | 47 | struct v4l2_subdev sd; |
48 | struct v4l2_ctrl_handler hdl; | ||
47 | unsigned char reg[255]; | 49 | unsigned char reg[255]; |
48 | 50 | ||
49 | v4l2_std_id norm; | 51 | v4l2_std_id norm; |
50 | int ident; | 52 | int ident; |
51 | int input; | 53 | int input; |
52 | int enable; | 54 | int enable; |
53 | int bright; | ||
54 | int contrast; | ||
55 | int hue; | ||
56 | int sat; | ||
57 | }; | 55 | }; |
58 | 56 | ||
59 | static inline struct vpx3220 *to_vpx3220(struct v4l2_subdev *sd) | 57 | static inline struct vpx3220 *to_vpx3220(struct v4l2_subdev *sd) |
@@ -61,6 +59,11 @@ static inline struct vpx3220 *to_vpx3220(struct v4l2_subdev *sd) | |||
61 | return container_of(sd, struct vpx3220, sd); | 59 | return container_of(sd, struct vpx3220, sd); |
62 | } | 60 | } |
63 | 61 | ||
62 | static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) | ||
63 | { | ||
64 | return &container_of(ctrl->handler, struct vpx3220, hdl)->sd; | ||
65 | } | ||
66 | |||
64 | static char *inputs[] = { "internal", "composite", "svideo" }; | 67 | static char *inputs[] = { "internal", "composite", "svideo" }; |
65 | 68 | ||
66 | /* ----------------------------------------------------------------------- */ | 69 | /* ----------------------------------------------------------------------- */ |
@@ -417,88 +420,26 @@ static int vpx3220_s_stream(struct v4l2_subdev *sd, int enable) | |||
417 | return 0; | 420 | return 0; |
418 | } | 421 | } |
419 | 422 | ||
420 | static int vpx3220_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) | 423 | static int vpx3220_s_ctrl(struct v4l2_ctrl *ctrl) |
421 | { | ||
422 | switch (qc->id) { | ||
423 | case V4L2_CID_BRIGHTNESS: | ||
424 | v4l2_ctrl_query_fill(qc, -128, 127, 1, 0); | ||
425 | break; | ||
426 | |||
427 | case V4L2_CID_CONTRAST: | ||
428 | v4l2_ctrl_query_fill(qc, 0, 63, 1, 32); | ||
429 | break; | ||
430 | |||
431 | case V4L2_CID_SATURATION: | ||
432 | v4l2_ctrl_query_fill(qc, 0, 4095, 1, 2048); | ||
433 | break; | ||
434 | |||
435 | case V4L2_CID_HUE: | ||
436 | v4l2_ctrl_query_fill(qc, -512, 511, 1, 0); | ||
437 | break; | ||
438 | |||
439 | default: | ||
440 | return -EINVAL; | ||
441 | } | ||
442 | return 0; | ||
443 | } | ||
444 | |||
445 | static int vpx3220_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | ||
446 | { | 424 | { |
447 | struct vpx3220 *decoder = to_vpx3220(sd); | 425 | struct v4l2_subdev *sd = to_sd(ctrl); |
448 | 426 | ||
449 | switch (ctrl->id) { | 427 | switch (ctrl->id) { |
450 | case V4L2_CID_BRIGHTNESS: | 428 | case V4L2_CID_BRIGHTNESS: |
451 | ctrl->value = decoder->bright; | 429 | vpx3220_write(sd, 0xe6, ctrl->val); |
452 | break; | 430 | return 0; |
453 | case V4L2_CID_CONTRAST: | 431 | case V4L2_CID_CONTRAST: |
454 | ctrl->value = decoder->contrast; | 432 | /* Bit 7 and 8 is for noise shaping */ |
455 | break; | 433 | vpx3220_write(sd, 0xe7, ctrl->val + 192); |
434 | return 0; | ||
456 | case V4L2_CID_SATURATION: | 435 | case V4L2_CID_SATURATION: |
457 | ctrl->value = decoder->sat; | 436 | vpx3220_fp_write(sd, 0xa0, ctrl->val); |
458 | break; | 437 | return 0; |
459 | case V4L2_CID_HUE: | 438 | case V4L2_CID_HUE: |
460 | ctrl->value = decoder->hue; | 439 | vpx3220_fp_write(sd, 0x1c, ctrl->val); |
461 | break; | 440 | return 0; |
462 | default: | ||
463 | return -EINVAL; | ||
464 | } | 441 | } |
465 | return 0; | 442 | return -EINVAL; |
466 | } | ||
467 | |||
468 | static int vpx3220_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | ||
469 | { | ||
470 | struct vpx3220 *decoder = to_vpx3220(sd); | ||
471 | |||
472 | switch (ctrl->id) { | ||
473 | case V4L2_CID_BRIGHTNESS: | ||
474 | if (decoder->bright != ctrl->value) { | ||
475 | decoder->bright = ctrl->value; | ||
476 | vpx3220_write(sd, 0xe6, decoder->bright); | ||
477 | } | ||
478 | break; | ||
479 | case V4L2_CID_CONTRAST: | ||
480 | if (decoder->contrast != ctrl->value) { | ||
481 | /* Bit 7 and 8 is for noise shaping */ | ||
482 | decoder->contrast = ctrl->value; | ||
483 | vpx3220_write(sd, 0xe7, decoder->contrast + 192); | ||
484 | } | ||
485 | break; | ||
486 | case V4L2_CID_SATURATION: | ||
487 | if (decoder->sat != ctrl->value) { | ||
488 | decoder->sat = ctrl->value; | ||
489 | vpx3220_fp_write(sd, 0xa0, decoder->sat); | ||
490 | } | ||
491 | break; | ||
492 | case V4L2_CID_HUE: | ||
493 | if (decoder->hue != ctrl->value) { | ||
494 | decoder->hue = ctrl->value; | ||
495 | vpx3220_fp_write(sd, 0x1c, decoder->hue); | ||
496 | } | ||
497 | break; | ||
498 | default: | ||
499 | return -EINVAL; | ||
500 | } | ||
501 | return 0; | ||
502 | } | 443 | } |
503 | 444 | ||
504 | static int vpx3220_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) | 445 | static int vpx3220_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) |
@@ -511,12 +452,20 @@ static int vpx3220_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ide | |||
511 | 452 | ||
512 | /* ----------------------------------------------------------------------- */ | 453 | /* ----------------------------------------------------------------------- */ |
513 | 454 | ||
455 | static const struct v4l2_ctrl_ops vpx3220_ctrl_ops = { | ||
456 | .s_ctrl = vpx3220_s_ctrl, | ||
457 | }; | ||
458 | |||
514 | static const struct v4l2_subdev_core_ops vpx3220_core_ops = { | 459 | static const struct v4l2_subdev_core_ops vpx3220_core_ops = { |
515 | .g_chip_ident = vpx3220_g_chip_ident, | 460 | .g_chip_ident = vpx3220_g_chip_ident, |
516 | .init = vpx3220_init, | 461 | .init = vpx3220_init, |
517 | .g_ctrl = vpx3220_g_ctrl, | 462 | .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, |
518 | .s_ctrl = vpx3220_s_ctrl, | 463 | .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, |
519 | .queryctrl = vpx3220_queryctrl, | 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, | ||
520 | .s_std = vpx3220_s_std, | 469 | .s_std = vpx3220_s_std, |
521 | }; | 470 | }; |
522 | 471 | ||
@@ -558,10 +507,24 @@ static int vpx3220_probe(struct i2c_client *client, | |||
558 | decoder->norm = V4L2_STD_PAL; | 507 | decoder->norm = V4L2_STD_PAL; |
559 | decoder->input = 0; | 508 | decoder->input = 0; |
560 | decoder->enable = 1; | 509 | decoder->enable = 1; |
561 | decoder->bright = 32768; | 510 | v4l2_ctrl_handler_init(&decoder->hdl, 4); |
562 | decoder->contrast = 32768; | 511 | v4l2_ctrl_new_std(&decoder->hdl, &vpx3220_ctrl_ops, |
563 | decoder->hue = 32768; | 512 | V4L2_CID_BRIGHTNESS, -128, 127, 1, 0); |
564 | decoder->sat = 32768; | 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); | ||
565 | 528 | ||
566 | ver = i2c_smbus_read_byte_data(client, 0x00); | 529 | ver = i2c_smbus_read_byte_data(client, 0x00); |
567 | pn = (i2c_smbus_read_byte_data(client, 0x02) << 8) + | 530 | pn = (i2c_smbus_read_byte_data(client, 0x02) << 8) + |
@@ -599,9 +562,11 @@ static int vpx3220_probe(struct i2c_client *client, | |||
599 | static int vpx3220_remove(struct i2c_client *client) | 562 | static int vpx3220_remove(struct i2c_client *client) |
600 | { | 563 | { |
601 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | 564 | struct v4l2_subdev *sd = i2c_get_clientdata(client); |
565 | struct vpx3220 *decoder = to_vpx3220(sd); | ||
602 | 566 | ||
603 | v4l2_device_unregister_subdev(sd); | 567 | v4l2_device_unregister_subdev(sd); |
604 | kfree(to_vpx3220(sd)); | 568 | v4l2_ctrl_handler_free(&decoder->hdl); |
569 | kfree(decoder); | ||
605 | return 0; | 570 | return 0; |
606 | } | 571 | } |
607 | 572 | ||