summaryrefslogtreecommitdiff
path: root/drivers/media/platform/s5p-tv
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/platform/s5p-tv')
-rw-r--r--drivers/media/platform/s5p-tv/hdmi_drv.c129
-rw-r--r--drivers/media/platform/s5p-tv/hdmiphy_drv.c55
-rw-r--r--drivers/media/platform/s5p-tv/mixer_video.c52
-rw-r--r--drivers/media/platform/s5p-tv/sii9234_drv.c3
4 files changed, 129 insertions, 110 deletions
diff --git a/drivers/media/platform/s5p-tv/hdmi_drv.c b/drivers/media/platform/s5p-tv/hdmi_drv.c
index 8de1b3d..4e86626 100644
--- a/drivers/media/platform/s5p-tv/hdmi_drv.c
+++ b/drivers/media/platform/s5p-tv/hdmi_drv.c
@@ -31,6 +31,7 @@
#include <linux/pm_runtime.h>
#include <linux/clk.h>
#include <linux/regulator/consumer.h>
+#include <linux/v4l2-dv-timings.h>
#include <media/s5p_hdmi.h>
#include <media/v4l2-common.h>
@@ -43,9 +44,6 @@ MODULE_AUTHOR("Tomasz Stanislawski, <t.stanislaws@samsung.com>");
MODULE_DESCRIPTION("Samsung HDMI");
MODULE_LICENSE("GPL");
-/* default preset configured on probe */
-#define HDMI_DEFAULT_PRESET V4L2_DV_480P59_94
-
struct hdmi_pulse {
u32 beg;
u32 end;
@@ -91,8 +89,8 @@ struct hdmi_device {
const struct hdmi_timings *cur_conf;
/** flag indicating that timings are dirty */
int cur_conf_dirty;
- /** current preset */
- u32 cur_preset;
+ /** current timings */
+ struct v4l2_dv_timings cur_timings;
/** other resources */
struct hdmi_resources res;
};
@@ -252,7 +250,6 @@ static int hdmi_conf_apply(struct hdmi_device *hdmi_dev)
{
struct device *dev = hdmi_dev->dev;
const struct hdmi_timings *conf = hdmi_dev->cur_conf;
- struct v4l2_dv_preset preset;
int ret;
dev_dbg(dev, "%s\n", __func__);
@@ -267,11 +264,11 @@ static int hdmi_conf_apply(struct hdmi_device *hdmi_dev)
hdmi_write_mask(hdmi_dev, HDMI_PHY_RSTOUT, 0, HDMI_PHY_SW_RSTOUT);
mdelay(10);
- /* configure presets */
- preset.preset = hdmi_dev->cur_preset;
- ret = v4l2_subdev_call(hdmi_dev->phy_sd, video, s_dv_preset, &preset);
+ /* configure timings */
+ ret = v4l2_subdev_call(hdmi_dev->phy_sd, video, s_dv_timings,
+ &hdmi_dev->cur_timings);
if (ret) {
- dev_err(dev, "failed to set preset (%u)\n", preset.preset);
+ dev_err(dev, "failed to set timings\n");
return ret;
}
@@ -475,33 +472,26 @@ static const struct hdmi_timings hdmi_timings_1080p50 = {
.vsyn[0] = { .beg = 0 + 4, .end = 5 + 4},
};
+/* default hdmi_timings index of the timings configured on probe */
+#define HDMI_DEFAULT_TIMINGS_IDX (0)
+
static const struct {
- u32 preset;
- const struct hdmi_timings *timings;
+ bool reduced_fps;
+ const struct v4l2_dv_timings dv_timings;
+ const struct hdmi_timings *hdmi_timings;
} hdmi_timings[] = {
- { V4L2_DV_480P59_94, &hdmi_timings_480p },
- { V4L2_DV_576P50, &hdmi_timings_576p50 },
- { V4L2_DV_720P50, &hdmi_timings_720p50 },
- { V4L2_DV_720P59_94, &hdmi_timings_720p60 },
- { V4L2_DV_720P60, &hdmi_timings_720p60 },
- { V4L2_DV_1080P24, &hdmi_timings_1080p24 },
- { V4L2_DV_1080P30, &hdmi_timings_1080p60 },
- { V4L2_DV_1080P50, &hdmi_timings_1080p50 },
- { V4L2_DV_1080I50, &hdmi_timings_1080i50 },
- { V4L2_DV_1080I60, &hdmi_timings_1080i60 },
- { V4L2_DV_1080P60, &hdmi_timings_1080p60 },
+ { false, V4L2_DV_BT_CEA_720X480P59_94, &hdmi_timings_480p },
+ { false, V4L2_DV_BT_CEA_720X576P50, &hdmi_timings_576p50 },
+ { false, V4L2_DV_BT_CEA_1280X720P50, &hdmi_timings_720p50 },
+ { true, V4L2_DV_BT_CEA_1280X720P60, &hdmi_timings_720p60 },
+ { false, V4L2_DV_BT_CEA_1920X1080P24, &hdmi_timings_1080p24 },
+ { false, V4L2_DV_BT_CEA_1920X1080P30, &hdmi_timings_1080p60 },
+ { false, V4L2_DV_BT_CEA_1920X1080P50, &hdmi_timings_1080p50 },
+ { false, V4L2_DV_BT_CEA_1920X1080I50, &hdmi_timings_1080i50 },
+ { false, V4L2_DV_BT_CEA_1920X1080I60, &hdmi_timings_1080i60 },
+ { false, V4L2_DV_BT_CEA_1920X1080P60, &hdmi_timings_1080p60 },
};
-static const struct hdmi_timings *hdmi_preset2timings(u32 preset)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(hdmi_timings); ++i)
- if (hdmi_timings[i].preset == preset)
- return hdmi_timings[i].timings;
- return NULL;
-}
-
static int hdmi_streamon(struct hdmi_device *hdev)
{
struct device *dev = hdev->dev;
@@ -621,29 +611,33 @@ static int hdmi_s_power(struct v4l2_subdev *sd, int on)
return IS_ERR_VALUE(ret) ? ret : 0;
}
-static int hdmi_s_dv_preset(struct v4l2_subdev *sd,
- struct v4l2_dv_preset *preset)
+static int hdmi_s_dv_timings(struct v4l2_subdev *sd,
+ struct v4l2_dv_timings *timings)
{
struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
struct device *dev = hdev->dev;
- const struct hdmi_timings *conf;
+ int i;
- conf = hdmi_preset2timings(preset->preset);
- if (conf == NULL) {
- dev_err(dev, "preset (%u) not supported\n", preset->preset);
+ for (i = 0; i < ARRAY_SIZE(hdmi_timings); i++)
+ if (v4l_match_dv_timings(&hdmi_timings[i].dv_timings,
+ timings, 0))
+ break;
+ if (i == ARRAY_SIZE(hdmi_timings)) {
+ dev_err(dev, "timings not supported\n");
return -EINVAL;
}
- hdev->cur_conf = conf;
+ hdev->cur_conf = hdmi_timings[i].hdmi_timings;
hdev->cur_conf_dirty = 1;
- hdev->cur_preset = preset->preset;
+ hdev->cur_timings = *timings;
+ if (!hdmi_timings[i].reduced_fps)
+ hdev->cur_timings.bt.flags &= ~V4L2_DV_FL_CAN_REDUCE_FPS;
return 0;
}
-static int hdmi_g_dv_preset(struct v4l2_subdev *sd,
- struct v4l2_dv_preset *preset)
+static int hdmi_g_dv_timings(struct v4l2_subdev *sd,
+ struct v4l2_dv_timings *timings)
{
- memset(preset, 0, sizeof(*preset));
- preset->preset = sd_to_hdmi_dev(sd)->cur_preset;
+ *timings = sd_to_hdmi_dev(sd)->cur_timings;
return 0;
}
@@ -670,13 +664,33 @@ static int hdmi_g_mbus_fmt(struct v4l2_subdev *sd,
return 0;
}
-static int hdmi_enum_dv_presets(struct v4l2_subdev *sd,
- struct v4l2_dv_enum_preset *preset)
+static int hdmi_enum_dv_timings(struct v4l2_subdev *sd,
+ struct v4l2_enum_dv_timings *timings)
{
- if (preset->index >= ARRAY_SIZE(hdmi_timings))
+ if (timings->index >= ARRAY_SIZE(hdmi_timings))
return -EINVAL;
- return v4l_fill_dv_preset_info(hdmi_timings[preset->index].preset,
- preset);
+ timings->timings = hdmi_timings[timings->index].dv_timings;
+ if (!hdmi_timings[timings->index].reduced_fps)
+ timings->timings.bt.flags &= ~V4L2_DV_FL_CAN_REDUCE_FPS;
+ return 0;
+}
+
+static int hdmi_dv_timings_cap(struct v4l2_subdev *sd,
+ struct v4l2_dv_timings_cap *cap)
+{
+ struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
+
+ /* Let the phy fill in the pixelclock range */
+ v4l2_subdev_call(hdev->phy_sd, video, dv_timings_cap, cap);
+ cap->type = V4L2_DV_BT_656_1120;
+ cap->bt.min_width = 720;
+ cap->bt.max_width = 1920;
+ cap->bt.min_height = 480;
+ cap->bt.max_height = 1080;
+ cap->bt.standards = V4L2_DV_BT_STD_CEA861;
+ cap->bt.capabilities = V4L2_DV_BT_CAP_INTERLACED |
+ V4L2_DV_BT_CAP_PROGRESSIVE;
+ return 0;
}
static const struct v4l2_subdev_core_ops hdmi_sd_core_ops = {
@@ -684,9 +698,10 @@ static const struct v4l2_subdev_core_ops hdmi_sd_core_ops = {
};
static const struct v4l2_subdev_video_ops hdmi_sd_video_ops = {
- .s_dv_preset = hdmi_s_dv_preset,
- .g_dv_preset = hdmi_g_dv_preset,
- .enum_dv_presets = hdmi_enum_dv_presets,
+ .s_dv_timings = hdmi_s_dv_timings,
+ .g_dv_timings = hdmi_g_dv_timings,
+ .enum_dv_timings = hdmi_enum_dv_timings,
+ .dv_timings_cap = hdmi_dv_timings_cap,
.g_mbus_fmt = hdmi_g_mbus_fmt,
.s_stream = hdmi_s_stream,
};
@@ -956,9 +971,11 @@ static int hdmi_probe(struct platform_device *pdev)
sd->owner = THIS_MODULE;
strlcpy(sd->name, "s5p-hdmi", sizeof(sd->name));
- hdmi_dev->cur_preset = HDMI_DEFAULT_PRESET;
- /* FIXME: missing fail preset is not supported */
- hdmi_dev->cur_conf = hdmi_preset2timings(hdmi_dev->cur_preset);
+ hdmi_dev->cur_timings =
+ hdmi_timings[HDMI_DEFAULT_TIMINGS_IDX].dv_timings;
+ /* FIXME: missing fail timings is not supported */
+ hdmi_dev->cur_conf =
+ hdmi_timings[HDMI_DEFAULT_TIMINGS_IDX].hdmi_timings;
hdmi_dev->cur_conf_dirty = 1;
/* storing subdev for call that have only access to struct device */
diff --git a/drivers/media/platform/s5p-tv/hdmiphy_drv.c b/drivers/media/platform/s5p-tv/hdmiphy_drv.c
index 80717ce..e19a0af 100644
--- a/drivers/media/platform/s5p-tv/hdmiphy_drv.c
+++ b/drivers/media/platform/s5p-tv/hdmiphy_drv.c
@@ -176,35 +176,9 @@ static inline struct hdmiphy_ctx *sd_to_ctx(struct v4l2_subdev *sd)
return container_of(sd, struct hdmiphy_ctx, sd);
}
-static unsigned long hdmiphy_preset_to_pixclk(u32 preset)
+static const u8 *hdmiphy_find_conf(unsigned long pixclk,
+ const struct hdmiphy_conf *conf)
{
- static const unsigned long pixclk[] = {
- [V4L2_DV_480P59_94] = 27000000,
- [V4L2_DV_576P50] = 27000000,
- [V4L2_DV_720P59_94] = 74176000,
- [V4L2_DV_720P50] = 74250000,
- [V4L2_DV_720P60] = 74250000,
- [V4L2_DV_1080P24] = 74250000,
- [V4L2_DV_1080P30] = 74250000,
- [V4L2_DV_1080I50] = 74250000,
- [V4L2_DV_1080I60] = 74250000,
- [V4L2_DV_1080P50] = 148500000,
- [V4L2_DV_1080P60] = 148500000,
- };
- if (preset < ARRAY_SIZE(pixclk))
- return pixclk[preset];
- else
- return 0;
-}
-
-static const u8 *hdmiphy_find_conf(u32 preset, const struct hdmiphy_conf *conf)
-{
- unsigned long pixclk;
-
- pixclk = hdmiphy_preset_to_pixclk(preset);
- if (!pixclk)
- return NULL;
-
for (; conf->pixclk; ++conf)
if (conf->pixclk == pixclk)
return conf->data;
@@ -217,8 +191,8 @@ static int hdmiphy_s_power(struct v4l2_subdev *sd, int on)
return 0;
}
-static int hdmiphy_s_dv_preset(struct v4l2_subdev *sd,
- struct v4l2_dv_preset *preset)
+static int hdmiphy_s_dv_timings(struct v4l2_subdev *sd,
+ struct v4l2_dv_timings *timings)
{
const u8 *data;
u8 buffer[32];
@@ -226,9 +200,12 @@ static int hdmiphy_s_dv_preset(struct v4l2_subdev *sd,
struct hdmiphy_ctx *ctx = sd_to_ctx(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct device *dev = &client->dev;
+ unsigned long pixclk = timings->bt.pixelclock;
- dev_info(dev, "s_dv_preset(preset = %d)\n", preset->preset);
- data = hdmiphy_find_conf(preset->preset, ctx->conf_tab);
+ dev_info(dev, "s_dv_timings\n");
+ if ((timings->bt.flags & V4L2_DV_FL_REDUCED_FPS) && pixclk == 74250000)
+ pixclk = 74176000;
+ data = hdmiphy_find_conf(pixclk, ctx->conf_tab);
if (!data) {
dev_err(dev, "format not supported\n");
return -EINVAL;
@@ -245,6 +222,17 @@ static int hdmiphy_s_dv_preset(struct v4l2_subdev *sd,
return 0;
}
+static int hdmiphy_dv_timings_cap(struct v4l2_subdev *sd,
+ struct v4l2_dv_timings_cap *cap)
+{
+ cap->type = V4L2_DV_BT_656_1120;
+ /* The phy only determines the pixelclock, leave the other values
+ * at 0 to signify that we have no information for them. */
+ cap->bt.min_pixelclock = 27000000;
+ cap->bt.max_pixelclock = 148500000;
+ return 0;
+}
+
static int hdmiphy_s_stream(struct v4l2_subdev *sd, int enable)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -270,7 +258,8 @@ static const struct v4l2_subdev_core_ops hdmiphy_core_ops = {
};
static const struct v4l2_subdev_video_ops hdmiphy_video_ops = {
- .s_dv_preset = hdmiphy_s_dv_preset,
+ .s_dv_timings = hdmiphy_s_dv_timings,
+ .dv_timings_cap = hdmiphy_dv_timings_cap,
.s_stream = hdmiphy_s_stream,
};
diff --git a/drivers/media/platform/s5p-tv/mixer_video.c b/drivers/media/platform/s5p-tv/mixer_video.c
index 82142a2..ef0efdf 100644
--- a/drivers/media/platform/s5p-tv/mixer_video.c
+++ b/drivers/media/platform/s5p-tv/mixer_video.c
@@ -501,8 +501,8 @@ fail:
return -ERANGE;
}
-static int mxr_enum_dv_presets(struct file *file, void *fh,
- struct v4l2_dv_enum_preset *preset)
+static int mxr_enum_dv_timings(struct file *file, void *fh,
+ struct v4l2_enum_dv_timings *timings)
{
struct mxr_layer *layer = video_drvdata(file);
struct mxr_device *mdev = layer->mdev;
@@ -510,14 +510,14 @@ static int mxr_enum_dv_presets(struct file *file, void *fh,
/* lock protects from changing sd_out */
mutex_lock(&mdev->mutex);
- ret = v4l2_subdev_call(to_outsd(mdev), video, enum_dv_presets, preset);
+ ret = v4l2_subdev_call(to_outsd(mdev), video, enum_dv_timings, timings);
mutex_unlock(&mdev->mutex);
return ret ? -EINVAL : 0;
}
-static int mxr_s_dv_preset(struct file *file, void *fh,
- struct v4l2_dv_preset *preset)
+static int mxr_s_dv_timings(struct file *file, void *fh,
+ struct v4l2_dv_timings *timings)
{
struct mxr_layer *layer = video_drvdata(file);
struct mxr_device *mdev = layer->mdev;
@@ -526,7 +526,7 @@ static int mxr_s_dv_preset(struct file *file, void *fh,
/* lock protects from changing sd_out */
mutex_lock(&mdev->mutex);
- /* preset change cannot be done while there is an entity
+ /* timings change cannot be done while there is an entity
* dependant on output configuration
*/
if (mdev->n_output > 0) {
@@ -534,7 +534,7 @@ static int mxr_s_dv_preset(struct file *file, void *fh,
return -EBUSY;
}
- ret = v4l2_subdev_call(to_outsd(mdev), video, s_dv_preset, preset);
+ ret = v4l2_subdev_call(to_outsd(mdev), video, s_dv_timings, timings);
mutex_unlock(&mdev->mutex);
@@ -544,8 +544,8 @@ static int mxr_s_dv_preset(struct file *file, void *fh,
return ret ? -EINVAL : 0;
}
-static int mxr_g_dv_preset(struct file *file, void *fh,
- struct v4l2_dv_preset *preset)
+static int mxr_g_dv_timings(struct file *file, void *fh,
+ struct v4l2_dv_timings *timings)
{
struct mxr_layer *layer = video_drvdata(file);
struct mxr_device *mdev = layer->mdev;
@@ -553,13 +553,28 @@ static int mxr_g_dv_preset(struct file *file, void *fh,
/* lock protects from changing sd_out */
mutex_lock(&mdev->mutex);
- ret = v4l2_subdev_call(to_outsd(mdev), video, g_dv_preset, preset);
+ ret = v4l2_subdev_call(to_outsd(mdev), video, g_dv_timings, timings);
mutex_unlock(&mdev->mutex);
return ret ? -EINVAL : 0;
}
-static int mxr_s_std(struct file *file, void *fh, v4l2_std_id *norm)
+static int mxr_dv_timings_cap(struct file *file, void *fh,
+ struct v4l2_dv_timings_cap *cap)
+{
+ struct mxr_layer *layer = video_drvdata(file);
+ struct mxr_device *mdev = layer->mdev;
+ int ret;
+
+ /* lock protects from changing sd_out */
+ mutex_lock(&mdev->mutex);
+ ret = v4l2_subdev_call(to_outsd(mdev), video, dv_timings_cap, cap);
+ mutex_unlock(&mdev->mutex);
+
+ return ret ? -EINVAL : 0;
+}
+
+static int mxr_s_std(struct file *file, void *fh, v4l2_std_id norm)
{
struct mxr_layer *layer = video_drvdata(file);
struct mxr_device *mdev = layer->mdev;
@@ -576,7 +591,7 @@ static int mxr_s_std(struct file *file, void *fh, v4l2_std_id *norm)
return -EBUSY;
}
- ret = v4l2_subdev_call(to_outsd(mdev), video, s_std_output, *norm);
+ ret = v4l2_subdev_call(to_outsd(mdev), video, s_std_output, norm);
mutex_unlock(&mdev->mutex);
@@ -616,8 +631,8 @@ static int mxr_enum_output(struct file *file, void *fh, struct v4l2_output *a)
/* try to obtain supported tv norms */
v4l2_subdev_call(sd, video, g_tvnorms_output, &a->std);
a->capabilities = 0;
- if (sd->ops->video && sd->ops->video->s_dv_preset)
- a->capabilities |= V4L2_OUT_CAP_PRESETS;
+ if (sd->ops->video && sd->ops->video->s_dv_timings)
+ a->capabilities |= V4L2_OUT_CAP_DV_TIMINGS;
if (sd->ops->video && sd->ops->video->s_std_output)
a->capabilities |= V4L2_OUT_CAP_STD;
a->type = V4L2_OUTPUT_TYPE_ANALOG;
@@ -738,10 +753,11 @@ static const struct v4l2_ioctl_ops mxr_ioctl_ops = {
/* Streaming control */
.vidioc_streamon = mxr_streamon,
.vidioc_streamoff = mxr_streamoff,
- /* Preset functions */
- .vidioc_enum_dv_presets = mxr_enum_dv_presets,
- .vidioc_s_dv_preset = mxr_s_dv_preset,
- .vidioc_g_dv_preset = mxr_g_dv_preset,
+ /* DV Timings functions */
+ .vidioc_enum_dv_timings = mxr_enum_dv_timings,
+ .vidioc_s_dv_timings = mxr_s_dv_timings,
+ .vidioc_g_dv_timings = mxr_g_dv_timings,
+ .vidioc_dv_timings_cap = mxr_dv_timings_cap,
/* analog TV standard functions */
.vidioc_s_std = mxr_s_std,
.vidioc_g_std = mxr_g_std,
diff --git a/drivers/media/platform/s5p-tv/sii9234_drv.c b/drivers/media/platform/s5p-tv/sii9234_drv.c
index d90d228..39b77d2 100644
--- a/drivers/media/platform/s5p-tv/sii9234_drv.c
+++ b/drivers/media/platform/s5p-tv/sii9234_drv.c
@@ -23,9 +23,6 @@
#include <linux/regulator/machine.h>
#include <linux/slab.h>
-#include <mach/gpio.h>
-#include <plat/gpio-cfg.h>
-
#include <media/sii9234.h>
#include <media/v4l2-subdev.h>