summaryrefslogtreecommitdiff
path: root/linux/drivers/media/video/ov772x.c
diff options
context:
space:
mode:
Diffstat (limited to 'linux/drivers/media/video/ov772x.c')
-rw-r--r--linux/drivers/media/video/ov772x.c143
1 files changed, 91 insertions, 52 deletions
diff --git a/linux/drivers/media/video/ov772x.c b/linux/drivers/media/video/ov772x.c
index c023bbc84..932444623 100644
--- a/linux/drivers/media/video/ov772x.c
+++ b/linux/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 */
@@ -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 */
@@ -346,6 +363,13 @@
#define OP_SWAP_RGB 0x00000002
/*
+ * ID
+ */
+#define OV7720 0x7720
+#define OV7725 0x7721
+#define VERSION(pid, ver) ((pid<<8)|(ver&0xFF))
+
+/*
* struct
*/
struct regval_list {
@@ -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,
};
@@ -624,7 +637,6 @@ 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)
@@ -634,9 +646,6 @@ static int ov772x_start_capture(struct soc_camera_device *icd)
* reset hardware
*/
ov772x_reset(priv->client);
- ret = ov772x_write_array(priv->client, ov772x_default_regs);
- if (ret < 0)
- goto start_end;
/*
* set color format
@@ -680,7 +689,7 @@ static int ov772x_start_capture(struct soc_camera_device *icd)
goto start_end;
}
- dev_info(&icd->dev,
+ dev_dbg(&icd->dev,
"format %s, win %s\n", priv->fmt->name, priv->win->name);
start_end:
@@ -706,18 +715,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);
-
- return SOCAM_PCLK_SAMPLE_RISING |
- SOCAM_HSYNC_ACTIVE_HIGH |
- SOCAM_VSYNC_ACTIVE_HIGH |
- SOCAM_MASTER |
+ 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 |
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)
{
- 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;
@@ -755,6 +766,27 @@ static int ov772x_set_register(struct soc_camera_device *icd,
}
#endif
+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)
@@ -775,34 +807,28 @@ static int ov772x_set_fmt(struct soc_camera_device *icd,
}
}
+ /*
+ * select win
+ */
+ priv->win = ov772x_select_win(rect->width, rect->height);
+
return ret;
}
static int ov772x_try_fmt(struct soc_camera_device *icd,
struct v4l2_format *f)
{
- struct v4l2_pix_format *pix = &f->fmt.pix;
- struct ov772x_priv *priv;
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ const struct ov772x_win_size *win;
- priv = container_of(icd, struct ov772x_priv, icd);
-
- /* 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;
- }
-
- /* 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;
- }
+ /*
+ * select suitable win
+ */
+ win = ov772x_select_win(pix->width, pix->height);
- pix->field = V4L2_FIELD_NONE;
+ pix->width = win->width;
+ pix->height = win->height;
+ pix->field = V4L2_FIELD_NONE;
return 0;
}
@@ -811,6 +837,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.
@@ -837,15 +864,25 @@ static int ov772x_video_probe(struct soc_camera_device *icd)
*/
pid = i2c_smbus_read_byte_data(priv->client, PID);
ver = i2c_smbus_read_byte_data(priv->client, VER);
- if (pid != 0x77 ||
- ver != 0x21) {
+
+ 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),
@@ -924,8 +961,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;
}
@@ -935,13 +974,14 @@ 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;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
static const struct i2c_device_id ov772x_id[] = {
- {"ov772x", 0},
+ { "ov772x", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, ov772x_id);
@@ -964,7 +1004,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);
}