struct s5p_mfc_ctx *ctx = fh_to_ctx(file->private_data);
        struct s5p_mfc_dev *dev = ctx->dev;
 
+       /* if dev is null, do cleanup that doesn't need dev */
        mfc_debug_enter();
-       mutex_lock(&dev->mfc_mutex);
+       if (dev)
+               mutex_lock(&dev->mfc_mutex);
        s5p_mfc_clock_on();
        vb2_queue_release(&ctx->vq_src);
        vb2_queue_release(&ctx->vq_dst);
-       /* Mark context as idle */
-       clear_work_bit_irqsave(ctx);
-       /* If instance was initialised and not yet freed,
-        * return instance and free resources */
-       if (ctx->state != MFCINST_FREE && ctx->state != MFCINST_INIT) {
-               mfc_debug(2, "Has to free instance\n");
-               s5p_mfc_close_mfc_inst(dev, ctx);
-       }
-       /* hardware locking scheme */
-       if (dev->curr_ctx == ctx->num)
-               clear_bit(0, &dev->hw_lock);
-       dev->num_inst--;
-       if (dev->num_inst == 0) {
-               mfc_debug(2, "Last instance\n");
-               s5p_mfc_deinit_hw(dev);
-               del_timer_sync(&dev->watchdog_timer);
-               if (s5p_mfc_power_off() < 0)
-                       mfc_err("Power off failed\n");
+       if (dev) {
+               /* Mark context as idle */
+               clear_work_bit_irqsave(ctx);
+               /*
+                * If instance was initialised and not yet freed,
+                * return instance and free resources
+               */
+               if (ctx->state != MFCINST_FREE && ctx->state != MFCINST_INIT) {
+                       mfc_debug(2, "Has to free instance\n");
+                       s5p_mfc_close_mfc_inst(dev, ctx);
+               }
+               /* hardware locking scheme */
+               if (dev->curr_ctx == ctx->num)
+                       clear_bit(0, &dev->hw_lock);
+               dev->num_inst--;
+               if (dev->num_inst == 0) {
+                       mfc_debug(2, "Last instance\n");
+                       s5p_mfc_deinit_hw(dev);
+                       del_timer_sync(&dev->watchdog_timer);
+                       if (s5p_mfc_power_off() < 0)
+                               mfc_err("Power off failed\n");
+               }
        }
        mfc_debug(2, "Shutting down clock\n");
        s5p_mfc_clock_off();
-       dev->ctx[ctx->num] = NULL;
+       if (dev)
+               dev->ctx[ctx->num] = NULL;
        s5p_mfc_dec_ctrls_delete(ctx);
        v4l2_fh_del(&ctx->fh);
-       v4l2_fh_exit(&ctx->fh);
+       /* vdev is gone if dev is null */
+       if (dev)
+               v4l2_fh_exit(&ctx->fh);
        kfree(ctx);
        mfc_debug_leave();
-       mutex_unlock(&dev->mfc_mutex);
+       if (dev)
+               mutex_unlock(&dev->mfc_mutex);
+
        return 0;
 }
 
 static int s5p_mfc_remove(struct platform_device *pdev)
 {
        struct s5p_mfc_dev *dev = platform_get_drvdata(pdev);
+       struct s5p_mfc_ctx *ctx;
+       int i;
 
        v4l2_info(&dev->v4l2_dev, "Removing %s\n", pdev->name);
 
+       /*
+        * Clear ctx dev pointer to avoid races between s5p_mfc_remove()
+        * and s5p_mfc_release() and s5p_mfc_release() accessing ctx->dev
+        * after s5p_mfc_remove() is run during unbind.
+       */
+       mutex_lock(&dev->mfc_mutex);
+       for (i = 0; i < MFC_NUM_CONTEXTS; i++) {
+               ctx = dev->ctx[i];
+               if (!ctx)
+                       continue;
+               /* clear ctx->dev */
+               ctx->dev = NULL;
+       }
+       mutex_unlock(&dev->mfc_mutex);
+
        del_timer_sync(&dev->watchdog_timer);
        flush_workqueue(dev->watchdog_workqueue);
        destroy_workqueue(dev->watchdog_workqueue);