aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Verkuil <hans.verkuil@cisco.com>2013-03-04 07:29:33 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2013-03-23 09:59:06 -0400
commit5efb54b2b7bf685f5d2efdf468418e26a74554f2 (patch)
tree15f71e20d57af91258f86cae17bee76e2d473c2d
parent8cf2f7ad9749980a455d61b5664ccb553c12fd0e (diff)
[media] s5p-tv: add dv_timings support for hdmi
This just adds dv_timings support without modifying existing dv_preset support. Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Tested-by: Tomasz Stanislawski <t.stanislaws@samsung.com> Acked-by: Tomasz Stanislawski <t.stanislaws@samsung.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/media/platform/s5p-tv/hdmi_drv.c94
1 files changed, 81 insertions, 13 deletions
diff --git a/drivers/media/platform/s5p-tv/hdmi_drv.c b/drivers/media/platform/s5p-tv/hdmi_drv.c
index 8de1b3dce459..c78f54cd5df9 100644
--- a/drivers/media/platform/s5p-tv/hdmi_drv.c
+++ b/drivers/media/platform/s5p-tv/hdmi_drv.c
@@ -31,6 +31,7 @@
31#include <linux/pm_runtime.h> 31#include <linux/pm_runtime.h>
32#include <linux/clk.h> 32#include <linux/clk.h>
33#include <linux/regulator/consumer.h> 33#include <linux/regulator/consumer.h>
34#include <linux/v4l2-dv-timings.h>
34 35
35#include <media/s5p_hdmi.h> 36#include <media/s5p_hdmi.h>
36#include <media/v4l2-common.h> 37#include <media/v4l2-common.h>
@@ -93,6 +94,8 @@ struct hdmi_device {
93 int cur_conf_dirty; 94 int cur_conf_dirty;
94 /** current preset */ 95 /** current preset */
95 u32 cur_preset; 96 u32 cur_preset;
97 /** current timings */
98 struct v4l2_dv_timings cur_timings;
96 /** other resources */ 99 /** other resources */
97 struct hdmi_resources res; 100 struct hdmi_resources res;
98}; 101};
@@ -477,19 +480,21 @@ static const struct hdmi_timings hdmi_timings_1080p50 = {
477 480
478static const struct { 481static const struct {
479 u32 preset; 482 u32 preset;
480 const struct hdmi_timings *timings; 483 bool reduced_fps;
484 const struct v4l2_dv_timings dv_timings;
485 const struct hdmi_timings *hdmi_timings;
481} hdmi_timings[] = { 486} hdmi_timings[] = {
482 { V4L2_DV_480P59_94, &hdmi_timings_480p }, 487 { V4L2_DV_480P59_94, false, V4L2_DV_BT_CEA_720X480P59_94, &hdmi_timings_480p },
483 { V4L2_DV_576P50, &hdmi_timings_576p50 }, 488 { V4L2_DV_576P50, false, V4L2_DV_BT_CEA_720X576P50, &hdmi_timings_576p50 },
484 { V4L2_DV_720P50, &hdmi_timings_720p50 }, 489 { V4L2_DV_720P50, false, V4L2_DV_BT_CEA_1280X720P50, &hdmi_timings_720p50 },
485 { V4L2_DV_720P59_94, &hdmi_timings_720p60 }, 490 { V4L2_DV_720P59_94, true, V4L2_DV_BT_CEA_1280X720P60, &hdmi_timings_720p60 },
486 { V4L2_DV_720P60, &hdmi_timings_720p60 }, 491 { V4L2_DV_720P60, false, V4L2_DV_BT_CEA_1280X720P60, &hdmi_timings_720p60 },
487 { V4L2_DV_1080P24, &hdmi_timings_1080p24 }, 492 { V4L2_DV_1080P24, false, V4L2_DV_BT_CEA_1920X1080P24, &hdmi_timings_1080p24 },
488 { V4L2_DV_1080P30, &hdmi_timings_1080p60 }, 493 { V4L2_DV_1080P30, false, V4L2_DV_BT_CEA_1920X1080P30, &hdmi_timings_1080p60 },
489 { V4L2_DV_1080P50, &hdmi_timings_1080p50 }, 494 { V4L2_DV_1080P50, false, V4L2_DV_BT_CEA_1920X1080P50, &hdmi_timings_1080p50 },
490 { V4L2_DV_1080I50, &hdmi_timings_1080i50 }, 495 { V4L2_DV_1080I50, false, V4L2_DV_BT_CEA_1920X1080I50, &hdmi_timings_1080i50 },
491 { V4L2_DV_1080I60, &hdmi_timings_1080i60 }, 496 { V4L2_DV_1080I60, false, V4L2_DV_BT_CEA_1920X1080I60, &hdmi_timings_1080i60 },
492 { V4L2_DV_1080P60, &hdmi_timings_1080p60 }, 497 { V4L2_DV_1080P60, false, V4L2_DV_BT_CEA_1920X1080P60, &hdmi_timings_1080p60 },
493}; 498};
494 499
495static const struct hdmi_timings *hdmi_preset2timings(u32 preset) 500static const struct hdmi_timings *hdmi_preset2timings(u32 preset)
@@ -498,7 +503,7 @@ static const struct hdmi_timings *hdmi_preset2timings(u32 preset)
498 503
499 for (i = 0; i < ARRAY_SIZE(hdmi_timings); ++i) 504 for (i = 0; i < ARRAY_SIZE(hdmi_timings); ++i)
500 if (hdmi_timings[i].preset == preset) 505 if (hdmi_timings[i].preset == preset)
501 return hdmi_timings[i].timings; 506 return hdmi_timings[i].hdmi_timings;
502 return NULL; 507 return NULL;
503} 508}
504 509
@@ -647,6 +652,36 @@ static int hdmi_g_dv_preset(struct v4l2_subdev *sd,
647 return 0; 652 return 0;
648} 653}
649 654
655static int hdmi_s_dv_timings(struct v4l2_subdev *sd,
656 struct v4l2_dv_timings *timings)
657{
658 struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
659 struct device *dev = hdev->dev;
660 int i;
661
662 for (i = 0; i < ARRAY_SIZE(hdmi_timings); i++)
663 if (v4l_match_dv_timings(&hdmi_timings[i].dv_timings,
664 timings, 0))
665 break;
666 if (i == ARRAY_SIZE(hdmi_timings)) {
667 dev_err(dev, "timings not supported\n");
668 return -EINVAL;
669 }
670 hdev->cur_conf = hdmi_timings[i].hdmi_timings;
671 hdev->cur_conf_dirty = 1;
672 hdev->cur_timings = *timings;
673 if (!hdmi_timings[i].reduced_fps)
674 hdev->cur_timings.bt.flags &= ~V4L2_DV_FL_CAN_REDUCE_FPS;
675 return 0;
676}
677
678static int hdmi_g_dv_timings(struct v4l2_subdev *sd,
679 struct v4l2_dv_timings *timings)
680{
681 *timings = sd_to_hdmi_dev(sd)->cur_timings;
682 return 0;
683}
684
650static int hdmi_g_mbus_fmt(struct v4l2_subdev *sd, 685static int hdmi_g_mbus_fmt(struct v4l2_subdev *sd,
651 struct v4l2_mbus_framefmt *fmt) 686 struct v4l2_mbus_framefmt *fmt)
652{ 687{
@@ -679,6 +714,35 @@ static int hdmi_enum_dv_presets(struct v4l2_subdev *sd,
679 preset); 714 preset);
680} 715}
681 716
717static int hdmi_enum_dv_timings(struct v4l2_subdev *sd,
718 struct v4l2_enum_dv_timings *timings)
719{
720 if (timings->index >= ARRAY_SIZE(hdmi_timings))
721 return -EINVAL;
722 timings->timings = hdmi_timings[timings->index].dv_timings;
723 if (!hdmi_timings[timings->index].reduced_fps)
724 timings->timings.bt.flags &= ~V4L2_DV_FL_CAN_REDUCE_FPS;
725 return 0;
726}
727
728static int hdmi_dv_timings_cap(struct v4l2_subdev *sd,
729 struct v4l2_dv_timings_cap *cap)
730{
731 struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
732
733 /* Let the phy fill in the pixelclock range */
734 v4l2_subdev_call(hdev->phy_sd, video, dv_timings_cap, cap);
735 cap->type = V4L2_DV_BT_656_1120;
736 cap->bt.min_width = 720;
737 cap->bt.max_width = 1920;
738 cap->bt.min_height = 480;
739 cap->bt.max_height = 1080;
740 cap->bt.standards = V4L2_DV_BT_STD_CEA861;
741 cap->bt.capabilities = V4L2_DV_BT_CAP_INTERLACED |
742 V4L2_DV_BT_CAP_PROGRESSIVE;
743 return 0;
744}
745
682static const struct v4l2_subdev_core_ops hdmi_sd_core_ops = { 746static const struct v4l2_subdev_core_ops hdmi_sd_core_ops = {
683 .s_power = hdmi_s_power, 747 .s_power = hdmi_s_power,
684}; 748};
@@ -687,6 +751,10 @@ static const struct v4l2_subdev_video_ops hdmi_sd_video_ops = {
687 .s_dv_preset = hdmi_s_dv_preset, 751 .s_dv_preset = hdmi_s_dv_preset,
688 .g_dv_preset = hdmi_g_dv_preset, 752 .g_dv_preset = hdmi_g_dv_preset,
689 .enum_dv_presets = hdmi_enum_dv_presets, 753 .enum_dv_presets = hdmi_enum_dv_presets,
754 .s_dv_timings = hdmi_s_dv_timings,
755 .g_dv_timings = hdmi_g_dv_timings,
756 .enum_dv_timings = hdmi_enum_dv_timings,
757 .dv_timings_cap = hdmi_dv_timings_cap,
690 .g_mbus_fmt = hdmi_g_mbus_fmt, 758 .g_mbus_fmt = hdmi_g_mbus_fmt,
691 .s_stream = hdmi_s_stream, 759 .s_stream = hdmi_s_stream,
692}; 760};