}
 }
 
+static void ov6650_bind_align_crop_rectangle(struct v4l2_rect *rect)
+{
+       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);
+}
+
 static int ov6650_set_selection(struct v4l2_subdev *sd,
                struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_selection *sel)
            sel->target != V4L2_SEL_TGT_CROP)
                return -EINVAL;
 
-       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);
+       ov6650_bind_align_crop_rectangle(&sel->r);
 
        ret = ov6650_reg_write(client, REG_HSTRT, sel->r.left >> 1);
        if (!ret) {
 #define to_clkrc(div)  ((div) - 1)
 
 /* set the format we will capture in */
-static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
+static int ov6650_s_fmt(struct v4l2_subdev *sd, u32 code, bool half_scale)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct ov6650 *priv = to_ov6650(client);
-       bool half_scale = !is_unscaled_ok(mf->width, mf->height, &priv->rect);
-       struct v4l2_subdev_selection sel = {
-               .which = V4L2_SUBDEV_FORMAT_ACTIVE,
-               .target = V4L2_SEL_TGT_CROP,
-               .r.left = priv->rect.left + (priv->rect.width >> 1) -
-                       (mf->width >> (1 - half_scale)),
-               .r.top = priv->rect.top + (priv->rect.height >> 1) -
-                       (mf->height >> (1 - half_scale)),
-               .r.width = mf->width << half_scale,
-               .r.height = mf->height << half_scale,
-       };
-       u32 code = mf->code;
        u8 coma_set = 0, coma_mask = 0, coml_set, coml_mask;
        int ret;
 
                coma_mask |= COMA_QCIF;
        }
 
-       ret = ov6650_set_selection(sd, NULL, &sel);
-       if (!ret)
-               ret = ov6650_reg_rmw(client, REG_COMA, coma_set, coma_mask);
+       ret = ov6650_reg_rmw(client, REG_COMA, coma_set, coma_mask);
        if (!ret) {
                priv->half_scale = half_scale;
 
        struct v4l2_mbus_framefmt *mf = &format->format;
        struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct ov6650 *priv = to_ov6650(client);
+       struct v4l2_subdev_selection sel = {
+               .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+               .target = V4L2_SEL_TGT_CROP,
+       };
+       struct v4l2_rect *crop = &sel.r;
+       bool half_scale;
 
        if (format->pad)
                return -EINVAL;
 
-       if (is_unscaled_ok(mf->width, mf->height, &priv->rect))
-               v4l_bound_align_image(&mf->width, 2, W_CIF, 1,
-                               &mf->height, 2, H_CIF, 1, 0);
-
        switch (mf->code) {
        case MEDIA_BUS_FMT_Y10_1X10:
                mf->code = MEDIA_BUS_FMT_Y8_1X8;
                break;
        }
 
+       *crop = priv->rect;
+       half_scale = !is_unscaled_ok(mf->width, mf->height, crop);
+
+       /* adjust new crop rectangle position against its current center */
+       crop->left += (crop->width - (mf->width << half_scale)) / 2;
+       crop->top += (crop->height - (mf->height << half_scale)) / 2;
+       /* adjust new crop rectangle size */
+       crop->width = mf->width << half_scale;
+       crop->height = mf->height << half_scale;
+
        if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
-               /* store media bus format code and frame size in pad config */
-               sd_state->pads->try_fmt.width = mf->width;
-               sd_state->pads->try_fmt.height = mf->height;
+               /* store new crop rectangle, hadware bound, in pad config */
+               ov6650_bind_align_crop_rectangle(crop);
+               sd_state->pads->try_crop = *crop;
+
+               /* store new mbus frame format code and size in pad config */
+               sd_state->pads->try_fmt.width = crop->width >> half_scale;
+               sd_state->pads->try_fmt.height = crop->height >> half_scale;
                sd_state->pads->try_fmt.code = mf->code;
 
                /* return default mbus frame format updated with pad config */
                mf->code = sd_state->pads->try_fmt.code;
 
        } else {
-               /* apply new media bus format code and frame size */
-               int ret = ov6650_s_fmt(sd, mf);
+               int ret;
 
+               /* apply new crop rectangle */
+               ret = ov6650_set_selection(sd, NULL, &sel);
+               if (ret)
+                       return ret;
+
+               /* apply new media bus frame format and scaling if changed */
+               if (mf->code != priv->code || half_scale != priv->half_scale)
+                       ret = ov6650_s_fmt(sd, mf->code, half_scale);
                if (ret)
                        return ret;
 
        if (!ret)
                ret = ov6650_prog_dflt(client, xclk->clkrc);
        if (!ret) {
-               struct v4l2_mbus_framefmt mf = ov6650_def_fmt;
-
-               ret = ov6650_s_fmt(sd, &mf);
+               /* driver default frame format, no scaling */
+               ret = ov6650_s_fmt(sd, ov6650_def_fmt.code, false);
        }
        if (!ret)
                ret = v4l2_ctrl_handler_setup(&priv->hdl);