diff options
author | Hans Verkuil <hans.verkuil@cisco.com> | 2012-05-15 07:07:24 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-05-20 07:30:09 -0400 |
commit | eb8305b159f34abf9ac1349d61b4cf47578b13ab (patch) | |
tree | 767a7070ad44f5cdac0f3ec74fb177e81378971d /drivers/media/video/tvp7002.c | |
parent | f00dc30422d442c6cfbbab3c6e93fe6cb6681621 (diff) |
[media] tvp7002: add support for the new dv timings API
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Reviewed-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/tvp7002.c')
-rw-r--r-- | drivers/media/video/tvp7002.c | 102 |
1 files changed, 89 insertions, 13 deletions
diff --git a/drivers/media/video/tvp7002.c b/drivers/media/video/tvp7002.c index 408b65e782e5..fb6a5b57eb83 100644 --- a/drivers/media/video/tvp7002.c +++ b/drivers/media/video/tvp7002.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
30 | #include <linux/videodev2.h> | 30 | #include <linux/videodev2.h> |
31 | #include <linux/module.h> | 31 | #include <linux/module.h> |
32 | #include <linux/v4l2-dv-timings.h> | ||
32 | #include <media/tvp7002.h> | 33 | #include <media/tvp7002.h> |
33 | #include <media/v4l2-device.h> | 34 | #include <media/v4l2-device.h> |
34 | #include <media/v4l2-chip-ident.h> | 35 | #include <media/v4l2-chip-ident.h> |
@@ -328,6 +329,7 @@ static const struct i2c_reg_value tvp7002_parms_720P50[] = { | |||
328 | /* Preset definition for handling device operation */ | 329 | /* Preset definition for handling device operation */ |
329 | struct tvp7002_preset_definition { | 330 | struct tvp7002_preset_definition { |
330 | u32 preset; | 331 | u32 preset; |
332 | struct v4l2_dv_timings timings; | ||
331 | const struct i2c_reg_value *p_settings; | 333 | const struct i2c_reg_value *p_settings; |
332 | enum v4l2_colorspace color_space; | 334 | enum v4l2_colorspace color_space; |
333 | enum v4l2_field scanmode; | 335 | enum v4l2_field scanmode; |
@@ -341,6 +343,7 @@ struct tvp7002_preset_definition { | |||
341 | static const struct tvp7002_preset_definition tvp7002_presets[] = { | 343 | static const struct tvp7002_preset_definition tvp7002_presets[] = { |
342 | { | 344 | { |
343 | V4L2_DV_720P60, | 345 | V4L2_DV_720P60, |
346 | V4L2_DV_BT_CEA_1280X720P60, | ||
344 | tvp7002_parms_720P60, | 347 | tvp7002_parms_720P60, |
345 | V4L2_COLORSPACE_REC709, | 348 | V4L2_COLORSPACE_REC709, |
346 | V4L2_FIELD_NONE, | 349 | V4L2_FIELD_NONE, |
@@ -351,6 +354,7 @@ static const struct tvp7002_preset_definition tvp7002_presets[] = { | |||
351 | }, | 354 | }, |
352 | { | 355 | { |
353 | V4L2_DV_1080I60, | 356 | V4L2_DV_1080I60, |
357 | V4L2_DV_BT_CEA_1920X1080I60, | ||
354 | tvp7002_parms_1080I60, | 358 | tvp7002_parms_1080I60, |
355 | V4L2_COLORSPACE_REC709, | 359 | V4L2_COLORSPACE_REC709, |
356 | V4L2_FIELD_INTERLACED, | 360 | V4L2_FIELD_INTERLACED, |
@@ -361,6 +365,7 @@ static const struct tvp7002_preset_definition tvp7002_presets[] = { | |||
361 | }, | 365 | }, |
362 | { | 366 | { |
363 | V4L2_DV_1080I50, | 367 | V4L2_DV_1080I50, |
368 | V4L2_DV_BT_CEA_1920X1080I50, | ||
364 | tvp7002_parms_1080I50, | 369 | tvp7002_parms_1080I50, |
365 | V4L2_COLORSPACE_REC709, | 370 | V4L2_COLORSPACE_REC709, |
366 | V4L2_FIELD_INTERLACED, | 371 | V4L2_FIELD_INTERLACED, |
@@ -371,6 +376,7 @@ static const struct tvp7002_preset_definition tvp7002_presets[] = { | |||
371 | }, | 376 | }, |
372 | { | 377 | { |
373 | V4L2_DV_720P50, | 378 | V4L2_DV_720P50, |
379 | V4L2_DV_BT_CEA_1280X720P50, | ||
374 | tvp7002_parms_720P50, | 380 | tvp7002_parms_720P50, |
375 | V4L2_COLORSPACE_REC709, | 381 | V4L2_COLORSPACE_REC709, |
376 | V4L2_FIELD_NONE, | 382 | V4L2_FIELD_NONE, |
@@ -381,6 +387,7 @@ static const struct tvp7002_preset_definition tvp7002_presets[] = { | |||
381 | }, | 387 | }, |
382 | { | 388 | { |
383 | V4L2_DV_1080P60, | 389 | V4L2_DV_1080P60, |
390 | V4L2_DV_BT_CEA_1920X1080P60, | ||
384 | tvp7002_parms_1080P60, | 391 | tvp7002_parms_1080P60, |
385 | V4L2_COLORSPACE_REC709, | 392 | V4L2_COLORSPACE_REC709, |
386 | V4L2_FIELD_NONE, | 393 | V4L2_FIELD_NONE, |
@@ -391,6 +398,7 @@ static const struct tvp7002_preset_definition tvp7002_presets[] = { | |||
391 | }, | 398 | }, |
392 | { | 399 | { |
393 | V4L2_DV_480P59_94, | 400 | V4L2_DV_480P59_94, |
401 | V4L2_DV_BT_CEA_720X480P59_94, | ||
394 | tvp7002_parms_480P, | 402 | tvp7002_parms_480P, |
395 | V4L2_COLORSPACE_SMPTE170M, | 403 | V4L2_COLORSPACE_SMPTE170M, |
396 | V4L2_FIELD_NONE, | 404 | V4L2_FIELD_NONE, |
@@ -401,6 +409,7 @@ static const struct tvp7002_preset_definition tvp7002_presets[] = { | |||
401 | }, | 409 | }, |
402 | { | 410 | { |
403 | V4L2_DV_576P50, | 411 | V4L2_DV_576P50, |
412 | V4L2_DV_BT_CEA_720X576P50, | ||
404 | tvp7002_parms_576P, | 413 | tvp7002_parms_576P, |
405 | V4L2_COLORSPACE_SMPTE170M, | 414 | V4L2_COLORSPACE_SMPTE170M, |
406 | V4L2_FIELD_NONE, | 415 | V4L2_FIELD_NONE, |
@@ -605,6 +614,35 @@ static int tvp7002_s_dv_preset(struct v4l2_subdev *sd, | |||
605 | return -EINVAL; | 614 | return -EINVAL; |
606 | } | 615 | } |
607 | 616 | ||
617 | static int tvp7002_s_dv_timings(struct v4l2_subdev *sd, | ||
618 | struct v4l2_dv_timings *dv_timings) | ||
619 | { | ||
620 | struct tvp7002 *device = to_tvp7002(sd); | ||
621 | const struct v4l2_bt_timings *bt = &dv_timings->bt; | ||
622 | int i; | ||
623 | |||
624 | if (dv_timings->type != V4L2_DV_BT_656_1120) | ||
625 | return -EINVAL; | ||
626 | for (i = 0; i < NUM_PRESETS; i++) { | ||
627 | const struct v4l2_bt_timings *t = &tvp7002_presets[i].timings.bt; | ||
628 | |||
629 | if (!memcmp(bt, t, &bt->standards - &bt->width)) { | ||
630 | device->current_preset = &tvp7002_presets[i]; | ||
631 | return tvp7002_write_inittab(sd, tvp7002_presets[i].p_settings); | ||
632 | } | ||
633 | } | ||
634 | return -EINVAL; | ||
635 | } | ||
636 | |||
637 | static int tvp7002_g_dv_timings(struct v4l2_subdev *sd, | ||
638 | struct v4l2_dv_timings *dv_timings) | ||
639 | { | ||
640 | struct tvp7002 *device = to_tvp7002(sd); | ||
641 | |||
642 | *dv_timings = device->current_preset->timings; | ||
643 | return 0; | ||
644 | } | ||
645 | |||
608 | /* | 646 | /* |
609 | * tvp7002_s_ctrl() - Set a control | 647 | * tvp7002_s_ctrl() - Set a control |
610 | * @ctrl: ptr to v4l2_ctrl struct | 648 | * @ctrl: ptr to v4l2_ctrl struct |
@@ -666,8 +704,7 @@ static int tvp7002_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f | |||
666 | * Returns the current DV preset by TVP7002. If no active input is | 704 | * Returns the current DV preset by TVP7002. If no active input is |
667 | * detected, returns -EINVAL | 705 | * detected, returns -EINVAL |
668 | */ | 706 | */ |
669 | static int tvp7002_query_dv_preset(struct v4l2_subdev *sd, | 707 | static int tvp7002_query_dv(struct v4l2_subdev *sd, int *index) |
670 | struct v4l2_dv_preset *qpreset) | ||
671 | { | 708 | { |
672 | const struct tvp7002_preset_definition *presets = tvp7002_presets; | 709 | const struct tvp7002_preset_definition *presets = tvp7002_presets; |
673 | u8 progressive; | 710 | u8 progressive; |
@@ -678,10 +715,9 @@ static int tvp7002_query_dv_preset(struct v4l2_subdev *sd, | |||
678 | u8 lpf_msb; | 715 | u8 lpf_msb; |
679 | u8 cpl_lsb; | 716 | u8 cpl_lsb; |
680 | u8 cpl_msb; | 717 | u8 cpl_msb; |
681 | int index; | ||
682 | 718 | ||
683 | /* Return invalid preset if no active input is detected */ | 719 | /* Return invalid index if no active input is detected */ |
684 | qpreset->preset = V4L2_DV_INVALID; | 720 | *index = NUM_PRESETS; |
685 | 721 | ||
686 | /* Read standards from device registers */ | 722 | /* Read standards from device registers */ |
687 | tvp7002_read_err(sd, TVP7002_L_FRAME_STAT_LSBS, &lpf_lsb, &error); | 723 | tvp7002_read_err(sd, TVP7002_L_FRAME_STAT_LSBS, &lpf_lsb, &error); |
@@ -702,8 +738,8 @@ static int tvp7002_query_dv_preset(struct v4l2_subdev *sd, | |||
702 | progressive = (lpf_msb & TVP7002_INPR_MASK) >> TVP7002_IP_SHIFT; | 738 | progressive = (lpf_msb & TVP7002_INPR_MASK) >> TVP7002_IP_SHIFT; |
703 | 739 | ||
704 | /* Do checking of video modes */ | 740 | /* Do checking of video modes */ |
705 | for (index = 0; index < NUM_PRESETS; index++, presets++) | 741 | for (*index = 0; *index < NUM_PRESETS; (*index)++, presets++) |
706 | if (lpfr == presets->lines_per_frame && | 742 | if (lpfr == presets->lines_per_frame && |
707 | progressive == presets->progressive) { | 743 | progressive == presets->progressive) { |
708 | if (presets->cpl_min == 0xffff) | 744 | if (presets->cpl_min == 0xffff) |
709 | break; | 745 | break; |
@@ -711,17 +747,42 @@ static int tvp7002_query_dv_preset(struct v4l2_subdev *sd, | |||
711 | break; | 747 | break; |
712 | } | 748 | } |
713 | 749 | ||
714 | if (index == NUM_PRESETS) { | 750 | if (*index == NUM_PRESETS) { |
715 | v4l2_dbg(1, debug, sd, "detection failed: lpf = %x, cpl = %x\n", | 751 | v4l2_dbg(1, debug, sd, "detection failed: lpf = %x, cpl = %x\n", |
716 | lpfr, cpln); | 752 | lpfr, cpln); |
717 | return 0; | 753 | return -ENOLINK; |
718 | } | 754 | } |
719 | 755 | ||
720 | /* Set values in found preset */ | ||
721 | qpreset->preset = presets->preset; | ||
722 | |||
723 | /* Update lines per frame and clocks per line info */ | 756 | /* Update lines per frame and clocks per line info */ |
724 | v4l2_dbg(1, debug, sd, "detected preset: %d\n", presets->preset); | 757 | v4l2_dbg(1, debug, sd, "detected preset: %d\n", *index); |
758 | return 0; | ||
759 | } | ||
760 | |||
761 | static int tvp7002_query_dv_preset(struct v4l2_subdev *sd, | ||
762 | struct v4l2_dv_preset *qpreset) | ||
763 | { | ||
764 | int index; | ||
765 | int err = tvp7002_query_dv(sd, &index); | ||
766 | |||
767 | if (err || index == NUM_PRESETS) { | ||
768 | qpreset->preset = V4L2_DV_INVALID; | ||
769 | if (err == -ENOLINK) | ||
770 | err = 0; | ||
771 | return err; | ||
772 | } | ||
773 | qpreset->preset = tvp7002_presets[index].preset; | ||
774 | return 0; | ||
775 | } | ||
776 | |||
777 | static int tvp7002_query_dv_timings(struct v4l2_subdev *sd, | ||
778 | struct v4l2_dv_timings *timings) | ||
779 | { | ||
780 | int index; | ||
781 | int err = tvp7002_query_dv(sd, &index); | ||
782 | |||
783 | if (err) | ||
784 | return err; | ||
785 | *timings = tvp7002_presets[index].timings; | ||
725 | return 0; | 786 | return 0; |
726 | } | 787 | } |
727 | 788 | ||
@@ -891,6 +952,17 @@ static int tvp7002_enum_dv_presets(struct v4l2_subdev *sd, | |||
891 | return v4l_fill_dv_preset_info(tvp7002_presets[preset->index].preset, preset); | 952 | return v4l_fill_dv_preset_info(tvp7002_presets[preset->index].preset, preset); |
892 | } | 953 | } |
893 | 954 | ||
955 | static int tvp7002_enum_dv_timings(struct v4l2_subdev *sd, | ||
956 | struct v4l2_enum_dv_timings *timings) | ||
957 | { | ||
958 | /* Check requested format index is within range */ | ||
959 | if (timings->index >= NUM_PRESETS) | ||
960 | return -EINVAL; | ||
961 | |||
962 | timings->timings = tvp7002_presets[timings->index].timings; | ||
963 | return 0; | ||
964 | } | ||
965 | |||
894 | static const struct v4l2_ctrl_ops tvp7002_ctrl_ops = { | 966 | static const struct v4l2_ctrl_ops tvp7002_ctrl_ops = { |
895 | .s_ctrl = tvp7002_s_ctrl, | 967 | .s_ctrl = tvp7002_s_ctrl, |
896 | }; | 968 | }; |
@@ -917,6 +989,10 @@ static const struct v4l2_subdev_video_ops tvp7002_video_ops = { | |||
917 | .enum_dv_presets = tvp7002_enum_dv_presets, | 989 | .enum_dv_presets = tvp7002_enum_dv_presets, |
918 | .s_dv_preset = tvp7002_s_dv_preset, | 990 | .s_dv_preset = tvp7002_s_dv_preset, |
919 | .query_dv_preset = tvp7002_query_dv_preset, | 991 | .query_dv_preset = tvp7002_query_dv_preset, |
992 | .g_dv_timings = tvp7002_g_dv_timings, | ||
993 | .s_dv_timings = tvp7002_s_dv_timings, | ||
994 | .enum_dv_timings = tvp7002_enum_dv_timings, | ||
995 | .query_dv_timings = tvp7002_query_dv_timings, | ||
920 | .s_stream = tvp7002_s_stream, | 996 | .s_stream = tvp7002_s_stream, |
921 | .g_mbus_fmt = tvp7002_mbus_fmt, | 997 | .g_mbus_fmt = tvp7002_mbus_fmt, |
922 | .try_mbus_fmt = tvp7002_mbus_fmt, | 998 | .try_mbus_fmt = tvp7002_mbus_fmt, |