From 116dc059ca9c6b088afba98dde7b679a97ae7198 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Thu, 11 Jun 2020 14:36:40 +0100 Subject: [PATCH] media: i2c: imx290: Convert HMAX setting into V4L2_CID_HBLANK Userspace needs to know HBLANK if it is to work out exposure times and frame rates, therefore convert it to map onto V4L2_CID_HBLANK Signed-off-by: Dave Stevenson --- drivers/media/i2c/imx290.c | 66 +++++++++++++++++++++++++------------- 1 file changed, 44 insertions(+), 22 deletions(-) --- a/drivers/media/i2c/imx290.c +++ b/drivers/media/i2c/imx290.c @@ -40,6 +40,9 @@ enum imx290_clk_index { #define IMX290_GAIN 0x3014 #define IMX290_HMAX_LOW 0x301c #define IMX290_HMAX_HIGH 0x301d +#define IMX290_HMAX_MIN_2LANE 4400 /* Min of 4400 pixels = 30fps */ +#define IMX290_HMAX_MIN_4LANE 2200 /* Min of 2200 pixels = 60fps */ +#define IMX290_HMAX_MAX 0xffff #define IMX290_PGCTRL 0x308c #define IMX290_PHY_LANE_NUM 0x3407 #define IMX290_CSI_LANE_MODE 0x3443 @@ -82,6 +85,7 @@ struct imx290 { struct regmap *regmap; u8 nlanes; u8 bpp; + u16 hmax_min; struct v4l2_subdev sd; struct media_pad pad; @@ -94,6 +98,7 @@ struct imx290 { struct v4l2_ctrl_handler ctrls; struct v4l2_ctrl *link_freq; struct v4l2_ctrl *pixel_rate; + struct v4l2_ctrl *hblank; struct mutex lock; }; @@ -518,6 +523,26 @@ static int imx290_set_gain(struct imx290 return ret; } +static int imx290_set_hmax(struct imx290 *imx290, u32 val) +{ + u32 hmax = val + imx290->current_mode->width; + int ret; + + ret = imx290_write_reg(imx290, IMX290_HMAX_LOW, (hmax & 0xff)); + if (ret) { + dev_err(imx290->dev, "Error setting HMAX register\n"); + return ret; + } + + ret = imx290_write_reg(imx290, IMX290_HMAX_HIGH, ((hmax >> 8) & 0xff)); + if (ret) { + dev_err(imx290->dev, "Error setting HMAX register\n"); + return ret; + } + + return 0; +} + /* Stop streaming */ static int imx290_stop_streaming(struct imx290 *imx290) { @@ -546,6 +571,9 @@ static int imx290_set_ctrl(struct v4l2_c case V4L2_CID_GAIN: ret = imx290_set_gain(imx290, ctrl->val); break; + case V4L2_CID_HBLANK: + ret = imx290_set_hmax(imx290, ctrl->val); + break; case V4L2_CID_TEST_PATTERN: if (ctrl->val) { imx290_write_reg(imx290, IMX290_BLKLEVEL_LOW, 0x00); @@ -702,6 +730,12 @@ static int imx290_set_fmt(struct v4l2_su if (imx290->pixel_rate) __v4l2_ctrl_s_ctrl_int64(imx290->pixel_rate, imx290_calc_pixel_rate(imx290)); + + if (imx290->hblank) + __v4l2_ctrl_modify_range(imx290->hblank, + imx290->hmax_min - mode->width, + IMX290_HMAX_MAX - mode->width, + 1, mode->hmax - mode->width); } *format = fmt->format; @@ -756,25 +790,6 @@ static int imx290_write_current_format(s return 0; } -static int imx290_set_hmax(struct imx290 *imx290, u32 val) -{ - int ret; - - ret = imx290_write_reg(imx290, IMX290_HMAX_LOW, (val & 0xff)); - if (ret) { - dev_err(imx290->dev, "Error setting HMAX register\n"); - return ret; - } - - ret = imx290_write_reg(imx290, IMX290_HMAX_HIGH, ((val >> 8) & 0xff)); - if (ret) { - dev_err(imx290->dev, "Error setting HMAX register\n"); - return ret; - } - - return 0; -} - /* Start streaming */ static int imx290_start_streaming(struct imx290 *imx290) { @@ -813,9 +828,6 @@ static int imx290_start_streaming(struct dev_err(imx290->dev, "Could not set current mode\n"); return ret; } - ret = imx290_set_hmax(imx290, imx290->current_mode->hmax); - if (ret < 0) - return ret; /* Apply customized values from user */ ret = v4l2_ctrl_handler_setup(imx290->sd.ctrl_handler); @@ -1014,6 +1026,7 @@ static int imx290_probe(struct i2c_clien struct v4l2_fwnode_endpoint ep = { .bus_type = V4L2_MBUS_CSI2_DPHY }; + const struct imx290_mode *mode; struct imx290 *imx290; s64 fq; int ret; @@ -1052,6 +1065,8 @@ static int imx290_probe(struct i2c_clien ret = -EINVAL; goto free_err; } + imx290->hmax_min = (imx290->nlanes == 2) ? IMX290_HMAX_MIN_2LANE : + IMX290_HMAX_MIN_4LANE; dev_dbg(dev, "Using %u data lanes\n", imx290->nlanes); @@ -1126,6 +1141,13 @@ static int imx290_probe(struct i2c_clien v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, V4L2_CID_GAIN, 0, 238, 1, 0); + mode = imx290->current_mode; + imx290->hblank = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, + V4L2_CID_HBLANK, + imx290->hmax_min - mode->width, + IMX290_HMAX_MAX - mode->width, 1, + mode->hmax - mode->width); + imx290->link_freq = v4l2_ctrl_new_int_menu(&imx290->ctrls, &imx290_ctrl_ops, V4L2_CID_LINK_FREQ,