diff options
Diffstat (limited to 'drivers/media/i2c/ov7670.c')
-rw-r--r-- | drivers/media/i2c/ov7670.c | 90 |
1 files changed, 65 insertions, 25 deletions
diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c index 950a0acf85fb..28571de1c2f6 100644 --- a/drivers/media/i2c/ov7670.c +++ b/drivers/media/i2c/ov7670.c @@ -163,6 +163,11 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)"); #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 */ @@ -292,7 +297,8 @@ static struct regval_list ov7670_default_regs[] = { { 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 }, @@ -406,12 +412,12 @@ static struct regval_list ov7670_fmt_yuv422[] = { { REG_COM1, 0 }, /* CCIR601 */ { REG_COM15, COM15_R00FF }, { REG_COM9, 0x48 }, /* 32x gain ceiling; 0x8 is reserved bit */ - { 0x4f, 0x80 }, /* "matrix coefficient 1" */ - { 0x50, 0x80 }, /* "matrix coefficient 2" */ + { 0x4f, 0x80 }, /* "matrix coefficient 1" */ + { 0x50, 0x80 }, /* "matrix coefficient 2" */ { 0x51, 0 }, /* vb */ - { 0x52, 0x22 }, /* "matrix coefficient 4" */ - { 0x53, 0x5e }, /* "matrix coefficient 5" */ - { 0x54, 0x80 }, /* "matrix coefficient 6" */ + { 0x52, 0x22 }, /* "matrix coefficient 4" */ + { 0x53, 0x5e }, /* "matrix coefficient 5" */ + { 0x54, 0x80 }, /* "matrix coefficient 6" */ { REG_COM13, COM13_GAMMA|COM13_UVSAT }, { 0xff, 0xff }, }; @@ -421,13 +427,13 @@ static struct regval_list ov7670_fmt_rgb565[] = { { REG_RGB444, 0 }, /* No RGB444 please */ { REG_COM1, 0x0 }, /* CCIR601 */ { REG_COM15, COM15_RGB565 }, - { REG_COM9, 0x38 }, /* 16x gain ceiling; 0x8 is reserved bit */ - { 0x4f, 0xb3 }, /* "matrix coefficient 1" */ - { 0x50, 0xb3 }, /* "matrix coefficient 2" */ + { REG_COM9, 0x38 }, /* 16x gain ceiling; 0x8 is reserved bit */ + { 0x4f, 0xb3 }, /* "matrix coefficient 1" */ + { 0x50, 0xb3 }, /* "matrix coefficient 2" */ { 0x51, 0 }, /* vb */ - { 0x52, 0x3d }, /* "matrix coefficient 4" */ - { 0x53, 0xa7 }, /* "matrix coefficient 5" */ - { 0x54, 0xe4 }, /* "matrix coefficient 6" */ + { 0x52, 0x3d }, /* "matrix coefficient 4" */ + { 0x53, 0xa7 }, /* "matrix coefficient 5" */ + { 0x54, 0xe4 }, /* "matrix coefficient 6" */ { REG_COM13, COM13_GAMMA|COM13_UVSAT }, { 0xff, 0xff }, }; @@ -437,13 +443,13 @@ static struct regval_list ov7670_fmt_rgb444[] = { { REG_RGB444, R444_ENABLE }, /* Enable xxxxrrrr ggggbbbb */ { REG_COM1, 0x0 }, /* CCIR601 */ { REG_COM15, COM15_R01FE|COM15_RGB565 }, /* Data range needed? */ - { REG_COM9, 0x38 }, /* 16x gain ceiling; 0x8 is reserved bit */ - { 0x4f, 0xb3 }, /* "matrix coefficient 1" */ - { 0x50, 0xb3 }, /* "matrix coefficient 2" */ + { REG_COM9, 0x38 }, /* 16x gain ceiling; 0x8 is reserved bit */ + { 0x4f, 0xb3 }, /* "matrix coefficient 1" */ + { 0x50, 0xb3 }, /* "matrix coefficient 2" */ { 0x51, 0 }, /* vb */ - { 0x52, 0x3d }, /* "matrix coefficient 4" */ - { 0x53, 0xa7 }, /* "matrix coefficient 5" */ - { 0x54, 0xe4 }, /* "matrix coefficient 6" */ + { 0x52, 0x3d }, /* "matrix coefficient 4" */ + { 0x53, 0xa7 }, /* "matrix coefficient 5" */ + { 0x54, 0xe4 }, /* "matrix coefficient 6" */ { REG_COM13, COM13_GAMMA|COM13_UVSAT|0x2 }, /* Magic rsvd bit */ { 0xff, 0xff }, }; @@ -568,6 +574,19 @@ static int ov7670_write(struct v4l2_subdev *sd, unsigned char reg, 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. */ @@ -648,7 +667,7 @@ static struct ov7670_format_struct { { .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, .colorspace = V4L2_COLORSPACE_SRGB, - .regs = ov7670_fmt_yuv422, + .regs = ov7670_fmt_yuv422, .cmatrix = { 128, -128, 0, -34, -94, 128 }, }, { @@ -666,7 +685,7 @@ static struct ov7670_format_struct { { .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, .colorspace = V4L2_COLORSPACE_SRGB, - .regs = ov7670_fmt_raw, + .regs = ov7670_fmt_raw, .cmatrix = { 0, 0, 0, 0, 0, 0 }, }, }; @@ -1470,6 +1489,25 @@ static int ov7670_s_autoexp(struct v4l2_subdev *sd, 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) { @@ -1516,6 +1554,8 @@ static int ov7670_s_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; } @@ -1770,6 +1810,10 @@ static int ov7670_probe(struct i2c_client *client, 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; @@ -1802,9 +1846,7 @@ static int ov7670_probe(struct i2c_client *client, return 0; entity_cleanup: -#if defined(CONFIG_MEDIA_CONTROLLER) media_entity_cleanup(&info->sd.entity); -#endif hdl_free: v4l2_ctrl_handler_free(&info->hdl); power_off: @@ -1820,12 +1862,10 @@ static int ov7670_remove(struct i2c_client *client) struct v4l2_subdev *sd = i2c_get_clientdata(client); struct ov7670_info *info = to_state(sd); - v4l2_device_unregister_subdev(sd); + v4l2_async_unregister_subdev(sd); v4l2_ctrl_handler_free(&info->hdl); clk_disable_unprepare(info->clk); -#if defined(CONFIG_MEDIA_CONTROLLER) media_entity_cleanup(&info->sd.entity); -#endif ov7670_s_power(sd, 0); return 0; } |