V4L/DVB (10632): Added support for AVerMedia Cardbus Hybrid remote control
[safe/jmp/linux-2.6] / drivers / media / video / ov772x.c
index a2d51e2..3c9e0ba 100644 (file)
@@ -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 */
 #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 */
 #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 */
 
 #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,6 +398,7 @@ 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 }
@@ -612,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)
@@ -665,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:
@@ -691,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)
+                             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;
@@ -710,11 +736,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;
 
@@ -728,7 +755,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);
 
@@ -740,6 +767,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)
@@ -760,34 +808,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;
 }
@@ -796,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.
@@ -822,15 +865,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),
@@ -905,8 +958,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;
 }
@@ -916,12 +971,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);
@@ -941,7 +997,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);
 }