]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/media/video/ov772x.c
V4L/DVB (10668): ov772x: bit mask operation fix on ov772x_mask_set.
[linux-2.6-omap-h63xx.git] / drivers / media / video / ov772x.c
index 3c9e0ba974e9ec57bb819b234f18cb05c53ecc4d..6b18da7c3c0ac02272a8f38a99171436edbf641a 100644 (file)
 #define SLCT_QVGA       0x40   /*   1 : QVGA */
 #define ITU656_ON_OFF   0x20   /* ITU656 protocol ON/OFF selection */
                                /* RGB output format control */
+#define FMT_MASK        0x0c   /*      Mask of color format */
 #define FMT_GBR422      0x00   /*      00 : GBR 4:2:2 */
 #define FMT_RGB565      0x04   /*      01 : RGB 565 */
 #define FMT_RGB555      0x08   /*      10 : RGB 555 */
 #define FMT_RGB444      0x0c   /* 11 : RGB 444 */
                                /* Output format control */
+#define OFMT_MASK       0x03    /*      Mask of output format */
 #define OFMT_YUV        0x00   /*      00 : YUV */
 #define OFMT_P_BRAW     0x01   /*      01 : Processed Bayer RAW */
 #define OFMT_RGB        0x02   /*      10 : RGB */
 #define GAIN_2x         0x00   /*    000 :   2x */
 #define GAIN_4x         0x10   /*    001 :   4x */
 #define GAIN_8x         0x20   /*    010 :   8x */
-#define GAIN_16x        0x30   /* 011 :  16x */
+#define GAIN_16x        0x30   /*    011 :  16x */
 #define GAIN_32x        0x40   /*    100 :  32x */
 #define GAIN_64x        0x50   /* 101 :  64x */
 #define GAIN_128x       0x60   /* 110 : 128x */
 #define VOSZ_VGA        0xF0
 #define VOSZ_QVGA       0x78
 
-/*
- * bit configure (32 bit)
- * this is used in struct ov772x_color_format :: option
- */
-#define OP_UV       0x00000001
-#define OP_SWAP_RGB 0x00000002
-
 /*
  * ID
  */
@@ -380,8 +375,9 @@ struct regval_list {
 struct ov772x_color_format {
        char                     *name;
        __u32                     fourcc;
-       const struct regval_list *regs;
-       unsigned int              option;
+       u8                        dsp3;
+       u8                        com3;
+       u8                        com7;
 };
 
 struct ov772x_win_size {
@@ -403,34 +399,6 @@ struct ov772x_priv {
 
 #define ENDMARKER { 0xff, 0xff }
 
-/*
- * 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,
-};
-
-static const struct regval_list ov772x_YYUV_regs[] = {
-       { COM3, SWAP_YUV },
-       { COM7, OFMT_YUV },
-       ENDMARKER,
-};
-
-static const struct regval_list ov772x_UVYY_regs[] = {
-       { COM3, 0x00 },
-       { COM7, OFMT_YUV },
-       ENDMARKER,
-};
-
-
 /*
  * register setting for window size
  */
@@ -500,38 +468,48 @@ 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,
+               .dsp3   = 0x0,
+               .com3   = SWAP_YUV,
+               .com7   = OFMT_YUV,
        },
        {
                SETFOURCC(YVYU),
-               .regs   = ov772x_YYUV_regs,
-               .option = OP_UV,
+               .dsp3   = UV_ON,
+               .com3   = SWAP_YUV,
+               .com7   = OFMT_YUV,
        },
        {
                SETFOURCC(UYVY),
-               .regs   = ov772x_UVYY_regs,
+               .dsp3   = 0x0,
+               .com3   = 0x0,
+               .com7   = OFMT_YUV,
        },
        {
                SETFOURCC(RGB555),
-               .regs   = ov772x_RGB555_regs,
-               .option = OP_SWAP_RGB,
+               .dsp3   = 0x0,
+               .com3   = SWAP_RGB,
+               .com7   = FMT_RGB555 | OFMT_RGB,
        },
        {
                SETFOURCC(RGB555X),
-               .regs   = ov772x_RGB555_regs,
+               .dsp3   = 0x0,
+               .com3   = 0x0,
+               .com7   = FMT_RGB555 | OFMT_RGB,
        },
        {
                SETFOURCC(RGB565),
-               .regs   = ov772x_RGB565_regs,
-               .option = OP_SWAP_RGB,
+               .dsp3   = 0x0,
+               .com3   = SWAP_RGB,
+               .com7   = FMT_RGB565 | OFMT_RGB,
        },
        {
                SETFOURCC(RGB565X),
-               .regs   = ov772x_RGB565_regs,
+               .dsp3   = 0x0,
+               .com3   = 0x0,
+               .com7   = FMT_RGB565 | OFMT_RGB,
        },
 };
 
@@ -587,8 +565,11 @@ static int ov772x_mask_set(struct i2c_client *client,
                                          u8  set)
 {
        s32 val = i2c_smbus_read_byte_data(client, command);
+       if (val < 0)
+               return val;
+
        val &= ~mask;
-       val |=  set;
+       val |= set & mask;
 
        return i2c_smbus_write_byte_data(client, command, val);
 }
@@ -635,74 +616,20 @@ static int ov772x_release(struct soc_camera_device *icd)
 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);
-
-       /*
-        * 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;
-       }
 
-       /*
-        * 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;
+       if (!priv->win || !priv->fmt) {
+               dev_err(&icd->dev, "norm or win select error\n");
+               return -EPERM;
        }
 
        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;
 }
 
@@ -718,7 +645,7 @@ static unsigned long ov772x_query_bus_param(struct soc_camera_device *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 |
-               priv->info->buswidth;
+               SOCAM_DATA_ACTIVE_HIGH | priv->info->buswidth;
 
        return soc_camera_apply_sensor_flags(icl, flags);
 }
@@ -787,13 +714,13 @@ ov772x_select_win(u32 width, u32 height)
        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;
+       u8  val;
        int i;
 
        /*
@@ -803,16 +730,67 @@ static int ov772x_set_fmt(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;
 
        /*
         * select win
         */
        priv->win = ov772x_select_win(rect->width, rect->height);
 
+       /*
+        * reset hardware
+        */
+       ov772x_reset(priv->client);
+
+       /*
+        * set size format
+        */
+       ret = ov772x_write_array(priv->client, priv->win->regs);
+       if (ret < 0)
+               goto ov772x_set_fmt_error;
+
+       /*
+        * set DSP_CTRL3
+        */
+       val = priv->fmt->dsp3;
+       if (val) {
+               ret = ov772x_mask_set(priv->client,
+                                     DSP_CTRL3, UV_MASK, val);
+               if (ret < 0)
+                       goto ov772x_set_fmt_error;
+       }
+
+       /*
+        * set COM3
+        */
+       val = priv->fmt->com3;
+       ret = ov772x_mask_set(priv->client,
+                             COM3, SWAP_MASK, val);
+       if (ret < 0)
+               goto ov772x_set_fmt_error;
+
+       /*
+        * set COM7
+        */
+       val = priv->win->com7_bit | priv->fmt->com7;
+       ret = ov772x_mask_set(priv->client,
+                             COM7, (SLCT_MASK | FMT_MASK | OFMT_MASK),
+                             val);
+       if (ret < 0)
+               goto ov772x_set_fmt_error;
+
+       return ret;
+
+ov772x_set_fmt_error:
+
+       ov772x_reset(priv->client);
+       priv->win = NULL;
+       priv->fmt = NULL;
+
        return ret;
 }
 
@@ -889,7 +867,6 @@ static int ov772x_video_probe(struct soc_camera_device *icd)
                 i2c_smbus_read_byte_data(priv->client, MIDH),
                 i2c_smbus_read_byte_data(priv->client, MIDL));
 
-
        return soc_camera_video_start(icd);
 }