X-Git-Url: http://pilppa.org/gitweb/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fmedia%2Fvideo%2Fov772x.c;h=4d54e18995711d55c368ab923e67a3890a824867;hb=2941e81f64c2c3f99d03be09790f610dd6fedf64;hp=0af2ca6a98f7265e850b1d43d51747e3520b0189;hpb=bef216b7edb0fac356565dea4bd65131bf6f9c4a;p=linux-2.6-omap-h63xx.git diff --git a/drivers/media/video/ov772x.c b/drivers/media/video/ov772x.c index 0af2ca6a98f..4d54e189957 100644 --- a/drivers/media/video/ov772x.c +++ b/drivers/media/video/ov772x.c @@ -51,6 +51,7 @@ #define COM8 0x13 /* Common control 8 */ #define COM9 0x14 /* Common control 9 */ #define COM10 0x15 /* Common control 10 */ +#define REG16 0x16 /* Register 16 */ #define HSTART 0x17 /* Horizontal sensor size */ #define HSIZE 0x18 /* Horizontal frame (HREF column) end high 8-bit */ #define VSTART 0x19 /* Vertical frame (row) start high 8-bit */ @@ -65,6 +66,7 @@ #define AEW 0x24 /* AGC/AEC - Stable operating region (upper limit) */ #define AEB 0x25 /* AGC/AEC - Stable operating region (lower limit) */ #define VPT 0x26 /* AGC/AEC Fast mode operating region */ +#define REG28 0x28 /* Register 28 */ #define HOUTSIZE 0x29 /* Horizontal data output size MSBs */ #define EXHCH 0x2A /* Dummy pixel insert MSB */ #define EXHCL 0x2B /* Dummy pixel insert LSB */ @@ -94,6 +96,7 @@ #define TGT_R 0x43 /* BLC red channel target value */ #define TGT_GB 0x44 /* BLC Gb channel target value */ #define TGT_GR 0x45 /* BLC Gr channel target value */ +/* for ov7720 */ #define LCC0 0x46 /* Lens correction control 0 */ #define LCC1 0x47 /* Lens correction option 1 - X coordinate */ #define LCC2 0x48 /* Lens correction option 2 - Y coordinate */ @@ -101,6 +104,15 @@ #define LCC4 0x4A /* Lens correction option 4 - radius of the circular */ #define LCC5 0x4B /* Lens correction option 5 */ #define LCC6 0x4C /* Lens correction option 6 */ +/* for ov7725 */ +#define LC_CTR 0x46 /* Lens correction control */ +#define LC_XC 0x47 /* X coordinate of lens correction center relative */ +#define LC_YC 0x48 /* Y coordinate of lens correction center relative */ +#define LC_COEF 0x49 /* Lens correction coefficient */ +#define LC_RADI 0x4A /* Lens correction radius */ +#define LC_COEFB 0x4B /* Lens B channel compensation coefficient */ +#define LC_COEFR 0x4C /* Lens R channel compensation coefficient */ + #define FIXGAIN 0x4D /* Analog fix gain amplifer */ #define AREF0 0x4E /* Sensor reference control */ #define AREF1 0x4F /* Sensor reference current control */ @@ -112,34 +124,34 @@ #define AREF7 0x55 /* Analog reference control */ #define UFIX 0x60 /* U channel fixed value output */ #define VFIX 0x61 /* V channel fixed value output */ -#define AW_BB_BLK 0x62 /* AWB option for advanced AWB */ -#define AW_B_CTRL0 0x63 /* AWB control byte 0 */ +#define AWBB_BLK 0x62 /* AWB option for advanced AWB */ +#define AWB_CTRL0 0x63 /* AWB control byte 0 */ #define DSP_CTRL1 0x64 /* DSP control byte 1 */ #define DSP_CTRL2 0x65 /* DSP control byte 2 */ #define DSP_CTRL3 0x66 /* DSP control byte 3 */ #define DSP_CTRL4 0x67 /* DSP control byte 4 */ -#define AW_B_BIAS 0x68 /* AWB BLC level clip */ -#define AW_BCTRL1 0x69 /* AWB control 1 */ -#define AW_BCTRL2 0x6A /* AWB control 2 */ -#define AW_BCTRL3 0x6B /* AWB control 3 */ -#define AW_BCTRL4 0x6C /* AWB control 4 */ -#define AW_BCTRL5 0x6D /* AWB control 5 */ -#define AW_BCTRL6 0x6E /* AWB control 6 */ -#define AW_BCTRL7 0x6F /* AWB control 7 */ -#define AW_BCTRL8 0x70 /* AWB control 8 */ -#define AW_BCTRL9 0x71 /* AWB control 9 */ -#define AW_BCTRL10 0x72 /* AWB control 10 */ -#define AW_BCTRL11 0x73 /* AWB control 11 */ -#define AW_BCTRL12 0x74 /* AWB control 12 */ -#define AW_BCTRL13 0x75 /* AWB control 13 */ -#define AW_BCTRL14 0x76 /* AWB control 14 */ -#define AW_BCTRL15 0x77 /* AWB control 15 */ -#define AW_BCTRL16 0x78 /* AWB control 16 */ -#define AW_BCTRL17 0x79 /* AWB control 17 */ -#define AW_BCTRL18 0x7A /* AWB control 18 */ -#define AW_BCTRL19 0x7B /* AWB control 19 */ -#define AW_BCTRL20 0x7C /* AWB control 20 */ -#define AW_BCTRL21 0x7D /* AWB control 21 */ +#define AWB_BIAS 0x68 /* AWB BLC level clip */ +#define AWB_CTRL1 0x69 /* AWB control 1 */ +#define AWB_CTRL2 0x6A /* AWB control 2 */ +#define AWB_CTRL3 0x6B /* AWB control 3 */ +#define AWB_CTRL4 0x6C /* AWB control 4 */ +#define AWB_CTRL5 0x6D /* AWB control 5 */ +#define AWB_CTRL6 0x6E /* AWB control 6 */ +#define AWB_CTRL7 0x6F /* AWB control 7 */ +#define AWB_CTRL8 0x70 /* AWB control 8 */ +#define AWB_CTRL9 0x71 /* AWB control 9 */ +#define AWB_CTRL10 0x72 /* AWB control 10 */ +#define AWB_CTRL11 0x73 /* AWB control 11 */ +#define AWB_CTRL12 0x74 /* AWB control 12 */ +#define AWB_CTRL13 0x75 /* AWB control 13 */ +#define AWB_CTRL14 0x76 /* AWB control 14 */ +#define AWB_CTRL15 0x77 /* AWB control 15 */ +#define AWB_CTRL16 0x78 /* AWB control 16 */ +#define AWB_CTRL17 0x79 /* AWB control 17 */ +#define AWB_CTRL18 0x7A /* AWB control 18 */ +#define AWB_CTRL19 0x7B /* AWB control 19 */ +#define AWB_CTRL20 0x7C /* AWB control 20 */ +#define AWB_CTRL21 0x7D /* AWB control 21 */ #define GAM1 0x7E /* Gamma Curve 1st segment input end point */ #define GAM2 0x7F /* Gamma Curve 2nd segment input end point */ #define GAM3 0x80 /* Gamma Curve 3rd segment input end point */ @@ -182,8 +194,13 @@ #define SDE 0xA6 /* Special digital effect control */ #define USAT 0xA7 /* U component saturation control */ #define VSAT 0xA8 /* V component saturation control */ +/* for ov7720 */ #define HUE0 0xA9 /* Hue control 0 */ #define HUE1 0xAA /* Hue control 1 */ +/* for ov7725 */ +#define HUECOS 0xA9 /* Cosine value */ +#define HUESIN 0xAA /* Sine value */ + #define SIGN 0xAB /* Sign bit for Hue and contrast */ #define DSPAUTO 0xAC /* DSP auto function ON/OFF control */ @@ -345,6 +362,13 @@ #define OP_UV 0x00000001 #define OP_SWAP_RGB 0x00000002 +/* + * ID + */ +#define OV7720 0x7720 +#define OV7725 0x7721 +#define VERSION(pid, ver) ((pid<<8)|(ver&0xFF)) + /* * struct */ @@ -374,34 +398,22 @@ struct ov772x_priv { struct soc_camera_device icd; const struct ov772x_color_format *fmt; const struct ov772x_win_size *win; + int model; }; #define ENDMARKER { 0xff, 0xff } -static const struct regval_list ov772x_default_regs[] = -{ - { COM3, 0x00 }, - { COM4, PLL_4x | 0x01 }, - { 0x16, 0x00 }, /* Mystery */ - { COM11, 0x10 }, /* Mystery */ - { 0x28, 0x00 }, /* Mystery */ - { HREF, 0x00 }, - { COM13, 0xe2 }, /* Mystery */ - { AREF0, 0xef }, - { AREF2, 0x60 }, - { AREF6, 0x7a }, - ENDMARKER, -}; - /* * register setting for color format */ static const struct regval_list ov772x_RGB555_regs[] = { + { COM3, 0x00 }, { COM7, FMT_RGB555 | OFMT_RGB }, ENDMARKER, }; static const struct regval_list ov772x_RGB565_regs[] = { + { COM3, 0x00 }, { COM7, FMT_RGB565 | OFMT_RGB }, ENDMARKER, }; @@ -413,6 +425,7 @@ static const struct regval_list ov772x_YYUV_regs[] = { }; static const struct regval_list ov772x_UVYY_regs[] = { + { COM3, 0x00 }, { COM7, OFMT_YUV }, ENDMARKER, }; @@ -487,9 +500,8 @@ static const struct soc_camera_data_format ov772x_fmt_lists[] = { /* * color format list */ -#define T_YUYV 0 static const struct ov772x_color_format ov772x_cfmts[] = { - [T_YUYV] = { + { SETFOURCC(YUYV), .regs = ov772x_YYUV_regs, }, @@ -593,89 +605,49 @@ static int ov772x_reset(struct i2c_client *client) static int ov772x_init(struct soc_camera_device *icd) { - return 0; + struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); + int ret = 0; + + if (priv->info->link.power) { + ret = priv->info->link.power(&priv->client->dev, 1); + if (ret < 0) + return ret; + } + + if (priv->info->link.reset) + ret = priv->info->link.reset(&priv->client->dev); + + return ret; } static int ov772x_release(struct soc_camera_device *icd) { - return 0; + struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); + int ret = 0; + + if (priv->info->link.power) + ret = priv->info->link.power(&priv->client->dev, 0); + + return ret; } static int ov772x_start_capture(struct soc_camera_device *icd) { struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); - int ret; - - - if (!priv->win) - priv->win = &ov772x_win_vga; - if (!priv->fmt) - priv->fmt = &ov772x_cfmts[T_YUYV]; - - /* - * reset hardware - */ - ov772x_reset(priv->client); - ret = ov772x_write_array(priv->client, ov772x_default_regs); - if (ret < 0) - goto start_end; - - /* - * set color format - */ - ret = ov772x_write_array(priv->client, priv->fmt->regs); - if (ret < 0) - goto start_end; - - /* - * set size format - */ - ret = ov772x_write_array(priv->client, priv->win->regs); - if (ret < 0) - goto start_end; - - /* - * set COM7 bit ( QVGA or VGA ) - */ - ret = ov772x_mask_set(priv->client, - COM7, SLCT_MASK, priv->win->com7_bit); - if (ret < 0) - goto start_end; - /* - * set UV setting - */ - if (priv->fmt->option & OP_UV) { - ret = ov772x_mask_set(priv->client, - DSP_CTRL3, UV_MASK, UV_ON); - if (ret < 0) - goto start_end; + if (!priv->win || !priv->fmt) { + dev_err(&icd->dev, "norm or win select error\n"); + return -EPERM; } - /* - * set SWAP setting - */ - if (priv->fmt->option & OP_SWAP_RGB) { - ret = ov772x_mask_set(priv->client, - COM3, SWAP_MASK, SWAP_RGB); - if (ret < 0) - goto start_end; - } - - dev_info(&icd->dev, + dev_dbg(&icd->dev, "format %s, win %s\n", priv->fmt->name, priv->win->name); -start_end: - priv->fmt = NULL; - priv->win = NULL; - - return ret; + return 0; } static int ov772x_stop_capture(struct soc_camera_device *icd) { - struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); - ov772x_reset(priv->client); return 0; } @@ -688,18 +660,20 @@ static int ov772x_set_bus_param(struct soc_camera_device *icd, static unsigned long ov772x_query_bus_param(struct soc_camera_device *icd) { struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); + struct soc_camera_link *icl = priv->client->dev.platform_data; + unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER | + SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH | + SOCAM_DATA_ACTIVE_HIGH | priv->info->buswidth; - return SOCAM_PCLK_SAMPLE_RISING | - SOCAM_HSYNC_ACTIVE_HIGH | - SOCAM_VSYNC_ACTIVE_HIGH | - SOCAM_MASTER | - priv->info->buswidth; + return soc_camera_apply_sensor_flags(icl, flags); } static int ov772x_get_chip_id(struct soc_camera_device *icd, - struct v4l2_chip_ident *id) + struct v4l2_dbg_chip_ident *id) { - id->ident = V4L2_IDENT_OV772X; + struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); + + id->ident = priv->model; id->revision = 0; return 0; @@ -707,11 +681,12 @@ static int ov772x_get_chip_id(struct soc_camera_device *icd, #ifdef CONFIG_VIDEO_ADV_DEBUG static int ov772x_get_register(struct soc_camera_device *icd, - struct v4l2_register *reg) + struct v4l2_dbg_register *reg) { struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); int ret; + reg->size = 1; if (reg->reg > 0xff) return -EINVAL; @@ -725,7 +700,7 @@ static int ov772x_get_register(struct soc_camera_device *icd, } static int ov772x_set_register(struct soc_camera_device *icd, - struct v4l2_register *reg) + struct v4l2_dbg_register *reg) { struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); @@ -737,9 +712,29 @@ static int ov772x_set_register(struct soc_camera_device *icd, } #endif -static int ov772x_set_fmt_cap(struct soc_camera_device *icd, - __u32 pixfmt, - struct v4l2_rect *rect) +static const struct ov772x_win_size* +ov772x_select_win(u32 width, u32 height) +{ + __u32 diff; + const struct ov772x_win_size *win; + + /* default is QVGA */ + diff = abs(width - ov772x_win_qvga.width) + + abs(height - ov772x_win_qvga.height); + win = &ov772x_win_qvga; + + /* VGA */ + if (diff > + abs(width - ov772x_win_vga.width) + + abs(height - ov772x_win_vga.height)) + win = &ov772x_win_vga; + + return win; +} + +static int ov772x_set_fmt(struct soc_camera_device *icd, + __u32 pixfmt, + struct v4l2_rect *rect) { struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); int ret = -EINVAL; @@ -752,39 +747,89 @@ static int ov772x_set_fmt_cap(struct soc_camera_device *icd, for (i = 0; i < ARRAY_SIZE(ov772x_cfmts); i++) { if (pixfmt == ov772x_cfmts[i].fourcc) { priv->fmt = ov772x_cfmts + i; - ret = 0; break; } } + if (!priv->fmt) + goto ov772x_set_fmt_error; - return ret; -} + /* + * select win + */ + priv->win = ov772x_select_win(rect->width, rect->height); -static int ov772x_try_fmt_cap(struct soc_camera_device *icd, - struct v4l2_format *f) -{ - struct v4l2_pix_format *pix = &f->fmt.pix; - struct ov772x_priv *priv; + /* + * reset hardware + */ + ov772x_reset(priv->client); - priv = container_of(icd, struct ov772x_priv, icd); + /* + * set color format + */ + ret = ov772x_write_array(priv->client, priv->fmt->regs); + if (ret < 0) + goto ov772x_set_fmt_error; + + /* + * set size format + */ + ret = ov772x_write_array(priv->client, priv->win->regs); + if (ret < 0) + goto ov772x_set_fmt_error; - /* QVGA */ - if (pix->width <= ov772x_win_qvga.width || - pix->height <= ov772x_win_qvga.height) { - priv->win = &ov772x_win_qvga; - pix->width = ov772x_win_qvga.width; - pix->height = ov772x_win_qvga.height; + /* + * set COM7 bit ( QVGA or VGA ) + */ + ret = ov772x_mask_set(priv->client, + COM7, SLCT_MASK, priv->win->com7_bit); + if (ret < 0) + goto ov772x_set_fmt_error; + + /* + * set UV setting + */ + if (priv->fmt->option & OP_UV) { + ret = ov772x_mask_set(priv->client, + DSP_CTRL3, UV_MASK, UV_ON); + if (ret < 0) + goto ov772x_set_fmt_error; } - /* VGA */ - else if (pix->width <= ov772x_win_vga.width || - pix->height <= ov772x_win_vga.height) { - priv->win = &ov772x_win_vga; - pix->width = ov772x_win_vga.width; - pix->height = ov772x_win_vga.height; + /* + * set SWAP setting + */ + if (priv->fmt->option & OP_SWAP_RGB) { + ret = ov772x_mask_set(priv->client, + COM3, SWAP_MASK, SWAP_RGB); + if (ret < 0) + goto ov772x_set_fmt_error; } - pix->field = V4L2_FIELD_NONE; + return ret; + +ov772x_set_fmt_error: + + ov772x_reset(priv->client); + priv->win = NULL; + priv->fmt = NULL; + + return ret; +} + +static int ov772x_try_fmt(struct soc_camera_device *icd, + struct v4l2_format *f) +{ + struct v4l2_pix_format *pix = &f->fmt.pix; + const struct ov772x_win_size *win; + + /* + * select suitable win + */ + win = ov772x_select_win(pix->width, pix->height); + + pix->width = win->width; + pix->height = win->height; + pix->field = V4L2_FIELD_NONE; return 0; } @@ -793,6 +838,7 @@ static int ov772x_video_probe(struct soc_camera_device *icd) { struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); u8 pid, ver; + const char *devname; /* * We must have a parent by now. And it cannot be a wrong one. @@ -814,41 +860,41 @@ static int ov772x_video_probe(struct soc_camera_device *icd) icd->formats = ov772x_fmt_lists; icd->num_formats = ARRAY_SIZE(ov772x_fmt_lists); - if (priv->info->link.power) - priv->info->link.power(&priv->client->dev, 1); - /* * check and show product ID and manufacturer ID */ pid = i2c_smbus_read_byte_data(priv->client, PID); ver = i2c_smbus_read_byte_data(priv->client, VER); - if (pid != 0x77 || - ver != 0x21) { - if (priv->info->link.power) - priv->info->link.power(&priv->client->dev, 0); + + switch (VERSION(pid, ver)) { + case OV7720: + devname = "ov7720"; + priv->model = V4L2_IDENT_OV7720; + break; + case OV7725: + devname = "ov7725"; + priv->model = V4L2_IDENT_OV7725; + break; + default: + dev_err(&icd->dev, + "Product ID error %x:%x\n", pid, ver); return -ENODEV; } dev_info(&icd->dev, - "ov772x Product ID %0x:%0x Manufacturer ID %x:%x\n", + "%s Product ID %0x:%0x Manufacturer ID %x:%x\n", + devname, pid, ver, i2c_smbus_read_byte_data(priv->client, MIDH), i2c_smbus_read_byte_data(priv->client, MIDL)); - return soc_camera_video_start(icd); } static void ov772x_video_remove(struct soc_camera_device *icd) { - struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); - soc_camera_video_stop(icd); - - if (priv->info->link.power) - priv->info->link.power(&priv->client->dev, 0); - } static struct soc_camera_ops ov772x_ops = { @@ -859,8 +905,8 @@ static struct soc_camera_ops ov772x_ops = { .release = ov772x_release, .start_capture = ov772x_start_capture, .stop_capture = ov772x_stop_capture, - .set_fmt_cap = ov772x_set_fmt_cap, - .try_fmt_cap = ov772x_try_fmt_cap, + .set_fmt = ov772x_set_fmt, + .try_fmt = ov772x_try_fmt, .set_bus_param = ov772x_set_bus_param, .query_bus_param = ov772x_query_bus_param, .get_chip_id = ov772x_get_chip_id, @@ -911,8 +957,10 @@ static int ov772x_probe(struct i2c_client *client, ret = soc_camera_device_register(icd); - if (ret) + if (ret) { + i2c_set_clientdata(client, NULL); kfree(priv); + } return ret; } @@ -922,12 +970,13 @@ static int ov772x_remove(struct i2c_client *client) struct ov772x_priv *priv = i2c_get_clientdata(client); soc_camera_device_unregister(&priv->icd); + i2c_set_clientdata(client, NULL); kfree(priv); return 0; } static const struct i2c_device_id ov772x_id[] = { - {"ov772x", 0}, + { "ov772x", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, ov772x_id); @@ -947,7 +996,6 @@ static struct i2c_driver ov772x_i2c_driver = { static int __init ov772x_module_init(void) { - printk(KERN_INFO "ov772x driver\n"); return i2c_add_driver(&ov772x_i2c_driver); }