|
@@ -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] },
|