Commit 81ea4829 authored by Markus Pargmann's avatar Markus Pargmann Committed by Mauro Carvalho Chehab

[media] v4l: mt9v032: Add V4L2 controls for AEC and AGC

This patch adds V4L2 controls for Auto Exposure Control and Auto Gain
Control settings. These settings include low pass filter, update
frequency of these settings and the update interval for those units.

[Avoid forward declarations]
[Fix 80 columns limit violation]
[Rename controls to avoid underscores in names]
[Fix the AEC maximum shutter width on MT9V032]
Signed-off-by: default avatarMarkus Pargmann <mpa@pengutronix.de>
Signed-off-by: default avatarLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@s-opensource.com>
parent 78060d51
......@@ -132,9 +132,16 @@
#define MT9V032_TEST_PATTERN_GRAY_DIAGONAL (3 << 11)
#define MT9V032_TEST_PATTERN_ENABLE (1 << 13)
#define MT9V032_TEST_PATTERN_FLIP (1 << 14)
#define MT9V032_AEGC_DESIRED_BIN 0xa5
#define MT9V032_AEC_UPDATE_FREQUENCY 0xa6
#define MT9V032_AEC_LPF 0xa8
#define MT9V032_AGC_UPDATE_FREQUENCY 0xa9
#define MT9V032_AGC_LPF 0xaa
#define MT9V032_AEC_AGC_ENABLE 0xaf
#define MT9V032_AEC_ENABLE (1 << 0)
#define MT9V032_AGC_ENABLE (1 << 1)
#define MT9V034_AEC_MAX_SHUTTER_WIDTH 0xad
#define MT9V032_AEC_MAX_SHUTTER_WIDTH 0xbd
#define MT9V032_THERMAL_INFO 0xc1
enum mt9v032_model {
......@@ -161,6 +168,8 @@ struct mt9v032_model_data {
unsigned int min_shutter;
unsigned int max_shutter;
unsigned int pclk_reg;
unsigned int aec_max_shutter_reg;
const struct v4l2_ctrl_config * const aec_max_shutter_v4l2_ctrl;
};
struct mt9v032_model_info {
......@@ -174,63 +183,6 @@ static const struct mt9v032_model_version mt9v032_versions[] = {
{ MT9V034_CHIP_ID_REV1, "MT9V024/MT9V034 rev1" },
};
static const struct mt9v032_model_data mt9v032_model_data[] = {
{
/* MT9V022, MT9V032 revisions 1/2/3 */
.min_row_time = 660,
.min_hblank = MT9V032_HORIZONTAL_BLANKING_MIN,
.min_vblank = MT9V032_VERTICAL_BLANKING_MIN,
.max_vblank = MT9V032_VERTICAL_BLANKING_MAX,
.min_shutter = MT9V032_TOTAL_SHUTTER_WIDTH_MIN,
.max_shutter = MT9V032_TOTAL_SHUTTER_WIDTH_MAX,
.pclk_reg = MT9V032_PIXEL_CLOCK,
}, {
/* MT9V024, MT9V034 */
.min_row_time = 690,
.min_hblank = MT9V034_HORIZONTAL_BLANKING_MIN,
.min_vblank = MT9V034_VERTICAL_BLANKING_MIN,
.max_vblank = MT9V034_VERTICAL_BLANKING_MAX,
.min_shutter = MT9V034_TOTAL_SHUTTER_WIDTH_MIN,
.max_shutter = MT9V034_TOTAL_SHUTTER_WIDTH_MAX,
.pclk_reg = MT9V034_PIXEL_CLOCK,
},
};
static const struct mt9v032_model_info mt9v032_models[] = {
[MT9V032_MODEL_V022_COLOR] = {
.data = &mt9v032_model_data[0],
.color = true,
},
[MT9V032_MODEL_V022_MONO] = {
.data = &mt9v032_model_data[0],
.color = false,
},
[MT9V032_MODEL_V024_COLOR] = {
.data = &mt9v032_model_data[1],
.color = true,
},
[MT9V032_MODEL_V024_MONO] = {
.data = &mt9v032_model_data[1],
.color = false,
},
[MT9V032_MODEL_V032_COLOR] = {
.data = &mt9v032_model_data[0],
.color = true,
},
[MT9V032_MODEL_V032_MONO] = {
.data = &mt9v032_model_data[0],
.color = false,
},
[MT9V032_MODEL_V034_COLOR] = {
.data = &mt9v032_model_data[1],
.color = true,
},
[MT9V032_MODEL_V034_MONO] = {
.data = &mt9v032_model_data[1],
.color = false,
},
};
struct mt9v032 {
struct v4l2_subdev subdev;
struct media_pad pad;
......@@ -646,6 +598,34 @@ static int mt9v032_set_selection(struct v4l2_subdev *subdev,
*/
#define V4L2_CID_TEST_PATTERN_COLOR (V4L2_CID_USER_BASE | 0x1001)
/*
* Value between 1 and 64 to set the desired bin. This is effectively a measure
* of how bright the image is supposed to be. Both AGC and AEC try to reach
* this.
*/
#define V4L2_CID_AEGC_DESIRED_BIN (V4L2_CID_USER_BASE | 0x1002)
/*
* LPF is the low pass filter capability of the chip. Both AEC and AGC have
* this setting. This limits the speed in which AGC/AEC adjust their settings.
* Possible values are 0-2. 0 means no LPF. For 1 and 2 this equation is used:
*
* if |(calculated new exp - current exp)| > (current exp / 4)
* next exp = calculated new exp
* else
* next exp = current exp + ((calculated new exp - current exp) / 2^LPF)
*/
#define V4L2_CID_AEC_LPF (V4L2_CID_USER_BASE | 0x1003)
#define V4L2_CID_AGC_LPF (V4L2_CID_USER_BASE | 0x1004)
/*
* Value between 0 and 15. This is the number of frames being skipped before
* updating the auto exposure/gain.
*/
#define V4L2_CID_AEC_UPDATE_INTERVAL (V4L2_CID_USER_BASE | 0x1005)
#define V4L2_CID_AGC_UPDATE_INTERVAL (V4L2_CID_USER_BASE | 0x1006)
/*
* Maximum shutter width used for AEC.
*/
#define V4L2_CID_AEC_MAX_SHUTTER_WIDTH (V4L2_CID_USER_BASE | 0x1007)
static int mt9v032_s_ctrl(struct v4l2_ctrl *ctrl)
{
......@@ -715,6 +695,28 @@ static int mt9v032_s_ctrl(struct v4l2_ctrl *ctrl)
break;
}
return regmap_write(map, MT9V032_TEST_PATTERN, data);
case V4L2_CID_AEGC_DESIRED_BIN:
return regmap_write(map, MT9V032_AEGC_DESIRED_BIN, ctrl->val);
case V4L2_CID_AEC_LPF:
return regmap_write(map, MT9V032_AEC_LPF, ctrl->val);
case V4L2_CID_AGC_LPF:
return regmap_write(map, MT9V032_AGC_LPF, ctrl->val);
case V4L2_CID_AEC_UPDATE_INTERVAL:
return regmap_write(map, MT9V032_AEC_UPDATE_FREQUENCY,
ctrl->val);
case V4L2_CID_AGC_UPDATE_INTERVAL:
return regmap_write(map, MT9V032_AGC_UPDATE_FREQUENCY,
ctrl->val);
case V4L2_CID_AEC_MAX_SHUTTER_WIDTH:
return regmap_write(map,
mt9v032->model->data->aec_max_shutter_reg,
ctrl->val);
}
return 0;
......@@ -744,6 +746,84 @@ static const struct v4l2_ctrl_config mt9v032_test_pattern_color = {
.flags = 0,
};
static const struct v4l2_ctrl_config mt9v032_aegc_controls[] = {
{
.ops = &mt9v032_ctrl_ops,
.id = V4L2_CID_AEGC_DESIRED_BIN,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "AEC/AGC Desired Bin",
.min = 1,
.max = 64,
.step = 1,
.def = 58,
.flags = 0,
}, {
.ops = &mt9v032_ctrl_ops,
.id = V4L2_CID_AEC_LPF,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "AEC Low Pass Filter",
.min = 0,
.max = 2,
.step = 1,
.def = 0,
.flags = 0,
}, {
.ops = &mt9v032_ctrl_ops,
.id = V4L2_CID_AGC_LPF,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "AGC Low Pass Filter",
.min = 0,
.max = 2,
.step = 1,
.def = 2,
.flags = 0,
}, {
.ops = &mt9v032_ctrl_ops,
.id = V4L2_CID_AEC_UPDATE_INTERVAL,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "AEC Update Interval",
.min = 0,
.max = 16,
.step = 1,
.def = 2,
.flags = 0,
}, {
.ops = &mt9v032_ctrl_ops,
.id = V4L2_CID_AGC_UPDATE_INTERVAL,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "AGC Update Interval",
.min = 0,
.max = 16,
.step = 1,
.def = 2,
.flags = 0,
}
};
static const struct v4l2_ctrl_config mt9v032_aec_max_shutter_width = {
.ops = &mt9v032_ctrl_ops,
.id = V4L2_CID_AEC_MAX_SHUTTER_WIDTH,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "AEC Max Shutter Width",
.min = 1,
.max = 2047,
.step = 1,
.def = 480,
.flags = 0,
};
static const struct v4l2_ctrl_config mt9v034_aec_max_shutter_width = {
.ops = &mt9v032_ctrl_ops,
.id = V4L2_CID_AEC_MAX_SHUTTER_WIDTH,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "AEC Max Shutter Width",
.min = 1,
.max = 32765,
.step = 1,
.def = 480,
.flags = 0,
};
/* -----------------------------------------------------------------------------
* V4L2 subdev core operations
*/
......@@ -978,7 +1058,8 @@ static int mt9v032_probe(struct i2c_client *client,
mt9v032->pdata = pdata;
mt9v032->model = (const void *)did->driver_data;
v4l2_ctrl_handler_init(&mt9v032->ctrls, 10);
v4l2_ctrl_handler_init(&mt9v032->ctrls, 11 +
ARRAY_SIZE(mt9v032_aegc_controls));
v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops,
V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
......@@ -1007,6 +1088,13 @@ static int mt9v032_probe(struct i2c_client *client,
mt9v032->test_pattern_color = v4l2_ctrl_new_custom(&mt9v032->ctrls,
&mt9v032_test_pattern_color, NULL);
v4l2_ctrl_new_custom(&mt9v032->ctrls,
mt9v032->model->data->aec_max_shutter_v4l2_ctrl,
NULL);
for (i = 0; i < ARRAY_SIZE(mt9v032_aegc_controls); ++i)
v4l2_ctrl_new_custom(&mt9v032->ctrls, &mt9v032_aegc_controls[i],
NULL);
v4l2_ctrl_cluster(2, &mt9v032->test_pattern);
mt9v032->pixel_rate =
......@@ -1095,6 +1183,67 @@ static int mt9v032_remove(struct i2c_client *client)
return 0;
}
static const struct mt9v032_model_data mt9v032_model_data[] = {
{
/* MT9V022, MT9V032 revisions 1/2/3 */
.min_row_time = 660,
.min_hblank = MT9V032_HORIZONTAL_BLANKING_MIN,
.min_vblank = MT9V032_VERTICAL_BLANKING_MIN,
.max_vblank = MT9V032_VERTICAL_BLANKING_MAX,
.min_shutter = MT9V032_TOTAL_SHUTTER_WIDTH_MIN,
.max_shutter = MT9V032_TOTAL_SHUTTER_WIDTH_MAX,
.pclk_reg = MT9V032_PIXEL_CLOCK,
.aec_max_shutter_reg = MT9V032_AEC_MAX_SHUTTER_WIDTH,
.aec_max_shutter_v4l2_ctrl = &mt9v032_aec_max_shutter_width,
}, {
/* MT9V024, MT9V034 */
.min_row_time = 690,
.min_hblank = MT9V034_HORIZONTAL_BLANKING_MIN,
.min_vblank = MT9V034_VERTICAL_BLANKING_MIN,
.max_vblank = MT9V034_VERTICAL_BLANKING_MAX,
.min_shutter = MT9V034_TOTAL_SHUTTER_WIDTH_MIN,
.max_shutter = MT9V034_TOTAL_SHUTTER_WIDTH_MAX,
.pclk_reg = MT9V034_PIXEL_CLOCK,
.aec_max_shutter_reg = MT9V034_AEC_MAX_SHUTTER_WIDTH,
.aec_max_shutter_v4l2_ctrl = &mt9v034_aec_max_shutter_width,
},
};
static const struct mt9v032_model_info mt9v032_models[] = {
[MT9V032_MODEL_V022_COLOR] = {
.data = &mt9v032_model_data[0],
.color = true,
},
[MT9V032_MODEL_V022_MONO] = {
.data = &mt9v032_model_data[0],
.color = false,
},
[MT9V032_MODEL_V024_COLOR] = {
.data = &mt9v032_model_data[1],
.color = true,
},
[MT9V032_MODEL_V024_MONO] = {
.data = &mt9v032_model_data[1],
.color = false,
},
[MT9V032_MODEL_V032_COLOR] = {
.data = &mt9v032_model_data[0],
.color = true,
},
[MT9V032_MODEL_V032_MONO] = {
.data = &mt9v032_model_data[0],
.color = false,
},
[MT9V032_MODEL_V034_COLOR] = {
.data = &mt9v032_model_data[1],
.color = true,
},
[MT9V032_MODEL_V034_MONO] = {
.data = &mt9v032_model_data[1],
.color = false,
},
};
static const struct i2c_device_id mt9v032_id[] = {
{ "mt9v022", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V022_COLOR] },
{ "mt9v022m", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V022_MONO] },
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment