media: ov6650: Fix some format attributes not under control
[sfrench/cifs-2.6.git] / drivers / media / i2c / ov6650.c
index 5b9af5e5b7f1314cf2d53aef70173a71fb3ceae0..fd608aebb68d003de1e0c9e26027c6f1a7c52f51 100644 (file)
@@ -200,7 +200,6 @@ struct ov6650 {
        unsigned long           pclk_max;       /* from resolution and format */
        struct v4l2_fract       tpf;            /* as requested with s_frame_interval */
        u32 code;
-       enum v4l2_colorspace    colorspace;
 };
 
 
@@ -213,6 +212,17 @@ static u32 ov6650_codes[] = {
        MEDIA_BUS_FMT_Y8_1X8,
 };
 
+static const struct v4l2_mbus_framefmt ov6650_def_fmt = {
+       .width          = W_CIF,
+       .height         = H_CIF,
+       .code           = MEDIA_BUS_FMT_SBGGR8_1X8,
+       .colorspace     = V4L2_COLORSPACE_SRGB,
+       .field          = V4L2_FIELD_NONE,
+       .ycbcr_enc      = V4L2_YCBCR_ENC_DEFAULT,
+       .quantization   = V4L2_QUANTIZATION_DEFAULT,
+       .xfer_func      = V4L2_XFER_FUNC_DEFAULT,
+};
+
 /* read a register */
 static int ov6650_reg_read(struct i2c_client *client, u8 reg, u8 *val)
 {
@@ -465,38 +475,37 @@ static int ov6650_set_selection(struct v4l2_subdev *sd,
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct ov6650 *priv = to_ov6650(client);
-       struct v4l2_rect rect = sel->r;
        int ret;
 
        if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE ||
            sel->target != V4L2_SEL_TGT_CROP)
                return -EINVAL;
 
-       v4l_bound_align_image(&rect.width, 2, W_CIF, 1,
-                             &rect.height, 2, H_CIF, 1, 0);
-       v4l_bound_align_image(&rect.left, DEF_HSTRT << 1,
-                             (DEF_HSTRT << 1) + W_CIF - (__s32)rect.width, 1,
-                             &rect.top, DEF_VSTRT << 1,
-                             (DEF_VSTRT << 1) + H_CIF - (__s32)rect.height, 1,
-                             0);
+       v4l_bound_align_image(&sel->r.width, 2, W_CIF, 1,
+                             &sel->r.height, 2, H_CIF, 1, 0);
+       v4l_bound_align_image(&sel->r.left, DEF_HSTRT << 1,
+                             (DEF_HSTRT << 1) + W_CIF - (__s32)sel->r.width, 1,
+                             &sel->r.top, DEF_VSTRT << 1,
+                             (DEF_VSTRT << 1) + H_CIF - (__s32)sel->r.height,
+                             1, 0);
 
-       ret = ov6650_reg_write(client, REG_HSTRT, rect.left >> 1);
+       ret = ov6650_reg_write(client, REG_HSTRT, sel->r.left >> 1);
        if (!ret) {
-               priv->rect.left = rect.left;
+               priv->rect.left = sel->r.left;
                ret = ov6650_reg_write(client, REG_HSTOP,
-                               (rect.left + rect.width) >> 1);
+                                      (sel->r.left + sel->r.width) >> 1);
        }
        if (!ret) {
-               priv->rect.width = rect.width;
-               ret = ov6650_reg_write(client, REG_VSTRT, rect.top >> 1);
+               priv->rect.width = sel->r.width;
+               ret = ov6650_reg_write(client, REG_VSTRT, sel->r.top >> 1);
        }
        if (!ret) {
-               priv->rect.top = rect.top;
+               priv->rect.top = sel->r.top;
                ret = ov6650_reg_write(client, REG_VSTOP,
-                               (rect.top + rect.height) >> 1);
+                                      (sel->r.top + sel->r.height) >> 1);
        }
        if (!ret)
-               priv->rect.height = rect.height;
+               priv->rect.height = sel->r.height;
 
        return ret;
 }
@@ -512,11 +521,13 @@ static int ov6650_get_fmt(struct v4l2_subdev *sd,
        if (format->pad)
                return -EINVAL;
 
+       /* initialize response with default media bus frame format */
+       *mf = ov6650_def_fmt;
+
+       /* update media bus format code and frame size */
        mf->width       = priv->rect.width >> priv->half_scale;
        mf->height      = priv->rect.height >> priv->half_scale;
        mf->code        = priv->code;
-       mf->colorspace  = priv->colorspace;
-       mf->field       = V4L2_FIELD_NONE;
 
        return 0;
 }
@@ -623,11 +634,6 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
                priv->pclk_max = 8000000;
        }
 
-       if (code == MEDIA_BUS_FMT_SBGGR8_1X8)
-               priv->colorspace = V4L2_COLORSPACE_SRGB;
-       else if (code != 0)
-               priv->colorspace = V4L2_COLORSPACE_JPEG;
-
        if (half_scale) {
                dev_dbg(&client->dev, "max resolution: QCIF\n");
                coma_set |= COMA_QCIF;
@@ -657,11 +663,6 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
        if (!ret)
                ret = ov6650_reg_rmw(client, REG_COML, coml_set, coml_mask);
 
-       if (!ret) {
-               mf->colorspace  = priv->colorspace;
-               mf->width = priv->rect.width >> half_scale;
-               mf->height = priv->rect.height >> half_scale;
-       }
        return ret;
 }
 
@@ -680,8 +681,6 @@ static int ov6650_set_fmt(struct v4l2_subdev *sd,
                v4l_bound_align_image(&mf->width, 2, W_CIF, 1,
                                &mf->height, 2, H_CIF, 1, 0);
 
-       mf->field = V4L2_FIELD_NONE;
-
        switch (mf->code) {
        case MEDIA_BUS_FMT_Y10_1X10:
                mf->code = MEDIA_BUS_FMT_Y8_1X8;
@@ -691,20 +690,39 @@ static int ov6650_set_fmt(struct v4l2_subdev *sd,
        case MEDIA_BUS_FMT_YUYV8_2X8:
        case MEDIA_BUS_FMT_VYUY8_2X8:
        case MEDIA_BUS_FMT_UYVY8_2X8:
-               mf->colorspace = V4L2_COLORSPACE_JPEG;
                break;
        default:
                mf->code = MEDIA_BUS_FMT_SBGGR8_1X8;
                /* fall through */
        case MEDIA_BUS_FMT_SBGGR8_1X8:
-               mf->colorspace = V4L2_COLORSPACE_SRGB;
                break;
        }
 
-       if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
-               return ov6650_s_fmt(sd, mf);
-       cfg->try_fmt = *mf;
+       if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
+               /* store media bus format code and frame size in pad config */
+               cfg->try_fmt.width = mf->width;
+               cfg->try_fmt.height = mf->height;
+               cfg->try_fmt.code = mf->code;
 
+               /* return default mbus frame format updated with pad config */
+               *mf = ov6650_def_fmt;
+               mf->width = cfg->try_fmt.width;
+               mf->height = cfg->try_fmt.height;
+               mf->code = cfg->try_fmt.code;
+
+       } else {
+               /* apply new media bus format code and frame size */
+               int ret = ov6650_s_fmt(sd, mf);
+
+               if (ret)
+                       return ret;
+
+               /* return default format updated with active size and code */
+               *mf = ov6650_def_fmt;
+               mf->width = priv->rect.width >> priv->half_scale;
+               mf->height = priv->rect.height >> priv->half_scale;
+               mf->code = priv->code;
+       }
        return 0;
 }
 
@@ -989,8 +1007,10 @@ static int ov6650_probe(struct i2c_client *client,
                        V4L2_CID_GAMMA, 0, 0xff, 1, 0x12);
 
        priv->subdev.ctrl_handler = &priv->hdl;
-       if (priv->hdl.error)
-               return priv->hdl.error;
+       if (priv->hdl.error) {
+               ret = priv->hdl.error;
+               goto ectlhdlfree;
+       }
 
        v4l2_ctrl_auto_cluster(2, &priv->autogain, 0, true);
        v4l2_ctrl_auto_cluster(3, &priv->autowb, 0, true);
@@ -1003,13 +1023,14 @@ static int ov6650_probe(struct i2c_client *client,
        priv->rect.height = H_CIF;
        priv->half_scale  = false;
        priv->code        = MEDIA_BUS_FMT_YUYV8_2X8;
-       priv->colorspace  = V4L2_COLORSPACE_JPEG;
 
        priv->subdev.internal_ops = &ov6650_internal_ops;
 
        ret = v4l2_async_register_subdev(&priv->subdev);
-       if (ret)
-               v4l2_ctrl_handler_free(&priv->hdl);
+       if (!ret)
+               return 0;
+ectlhdlfree:
+       v4l2_ctrl_handler_free(&priv->hdl);
 
        return ret;
 }
@@ -1041,6 +1062,6 @@ static struct i2c_driver ov6650_i2c_driver = {
 
 module_i2c_driver(ov6650_i2c_driver);
 
-MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV6650");
-MODULE_AUTHOR("Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>");
+MODULE_DESCRIPTION("V4L2 subdevice driver for OmniVision OV6650 camera sensor");
+MODULE_AUTHOR("Janusz Krzysztofik <jmkrzyszt@gmail.com");
 MODULE_LICENSE("GPL v2");