#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 {
        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 {
        { 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;
  */
 
 #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)
 {
                        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;
        .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
  */
        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);
        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 =
        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] },