From 8cf2f7ad9749980a455d61b5664ccb553c12fd0e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 4 Mar 2013 09:28:57 -0300 Subject: [PATCH] [media] s5p-tv: add dv_timings support for hdmiphy This just adds dv_timings support without modifying existing dv_preset support, although I had to refactor a little bit in order to share hdmiphy_find_conf() between the preset and timings code. Signed-off-by: Hans Verkuil Tested-by: Tomasz Stanislawski Acked-by: Tomasz Stanislawski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-tv/hdmiphy_drv.c | 60 ++++++++++++++++++++++++----- 1 file changed, 51 insertions(+), 9 deletions(-) diff --git a/drivers/media/platform/s5p-tv/hdmiphy_drv.c b/drivers/media/platform/s5p-tv/hdmiphy_drv.c index 80717ce..ef0d812 100644 --- a/drivers/media/platform/s5p-tv/hdmiphy_drv.c +++ b/drivers/media/platform/s5p-tv/hdmiphy_drv.c @@ -197,14 +197,9 @@ static unsigned long hdmiphy_preset_to_pixclk(u32 preset) return 0; } -static const u8 *hdmiphy_find_conf(u32 preset, const struct hdmiphy_conf *conf) +static const u8 *hdmiphy_find_conf(unsigned long pixclk, + 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; @@ -220,15 +215,49 @@ static int hdmiphy_s_power(struct v4l2_subdev *sd, int on) static int hdmiphy_s_dv_preset(struct v4l2_subdev *sd, struct v4l2_dv_preset *preset) { - const u8 *data; + const u8 *data = NULL; u8 buffer[32]; int ret; struct hdmiphy_ctx *ctx = sd_to_ctx(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); + unsigned long pixclk; struct device *dev = &client->dev; dev_info(dev, "s_dv_preset(preset = %d)\n", preset->preset); - data = hdmiphy_find_conf(preset->preset, ctx->conf_tab); + + pixclk = hdmiphy_preset_to_pixclk(preset->preset); + data = hdmiphy_find_conf(pixclk, ctx->conf_tab); + if (!data) { + dev_err(dev, "format not supported\n"); + return -EINVAL; + } + + /* storing configuration to the device */ + memcpy(buffer, data, 32); + ret = i2c_master_send(client, buffer, 32); + if (ret != 32) { + dev_err(dev, "failed to configure HDMIPHY via I2C\n"); + return -EIO; + } + + return 0; +} + +static int hdmiphy_s_dv_timings(struct v4l2_subdev *sd, + struct v4l2_dv_timings *timings) +{ + const u8 *data; + u8 buffer[32]; + int ret; + 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_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 +274,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); @@ -271,6 +311,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, }; -- 2.7.4