return 0;
 }
 
-static int stop_streaming(struct vb2_queue *q)
+static void fimc_m2m_job_finish(struct fimc_ctx *ctx, int vb_state)
 {
-       struct fimc_ctx *ctx = q->drv_priv;
+       struct vb2_buffer *src_vb, *dst_vb;
        struct fimc_dev *fimc = ctx->fimc_dev;
 
+       if (!ctx || !ctx->m2m_ctx)
+               return;
+
+       src_vb = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+       dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
+
+       if (src_vb && dst_vb) {
+               v4l2_m2m_buf_done(src_vb, vb_state);
+               v4l2_m2m_buf_done(dst_vb, vb_state);
+               v4l2_m2m_job_finish(fimc->m2m.m2m_dev, ctx->m2m_ctx);
+       }
+}
+
+/* Complete the transaction which has been scheduled for execution. */
+static void fimc_m2m_shutdown(struct fimc_ctx *ctx)
+{
+       struct fimc_dev *fimc = ctx->fimc_dev;
+       int ret;
+
        if (!fimc_m2m_pending(fimc))
-               return 0;
+               return;
 
-       set_bit(ST_M2M_SHUT, &fimc->state);
+       fimc_ctx_state_lock_set(FIMC_CTX_SHUT, ctx);
 
-       wait_event_timeout(fimc->irq_queue,
-                          !test_bit(ST_M2M_SHUT, &fimc->state),
+       ret = wait_event_timeout(fimc->irq_queue,
+                          !fimc_ctx_state_is_set(FIMC_CTX_SHUT, ctx),
                           FIMC_SHUTDOWN_TIMEOUT);
+       /*
+        * In case of a timeout the buffers are not released in the interrupt
+        * handler so return them here with the error flag set, if there are
+        * any on the queue.
+        */
+       if (ret == 0)
+               fimc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR);
+}
+
+static int stop_streaming(struct vb2_queue *q)
+{
+       struct fimc_ctx *ctx = q->drv_priv;
+
+       fimc_m2m_shutdown(ctx);
 
        return 0;
 }
 
-static void fimc_capture_handler(struct fimc_dev *fimc)
+static void fimc_capture_irq_handler(struct fimc_dev *fimc)
 {
        struct fimc_vid_cap *cap = &fimc->vid_cap;
        struct fimc_vid_buffer *v_buf;
 {
        struct fimc_dev *fimc = priv;
        struct fimc_vid_cap *cap = &fimc->vid_cap;
+       struct fimc_ctx *ctx;
 
-       BUG_ON(!fimc);
        fimc_hw_clear_irq(fimc);
 
-       spin_lock(&fimc->slock);
+       if (test_and_clear_bit(ST_M2M_PEND, &fimc->state)) {
+               ctx = v4l2_m2m_get_curr_priv(fimc->m2m.m2m_dev);
+               if (ctx != NULL) {
+                       fimc_m2m_job_finish(ctx, VB2_BUF_STATE_DONE);
 
-       if (test_and_clear_bit(ST_M2M_SHUT, &fimc->state)) {
-               wake_up(&fimc->irq_queue);
-               goto isr_unlock;
-       } else if (test_and_clear_bit(ST_M2M_PEND, &fimc->state)) {
-               struct vb2_buffer *src_vb, *dst_vb;
-               struct fimc_ctx *ctx = v4l2_m2m_get_curr_priv(fimc->m2m.m2m_dev);
-
-               if (!ctx || !ctx->m2m_ctx)
-                       goto isr_unlock;
-
-               src_vb = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
-               dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
-               if (src_vb && dst_vb) {
-                       v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
-                       v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
-                       v4l2_m2m_job_finish(fimc->m2m.m2m_dev, ctx->m2m_ctx);
+                       spin_lock(&ctx->slock);
+                       if (ctx->state & FIMC_CTX_SHUT) {
+                               ctx->state &= ~FIMC_CTX_SHUT;
+                               wake_up(&fimc->irq_queue);
+                       }
+                       spin_unlock(&ctx->slock);
                }
-               goto isr_unlock;
 
+               return IRQ_HANDLED;
        }
 
+       spin_lock(&fimc->slock);
+
        if (test_bit(ST_CAPT_PEND, &fimc->state)) {
                fimc_capture_irq_handler(fimc);
 
                }
        }
 
-isr_unlock:
        spin_unlock(&fimc->slock);
        return IRQ_HANDLED;
 }
 
        ctx->state |= (FIMC_SRC_ADDR | FIMC_DST_ADDR);
        ret = fimc_prepare_config(ctx, ctx->state);
-       if (ret) {
-               err("Wrong parameters");
+       if (ret)
                goto dma_unlock;
-       }
+
        /* Reconfigure hardware if the context has changed. */
        if (fimc->m2m.ctx != ctx) {
                ctx->state |= FIMC_PARAMS;
                fimc->m2m.ctx = ctx;
        }
 
+       spin_lock(&fimc->slock);
        fimc_hw_set_input_addr(fimc, &ctx->s_frame.paddr);
 
        if (ctx->state & FIMC_PARAMS) {
                fimc_hw_set_input_path(ctx);
                fimc_hw_set_in_dma(ctx);
-               if (fimc_set_scaler_info(ctx)) {
-                       err("Scaler setup error");
+               ret = fimc_set_scaler_info(ctx);
+               if (ret) {
+                       spin_unlock(&fimc->slock);
                        goto dma_unlock;
                }
-
                fimc_hw_set_prescaler(ctx);
                fimc_hw_set_mainscaler(ctx);
                fimc_hw_set_target_format(ctx);
        ctx->state &= (FIMC_CTX_M2M | FIMC_CTX_CAP |
                       FIMC_SRC_FMT | FIMC_DST_FMT);
        fimc_hw_activate_input_dma(fimc, true);
+       spin_unlock(&fimc->slock);
 
 dma_unlock:
        spin_unlock_irqrestore(&ctx->slock, flags);
 
 static void fimc_job_abort(void *priv)
 {
-       struct fimc_ctx *ctx = priv;
-       struct fimc_dev *fimc = ctx->fimc_dev;
-
-       if (!fimc_m2m_pending(fimc))
-               return;
-
-       set_bit(ST_M2M_SHUT, &fimc->state);
-
-       wait_event_timeout(fimc->irq_queue,
-                          !test_bit(ST_M2M_SHUT, &fimc->state),
-                          FIMC_SHUTDOWN_TIMEOUT);
+       fimc_m2m_shutdown(priv);
 }
 
 static int fimc_queue_setup(struct vb2_queue *vq, unsigned int *num_buffers,
 
 
        if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
-               if (ctx->state & FIMC_CTX_CAP)
+               if (fimc_ctx_state_is_set(FIMC_CTX_CAP, ctx))
                        return -EINVAL;
                is_output = 1;
        } else if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
        struct vb2_queue *vq;
        struct fimc_frame *frame;
        struct v4l2_pix_format_mplane *pix;
-       unsigned long flags;
        int i, ret = 0;
-       u32 tmp;
 
        ret = fimc_vidioc_try_fmt_mplane(file, priv, f);
        if (ret)
        frame->offs_h   = 0;
        frame->offs_v   = 0;
 
-       spin_lock_irqsave(&ctx->slock, flags);
-       tmp = (frame == &ctx->d_frame) ? FIMC_DST_FMT : FIMC_SRC_FMT;
-       ctx->state |= FIMC_PARAMS | tmp;
-       spin_unlock_irqrestore(&ctx->slock, flags);
+       if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+               fimc_ctx_state_lock_set(FIMC_PARAMS | FIMC_DST_FMT, ctx);
+       else
+               fimc_ctx_state_lock_set(FIMC_PARAMS | FIMC_SRC_FMT, ctx);
 
        dbg("f_w: %d, f_h: %d", frame->f_width, frame->f_height);
 
 
        /* The source and target color format need to be set */
        if (V4L2_TYPE_IS_OUTPUT(type)) {
-               if (~ctx->state & FIMC_SRC_FMT)
+               if (!fimc_ctx_state_is_set(FIMC_SRC_FMT, ctx))
                        return -EINVAL;
-       } else if (~ctx->state & FIMC_DST_FMT) {
+       } else if (!fimc_ctx_state_is_set(FIMC_DST_FMT, ctx)) {
                return -EINVAL;
        }
 
                return 0;
        }
 
-       if (ctx->state & FIMC_CTX_CAP) {
+       if (fimc_ctx_state_is_set(FIMC_CTX_CAP, ctx)) {
                return v4l2_subdev_call(ctx->fimc_dev->vid_cap.sd,
                                        core, queryctrl, qc);
        }
                ctrl->value = ctx->rotation;
                break;
        default:
-               if (ctx->state & FIMC_CTX_CAP) {
+               if (fimc_ctx_state_is_set(FIMC_CTX_CAP, ctx)) {
                        return v4l2_subdev_call(fimc->vid_cap.sd, core,
                                                g_ctrl, ctrl);
                } else {
-                       v4l2_err(&fimc->m2m.v4l2_dev,
-                                "Invalid control\n");
+                       v4l2_err(&fimc->m2m.v4l2_dev, "Invalid control\n");
                        return -EINVAL;
                }
        }
 {
        struct samsung_fimc_variant *variant = ctx->fimc_dev->variant;
        struct fimc_dev *fimc = ctx->fimc_dev;
-       unsigned long flags;
        int ret = 0;
 
-       spin_lock_irqsave(&ctx->slock, flags);
-
        switch (ctrl->id) {
        case V4L2_CID_HFLIP:
                if (ctrl->value)
                break;
 
        case V4L2_CID_ROTATE:
-               if (!(~ctx->state & (FIMC_DST_FMT | FIMC_SRC_FMT))) {
+               if (fimc_ctx_state_is_set(FIMC_DST_FMT | FIMC_SRC_FMT, ctx)) {
                        ret = fimc_check_scaler_ratio(ctx->s_frame.width,
-                                                     ctx->s_frame.height,
-                                                     ctx->d_frame.width,
-                                                     ctx->d_frame.height,
-                                                     ctrl->value);
-                       if (ret) {
-                               v4l2_err(&fimc->m2m.v4l2_dev,
-                                        "Out of scaler range");
-                               spin_unlock_irqrestore(&ctx->slock, flags);
-                               return -EINVAL;
-                       }
+                                       ctx->s_frame.height, ctx->d_frame.width,
+                                       ctx->d_frame.height, ctrl->value);
+               }
+
+               if (ret) {
+                       v4l2_err(&fimc->m2m.v4l2_dev, "Out of scaler range\n");
+                       return -EINVAL;
                }
 
                /* Check for the output rotator availability */
                if ((ctrl->value == 90 || ctrl->value == 270) &&
-                   (ctx->in_path == FIMC_DMA && !variant->has_out_rot)) {
-                       spin_unlock_irqrestore(&ctx->slock, flags);
+                   (ctx->in_path == FIMC_DMA && !variant->has_out_rot))
                        return -EINVAL;
-               } else {
-                       ctx->rotation = ctrl->value;
-               }
+               ctx->rotation = ctrl->value;
                break;
 
        default:
-               spin_unlock_irqrestore(&ctx->slock, flags);
                v4l2_err(&fimc->m2m.v4l2_dev, "Invalid control\n");
                return -EINVAL;
        }
-       ctx->state |= FIMC_PARAMS;
-       spin_unlock_irqrestore(&ctx->slock, flags);
+
+       fimc_ctx_state_lock_set(FIMC_PARAMS, ctx);
 
        return 0;
 }
        struct fimc_dev *fimc = ctx->fimc_dev;
        struct fimc_frame *f;
        u32 min_size, halign, depth = 0;
+       bool is_capture_ctx;
        int i;
 
        if (cr->c.top < 0 || cr->c.left < 0) {
                return -EINVAL;
        }
 
+       is_capture_ctx = fimc_ctx_state_is_set(FIMC_CTX_CAP, ctx);
+
        if (cr->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
-               f = (ctx->state & FIMC_CTX_CAP) ? &ctx->s_frame : &ctx->d_frame;
+               f = is_capture_ctx ? &ctx->s_frame : &ctx->d_frame;
        else if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
-                ctx->state & FIMC_CTX_M2M)
+                !is_capture_ctx)
                f = &ctx->s_frame;
        else
                return -EINVAL;
        min_size = (f == &ctx->s_frame) ?
                fimc->variant->min_inp_pixsize : fimc->variant->min_out_pixsize;
 
-       if (ctx->state & FIMC_CTX_M2M) {
+       /* Get pixel alignment constraints. */
+       if (is_capture_ctx) {
+               min_size = 16;
+               halign = 4;
+       } else {
                if (fimc->id == 1 && fimc->variant->pix_hoff)
                        halign = fimc_fmt_is_rgb(f->fmt->color) ? 0 : 1;
                else
                        halign = ffs(min_size) - 1;
-       /* there are more strict aligment requirements at camera interface */
-       } else {
-               min_size = 16;
-               halign = 4;
        }
 
        for (i = 0; i < f->fmt->colplanes; i++)
                cr->c.top = f->o_height - cr->c.height;
 
        cr->c.left = round_down(cr->c.left, min_size);
-       cr->c.top  = round_down(cr->c.top,
-                               ctx->state & FIMC_CTX_M2M ? 8 : 16);
+       cr->c.top  = round_down(cr->c.top, is_capture_ctx ? 16 : 8);
 
        dbg("l:%d, t:%d, w:%d, h:%d, f_w: %d, f_h: %d",
            cr->c.left, cr->c.top, cr->c.width, cr->c.height,
        return 0;
 }
 
-
 static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr)
 {
        struct fimc_ctx *ctx = file->private_data;
        struct fimc_dev *fimc = ctx->fimc_dev;
-       unsigned long flags;
        struct fimc_frame *f;
        int ret;
 
        f = (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ?
                &ctx->s_frame : &ctx->d_frame;
 
-       spin_lock_irqsave(&ctx->slock, flags);
        /* Check to see if scaling ratio is within supported range */
-       if (!(~ctx->state & (FIMC_DST_FMT | FIMC_SRC_FMT))) {
+       if (fimc_ctx_state_is_set(FIMC_DST_FMT | FIMC_SRC_FMT, ctx)) {
                if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
                        ret = fimc_check_scaler_ratio(cr->c.width, cr->c.height,
                                                      ctx->d_frame.width,
                                                      cr->c.width, cr->c.height,
                                                      ctx->rotation);
                }
-
                if (ret) {
-                       v4l2_err(&fimc->m2m.v4l2_dev, "Out of scaler range");
-                       spin_unlock_irqrestore(&ctx->slock, flags);
+                       v4l2_err(&fimc->m2m.v4l2_dev, "Out of scaler range\n");
                        return -EINVAL;
                }
        }
 
-       ctx->state |= FIMC_PARAMS;
-
        f->offs_h = cr->c.left;
        f->offs_v = cr->c.top;
        f->width  = cr->c.width;
        f->height = cr->c.height;
 
-       spin_unlock_irqrestore(&ctx->slock, flags);
+       fimc_ctx_state_lock_set(FIMC_PARAMS, ctx);
+
        return 0;
 }