提交 6faaa97b 编写于 作者: N Naushir Patuck 提交者: Zheng Zengkai

media: i2c: imx477: Add very long exposure control to the driver

raspberrypi inclusion
category: feature
bugzilla: 50432

--------------------------------

Add support for very long exposures by using the exposure multiplier
register. Userland does not need to pass any additional controls to
enable long exposures, it simply requests a larger vblank to extend the
exposure control range appropriately.

Currently, since hblank is fixed, a maximum of approximately 124 seconds
of exposure time can be used. In a future change, hblank could also be
controlled in userland to give over 200 seconds of exposure time.
Signed-off-by: NNaushir Patuck <naush@raspberrypi.com>
Signed-off-by: NFang Yafen <yafen@iscas.ac.cn>
Signed-off-by: NZheng Zengkai <zhengzengkai@huawei.com>
上级 d268325a
...@@ -44,6 +44,10 @@ ...@@ -44,6 +44,10 @@
#define IMX477_REG_FRAME_LENGTH 0x0340 #define IMX477_REG_FRAME_LENGTH 0x0340
#define IMX477_FRAME_LENGTH_MAX 0xffdc #define IMX477_FRAME_LENGTH_MAX 0xffdc
/* Long exposure multiplier */
#define IMX477_LONG_EXP_SHIFT_MAX 7
#define IMX477_LONG_EXP_SHIFT_REG 0x3100
/* Exposure control */ /* Exposure control */
#define IMX477_REG_EXPOSURE 0x0202 #define IMX477_REG_EXPOSURE 0x0202
#define IMX477_EXPOSURE_OFFSET 22 #define IMX477_EXPOSURE_OFFSET 22
...@@ -1097,6 +1101,9 @@ struct imx477 { ...@@ -1097,6 +1101,9 @@ struct imx477 {
/* Rewrite common registers on stream on? */ /* Rewrite common registers on stream on? */
bool common_regs_written; bool common_regs_written;
/* Current long exposure factor in use. Set through V4L2_CID_VBLANK */
unsigned int long_exp_shift;
}; };
static inline struct imx477 *to_imx477(struct v4l2_subdev *_sd) static inline struct imx477 *to_imx477(struct v4l2_subdev *_sd)
...@@ -1285,13 +1292,33 @@ static void imx477_adjust_exposure_range(struct imx477 *imx477, ...@@ -1285,13 +1292,33 @@ static void imx477_adjust_exposure_range(struct imx477 *imx477,
/* Honour the VBLANK limits when setting exposure. */ /* Honour the VBLANK limits when setting exposure. */
exposure_max = imx477->mode->height + imx477->vblank->val - exposure_max = imx477->mode->height + imx477->vblank->val -
IMX477_EXPOSURE_OFFSET; (IMX477_EXPOSURE_OFFSET << imx477->long_exp_shift);
exposure_def = min(exposure_max, imx477->exposure->val); exposure_def = min(exposure_max, imx477->exposure->val);
__v4l2_ctrl_modify_range(imx477->exposure, imx477->exposure->minimum, __v4l2_ctrl_modify_range(imx477->exposure, imx477->exposure->minimum,
exposure_max, imx477->exposure->step, exposure_max, imx477->exposure->step,
exposure_def); exposure_def);
} }
static int imx477_set_frame_length(struct imx477 *imx477, unsigned int val)
{
int ret = 0;
imx477->long_exp_shift = 0;
while (val > IMX477_FRAME_LENGTH_MAX) {
imx477->long_exp_shift++;
val >>= 1;
}
ret = imx477_write_reg(imx477, IMX477_REG_FRAME_LENGTH,
IMX477_REG_VALUE_16BIT, val);
if (ret)
return ret;
return imx477_write_reg(imx477, IMX477_LONG_EXP_SHIFT_REG,
IMX477_REG_VALUE_08BIT, imx477->long_exp_shift);
}
static int imx477_set_ctrl(struct v4l2_ctrl *ctrl) static int imx477_set_ctrl(struct v4l2_ctrl *ctrl)
{ {
struct imx477 *imx477 = struct imx477 *imx477 =
...@@ -1299,6 +1326,10 @@ static int imx477_set_ctrl(struct v4l2_ctrl *ctrl) ...@@ -1299,6 +1326,10 @@ static int imx477_set_ctrl(struct v4l2_ctrl *ctrl)
struct i2c_client *client = v4l2_get_subdevdata(&imx477->sd); struct i2c_client *client = v4l2_get_subdevdata(&imx477->sd);
int ret = 0; int ret = 0;
/*
* The VBLANK control may change the limits of usable exposure, so check
* and adjust if necessary.
*/
if (ctrl->id == V4L2_CID_VBLANK) if (ctrl->id == V4L2_CID_VBLANK)
imx477_adjust_exposure_range(imx477, ctrl); imx477_adjust_exposure_range(imx477, ctrl);
...@@ -1316,7 +1347,8 @@ static int imx477_set_ctrl(struct v4l2_ctrl *ctrl) ...@@ -1316,7 +1347,8 @@ static int imx477_set_ctrl(struct v4l2_ctrl *ctrl)
break; break;
case V4L2_CID_EXPOSURE: case V4L2_CID_EXPOSURE:
ret = imx477_write_reg(imx477, IMX477_REG_EXPOSURE, ret = imx477_write_reg(imx477, IMX477_REG_EXPOSURE,
IMX477_REG_VALUE_16BIT, ctrl->val); IMX477_REG_VALUE_16BIT, ctrl->val >>
imx477->long_exp_shift);
break; break;
case V4L2_CID_DIGITAL_GAIN: case V4L2_CID_DIGITAL_GAIN:
ret = imx477_write_reg(imx477, IMX477_REG_DIGITAL_GAIN, ret = imx477_write_reg(imx477, IMX477_REG_DIGITAL_GAIN,
...@@ -1350,9 +1382,8 @@ static int imx477_set_ctrl(struct v4l2_ctrl *ctrl) ...@@ -1350,9 +1382,8 @@ static int imx477_set_ctrl(struct v4l2_ctrl *ctrl)
imx477->vflip->val << 1); imx477->vflip->val << 1);
break; break;
case V4L2_CID_VBLANK: case V4L2_CID_VBLANK:
ret = imx477_write_reg(imx477, IMX477_REG_FRAME_LENGTH, ret = imx477_set_frame_length(imx477,
IMX477_REG_VALUE_16BIT, imx477->mode->height + ctrl->val);
imx477->mode->height + ctrl->val);
break; break;
default: default:
dev_info(&client->dev, dev_info(&client->dev,
...@@ -1521,9 +1552,13 @@ static void imx477_set_framing_limits(struct imx477 *imx477) ...@@ -1521,9 +1552,13 @@ static void imx477_set_framing_limits(struct imx477 *imx477)
frm_length_default = frm_length_default =
imx477_get_frame_length(mode, &mode->timeperframe_default); imx477_get_frame_length(mode, &mode->timeperframe_default);
/* Default to no long exposure multiplier. */
imx477->long_exp_shift = 0;
/* Update limits and set FPS to default */ /* Update limits and set FPS to default */
__v4l2_ctrl_modify_range(imx477->vblank, frm_length_min - mode->height, __v4l2_ctrl_modify_range(imx477->vblank, frm_length_min - mode->height,
IMX477_FRAME_LENGTH_MAX - mode->height, ((1 << IMX477_LONG_EXP_SHIFT_MAX) *
IMX477_FRAME_LENGTH_MAX) - mode->height,
1, frm_length_default - mode->height); 1, frm_length_default - mode->height);
/* Setting this will adjust the exposure limits as well. */ /* Setting this will adjust the exposure limits as well. */
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册