#define   DBLV_X6        0x10    /* clock x6 */
 #define   DBLV_X8        0x11    /* clock x8 */
 
+#define REG_SCALING_XSC        0x70    /* Test pattern and horizontal scale factor */
+#define   TEST_PATTTERN_0 0x80
+#define REG_SCALING_YSC        0x71    /* Test pattern and vertical scale factor */
+#define   TEST_PATTTERN_1 0x80
+
 #define REG_REG76      0x76    /* OV's name */
 #define   R76_BLKPCOR    0x80    /* Black pixel correction enable */
 #define   R76_WHTPCOR    0x40    /* White pixel correction enable */
 
        { REG_COM3, 0 },        { REG_COM14, 0 },
        /* Mystery scaling numbers */
-       { 0x70, 0x3a },         { 0x71, 0x35 },
+       { REG_SCALING_XSC, 0x3a },
+       { REG_SCALING_YSC, 0x35 },
        { 0x72, 0x11 },         { 0x73, 0xf0 },
        { 0xa2, 0x02 },         { REG_COM10, 0x0 },
 
                return ov7670_write_i2c(sd, reg, value);
 }
 
+static int ov7670_update_bits(struct v4l2_subdev *sd, unsigned char reg,
+               unsigned char mask, unsigned char value)
+{
+       unsigned char orig;
+       int ret;
+
+       ret = ov7670_read(sd, reg, &orig);
+       if (ret)
+               return ret;
+
+       return ov7670_write(sd, reg, (orig & ~mask) | (value & mask));
+}
+
 /*
  * Write a list of register settings; ff/ff stops the process.
  */
        return ret;
 }
 
+static const char * const ov7670_test_pattern_menu[] = {
+       "No test output",
+       "Shifting \"1\"",
+       "8-bar color bar",
+       "Fade to gray color bar",
+};
+
+static int ov7670_s_test_pattern(struct v4l2_subdev *sd, int value)
+{
+       int ret;
+
+       ret = ov7670_update_bits(sd, REG_SCALING_XSC, TEST_PATTTERN_0,
+                               value & BIT(0) ? TEST_PATTTERN_0 : 0);
+       if (ret)
+               return ret;
+
+       return ov7670_update_bits(sd, REG_SCALING_YSC, TEST_PATTTERN_1,
+                               value & BIT(1) ? TEST_PATTTERN_1 : 0);
+}
 
 static int ov7670_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
 {
                        return ov7670_s_exp(sd, info->exposure->val);
                }
                return ov7670_s_autoexp(sd, ctrl->val);
+       case V4L2_CID_TEST_PATTERN:
+               return ov7670_s_test_pattern(sd, ctrl->val);
        }
        return -EINVAL;
 }
        info->auto_exposure = v4l2_ctrl_new_std_menu(&info->hdl, &ov7670_ctrl_ops,
                        V4L2_CID_EXPOSURE_AUTO, V4L2_EXPOSURE_MANUAL, 0,
                        V4L2_EXPOSURE_AUTO);
+       v4l2_ctrl_new_std_menu_items(&info->hdl, &ov7670_ctrl_ops,
+                       V4L2_CID_TEST_PATTERN,
+                       ARRAY_SIZE(ov7670_test_pattern_menu) - 1, 0, 0,
+                       ov7670_test_pattern_menu);
        sd->ctrl_handler = &info->hdl;
        if (info->hdl.error) {
                ret = info->hdl.error;