staging: bcm2835-camera: Fix duplicate definition of module information
[platform/kernel/linux-rpi.git] / drivers / staging / vc04_services / bcm2835-camera / bcm2835-camera.c
index c04bdf0..a8f3ce5 100644 (file)
@@ -4,10 +4,11 @@
  *
  * Copyright © 2013 Raspberry Pi (Trading) Ltd.
  *
- * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
- *          Dave Stevenson <dsteve@broadcom.com>
- *          Simon Mellor <simellor@broadcom.com>
- *          Luke Diamand <luked@broadcom.com>
+ * Authors: Vincent Sanders @ Collabora
+ *          Dave Stevenson @ Broadcom
+ *             (now dave.stevenson@raspberrypi.org)
+ *          Simon Mellor @ Broadcom
+ *          Luke Diamand @ Broadcom
  */
 
 #include <linux/errno.h>
 
 #define MAX_BCM2835_CAMERAS 2
 
-MODULE_DESCRIPTION("Broadcom 2835 MMAL video capture");
-MODULE_AUTHOR("Vincent Sanders");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(BM2835_MMAL_VERSION);
-
 int bcm2835_v4l2_debug;
 module_param_named(debug, bcm2835_v4l2_debug, int, 0644);
 MODULE_PARM_DESC(bcm2835_v4l2_debug, "Debug level 0-2");
@@ -76,6 +72,12 @@ static const struct v4l2_fract
        tpf_max     = {.numerator = 1,          .denominator = FPS_MIN},
        tpf_default = {.numerator = 1000,       .denominator = 30000};
 
+/* Container for MMAL and VB2 buffers*/
+struct vb2_mmal_buffer {
+       struct vb2_v4l2_buffer  vb;
+       struct mmal_buffer      mmal;
+};
+
 /* video formats */
 static struct mmal_fmt formats[] = {
        {
@@ -84,7 +86,7 @@ static struct mmal_fmt formats[] = {
                .flags = 0,
                .mmal = MMAL_ENCODING_I420,
                .depth = 12,
-               .mmal_component = MMAL_COMPONENT_CAMERA,
+               .mmal_component = COMP_CAMERA,
                .ybbp = 1,
                .remove_padding = 1,
        }, {
@@ -93,7 +95,7 @@ static struct mmal_fmt formats[] = {
                .flags = 0,
                .mmal = MMAL_ENCODING_YUYV,
                .depth = 16,
-               .mmal_component = MMAL_COMPONENT_CAMERA,
+               .mmal_component = COMP_CAMERA,
                .ybbp = 2,
                .remove_padding = 0,
        }, {
@@ -102,7 +104,7 @@ static struct mmal_fmt formats[] = {
                .flags = 0,
                .mmal = MMAL_ENCODING_RGB24,
                .depth = 24,
-               .mmal_component = MMAL_COMPONENT_CAMERA,
+               .mmal_component = COMP_CAMERA,
                .ybbp = 3,
                .remove_padding = 0,
        }, {
@@ -111,7 +113,7 @@ static struct mmal_fmt formats[] = {
                .flags = V4L2_FMT_FLAG_COMPRESSED,
                .mmal = MMAL_ENCODING_JPEG,
                .depth = 8,
-               .mmal_component = MMAL_COMPONENT_IMAGE_ENCODE,
+               .mmal_component = COMP_IMAGE_ENCODE,
                .ybbp = 0,
                .remove_padding = 0,
        }, {
@@ -120,7 +122,7 @@ static struct mmal_fmt formats[] = {
                .flags = V4L2_FMT_FLAG_COMPRESSED,
                .mmal = MMAL_ENCODING_H264,
                .depth = 8,
-               .mmal_component = MMAL_COMPONENT_VIDEO_ENCODE,
+               .mmal_component = COMP_VIDEO_ENCODE,
                .ybbp = 0,
                .remove_padding = 0,
        }, {
@@ -129,7 +131,7 @@ static struct mmal_fmt formats[] = {
                .flags = V4L2_FMT_FLAG_COMPRESSED,
                .mmal = MMAL_ENCODING_MJPEG,
                .depth = 8,
-               .mmal_component = MMAL_COMPONENT_VIDEO_ENCODE,
+               .mmal_component = COMP_VIDEO_ENCODE,
                .ybbp = 0,
                .remove_padding = 0,
        }, {
@@ -138,7 +140,7 @@ static struct mmal_fmt formats[] = {
                .flags = 0,
                .mmal = MMAL_ENCODING_YVYU,
                .depth = 16,
-               .mmal_component = MMAL_COMPONENT_CAMERA,
+               .mmal_component = COMP_CAMERA,
                .ybbp = 2,
                .remove_padding = 0,
        }, {
@@ -147,7 +149,7 @@ static struct mmal_fmt formats[] = {
                .flags = 0,
                .mmal = MMAL_ENCODING_VYUY,
                .depth = 16,
-               .mmal_component = MMAL_COMPONENT_CAMERA,
+               .mmal_component = COMP_CAMERA,
                .ybbp = 2,
                .remove_padding = 0,
        }, {
@@ -156,7 +158,7 @@ static struct mmal_fmt formats[] = {
                .flags = 0,
                .mmal = MMAL_ENCODING_UYVY,
                .depth = 16,
-               .mmal_component = MMAL_COMPONENT_CAMERA,
+               .mmal_component = COMP_CAMERA,
                .ybbp = 2,
                .remove_padding = 0,
        }, {
@@ -165,7 +167,7 @@ static struct mmal_fmt formats[] = {
                .flags = 0,
                .mmal = MMAL_ENCODING_NV12,
                .depth = 12,
-               .mmal_component = MMAL_COMPONENT_CAMERA,
+               .mmal_component = COMP_CAMERA,
                .ybbp = 1,
                .remove_padding = 1,
        }, {
@@ -174,7 +176,7 @@ static struct mmal_fmt formats[] = {
                .flags = 0,
                .mmal = MMAL_ENCODING_BGR24,
                .depth = 24,
-               .mmal_component = MMAL_COMPONENT_CAMERA,
+               .mmal_component = COMP_CAMERA,
                .ybbp = 3,
                .remove_padding = 0,
        }, {
@@ -183,7 +185,7 @@ static struct mmal_fmt formats[] = {
                .flags = 0,
                .mmal = MMAL_ENCODING_YV12,
                .depth = 12,
-               .mmal_component = MMAL_COMPONENT_CAMERA,
+               .mmal_component = COMP_CAMERA,
                .ybbp = 1,
                .remove_padding = 1,
        }, {
@@ -192,7 +194,7 @@ static struct mmal_fmt formats[] = {
                .flags = 0,
                .mmal = MMAL_ENCODING_NV21,
                .depth = 12,
-               .mmal_component = MMAL_COMPONENT_CAMERA,
+               .mmal_component = COMP_CAMERA,
                .ybbp = 1,
                .remove_padding = 1,
        }, {
@@ -201,7 +203,7 @@ static struct mmal_fmt formats[] = {
                .flags = 0,
                .mmal = MMAL_ENCODING_BGRA,
                .depth = 32,
-               .mmal_component = MMAL_COMPONENT_CAMERA,
+               .mmal_component = COMP_CAMERA,
                .ybbp = 4,
                .remove_padding = 0,
        },
@@ -240,6 +242,22 @@ static int queue_setup(struct vb2_queue *vq,
                return -EINVAL;
        }
 
+       /* Handle CREATE_BUFS situation - *nplanes != 0 */
+       if (*nplanes) {
+               if (*nplanes != 1 ||
+                   sizes[0] < dev->capture.port->current_buffer.size) {
+                       v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+                                "%s: dev:%p Invalid buffer request from CREATE_BUFS, size %u < %u, nplanes %u != 1\n",
+                                __func__, dev, sizes[0],
+                                dev->capture.port->current_buffer.size,
+                                *nplanes);
+                       return -EINVAL;
+               } else {
+                       return 0;
+               }
+       }
+
+       /* Handle REQBUFS situation */
        size = dev->capture.port->current_buffer.size;
        if (size == 0) {
                v4l2_err(&dev->v4l2_dev,
@@ -271,14 +289,15 @@ static int buffer_init(struct vb2_buffer *vb)
 {
        struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
        struct vb2_v4l2_buffer *vb2 = to_vb2_v4l2_buffer(vb);
-       struct mmal_buffer *buf = container_of(vb2, struct mmal_buffer, vb);
+       struct vb2_mmal_buffer *buf =
+                               container_of(vb2, struct vb2_mmal_buffer, vb);
 
        v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "%s: dev:%p, vb %p\n",
                 __func__, dev, vb);
-       buf->buffer = vb2_plane_vaddr(&buf->vb.vb2_buf, 0);
-       buf->buffer_size = vb2_plane_size(&buf->vb.vb2_buf, 0);
+       buf->mmal.buffer = vb2_plane_vaddr(&buf->vb.vb2_buf, 0);
+       buf->mmal.buffer_size = vb2_plane_size(&buf->vb.vb2_buf, 0);
 
-       return mmal_vchi_buffer_init(dev->instance, buf);
+       return mmal_vchi_buffer_init(dev->instance, &buf->mmal);
 }
 
 static int buffer_prepare(struct vb2_buffer *vb)
@@ -307,31 +326,34 @@ static void buffer_cleanup(struct vb2_buffer *vb)
 {
        struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
        struct vb2_v4l2_buffer *vb2 = to_vb2_v4l2_buffer(vb);
-       struct mmal_buffer *buf = container_of(vb2, struct mmal_buffer, vb);
+       struct vb2_mmal_buffer *buf =
+                               container_of(vb2, struct vb2_mmal_buffer, vb);
 
        v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "%s: dev:%p, vb %p\n",
                 __func__, dev, vb);
-       mmal_vchi_buffer_cleanup(buf);
+
+       mmal_vchi_buffer_cleanup(&buf->mmal);
 }
 
 static inline bool is_capturing(struct bm2835_mmal_dev *dev)
 {
        return dev->capture.camera_port ==
-           &dev->
-           component[MMAL_COMPONENT_CAMERA]->output[MMAL_CAMERA_PORT_CAPTURE];
+           &dev->component[COMP_CAMERA]->output[CAM_PORT_CAPTURE];
 }
 
 static void buffer_cb(struct vchiq_mmal_instance *instance,
                      struct vchiq_mmal_port *port,
                      int status,
-                     struct mmal_buffer *buf,
-                     unsigned long length, u32 mmal_flags, s64 dts, s64 pts)
+                     struct mmal_buffer *mmal_buf)
 {
        struct bm2835_mmal_dev *dev = port->cb_ctx;
+       struct vb2_mmal_buffer *buf =
+                       container_of(mmal_buf, struct vb2_mmal_buffer, mmal);
 
        v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
                 "%s: status:%d, buf:%p, length:%lu, flags %u, pts %lld\n",
-                __func__, status, buf, length, mmal_flags, pts);
+                __func__, status, buf, mmal_buf->length, mmal_buf->mmal_flags,
+                mmal_buf->pts);
 
        if (status != 0) {
                /* error in transfer */
@@ -340,18 +362,17 @@ static void buffer_cb(struct vchiq_mmal_instance *instance,
                        vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
                }
                return;
-       } else if (length == 0) {
+       }
+
+       if (mmal_buf->length == 0) {
                /* stream ended */
-               if (buf) {
-                       /* this should only ever happen if the port is
-                        * disabled and there are buffers still queued
+               if (dev->capture.frame_count) {
+                       /* empty buffer whilst capturing - expected to be an
+                        * EOS, so grab another frame
                         */
-                       vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
-                       pr_debug("Empty buffer");
-               } else if (dev->capture.frame_count) {
-                       /* grab another frame */
                        if (is_capturing(dev)) {
-                               pr_debug("Grab another frame");
+                               v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+                                        "Grab another frame");
                                vchiq_mmal_port_parameter_set(
                                        instance,
                                        dev->capture.camera_port,
@@ -359,49 +380,89 @@ static void buffer_cb(struct vchiq_mmal_instance *instance,
                                        &dev->capture.frame_count,
                                        sizeof(dev->capture.frame_count));
                        }
+                       if (vchiq_mmal_submit_buffer(instance, port,
+                                                    &buf->mmal))
+                               v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+                                        "Failed to return EOS buffer");
                } else {
-                       /* signal frame completion */
+                       /* stopping streaming.
+                        * return buffer, and signal frame completion
+                        */
+                       vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
                        complete(&dev->capture.frame_cmplt);
                }
-       } else {
-               if (dev->capture.frame_count) {
-                       if (dev->capture.vc_start_timestamp != -1 &&
-                           pts != 0) {
-                               ktime_t timestamp;
-                               s64 runtime_us = pts -
-                                   dev->capture.vc_start_timestamp;
-                               timestamp = ktime_add_us(dev->capture.kernel_start_ts,
-                                                        runtime_us);
-                               v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
-                                        "Convert start time %llu and %llu with offset %llu to %llu\n",
-                                        ktime_to_ns(dev->capture.kernel_start_ts),
-                                        dev->capture.vc_start_timestamp, pts,
-                                        ktime_to_ns(timestamp));
-                               buf->vb.vb2_buf.timestamp = ktime_to_ns(timestamp);
-                       } else {
-                               buf->vb.vb2_buf.timestamp = ktime_get_ns();
-                       }
+               return;
+       }
 
-                       vb2_set_plane_payload(&buf->vb.vb2_buf, 0, length);
-                       vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
+       if (!dev->capture.frame_count) {
+               /* signal frame completion */
+               vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
+               complete(&dev->capture.frame_cmplt);
+               return;
+       }
 
-                       if (mmal_flags & MMAL_BUFFER_HEADER_FLAG_EOS &&
-                           is_capturing(dev)) {
-                               v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
-                                        "Grab another frame as buffer has EOS");
-                               vchiq_mmal_port_parameter_set(
-                                       instance,
-                                       dev->capture.camera_port,
-                                       MMAL_PARAMETER_CAPTURE,
-                                       &dev->capture.frame_count,
-                                       sizeof(dev->capture.frame_count));
-                       }
+       if (dev->capture.vc_start_timestamp == -1) {
+               /*
+                * VPU doesn't support MMAL_PARAMETER_SYSTEM_TIME, rely on
+                * kernel time, and have no latency compensation.
+                */
+               buf->vb.vb2_buf.timestamp = ktime_get_ns();
+               v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+                        "Buffer time set as current time - %lld",
+                        buf->vb.vb2_buf.timestamp);
+       } else if (mmal_buf->pts != 0) {
+               ktime_t timestamp;
+               s64 runtime_us = mmal_buf->pts -
+                   dev->capture.vc_start_timestamp;
+               timestamp = ktime_add_us(dev->capture.kernel_start_ts,
+                                        runtime_us);
+               v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+                        "Convert start time %llu and %llu with offset %llu to %llu\n",
+                        ktime_to_ns(dev->capture.kernel_start_ts),
+                        dev->capture.vc_start_timestamp, mmal_buf->pts,
+                        ktime_to_ns(timestamp));
+               if (timestamp < dev->capture.last_timestamp) {
+                       v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+                                "Negative delta - using last time\n");
+                       timestamp = dev->capture.last_timestamp;
+               }
+               buf->vb.vb2_buf.timestamp = ktime_to_ns(timestamp);
+       } else {
+               if (dev->capture.last_timestamp) {
+                       buf->vb.vb2_buf.timestamp = dev->capture.last_timestamp;
+                       v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+                                "Buffer time set as last timestamp - %lld",
+                                buf->vb.vb2_buf.timestamp);
                } else {
-                       /* signal frame completion */
-                       vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
-                       complete(&dev->capture.frame_cmplt);
+                       buf->vb.vb2_buf.timestamp =
+                               ktime_to_ns(dev->capture.kernel_start_ts);
+                       v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+                                "Buffer time set as start timestamp - %lld",
+                                buf->vb.vb2_buf.timestamp);
                }
        }
+       dev->capture.last_timestamp = buf->vb.vb2_buf.timestamp;
+       buf->vb.sequence = dev->capture.sequence++;
+       buf->vb.field = V4L2_FIELD_NONE;
+
+       vb2_set_plane_payload(&buf->vb.vb2_buf, 0, mmal_buf->length);
+       if (mmal_buf->mmal_flags & MMAL_BUFFER_HEADER_FLAG_KEYFRAME)
+               buf->vb.flags |= V4L2_BUF_FLAG_KEYFRAME;
+
+       v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+                "Buffer has ts %llu", dev->capture.last_timestamp);
+       vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
+
+       if (mmal_buf->mmal_flags & MMAL_BUFFER_HEADER_FLAG_EOS &&
+           is_capturing(dev)) {
+               v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+                        "Grab another frame as buffer has EOS");
+               vchiq_mmal_port_parameter_set(instance,
+                                             dev->capture.camera_port,
+                                             MMAL_PARAMETER_CAPTURE,
+                                             &dev->capture.frame_count,
+                                             sizeof(dev->capture.frame_count));
+       }
 }
 
 static int enable_camera(struct bm2835_mmal_dev *dev)
@@ -411,7 +472,7 @@ static int enable_camera(struct bm2835_mmal_dev *dev)
        if (!dev->camera_use_count) {
                ret = vchiq_mmal_port_parameter_set(
                        dev->instance,
-                       &dev->component[MMAL_COMPONENT_CAMERA]->control,
+                       &dev->component[COMP_CAMERA]->control,
                        MMAL_PARAMETER_CAMERA_NUM, &dev->camera_num,
                        sizeof(dev->camera_num));
                if (ret < 0) {
@@ -422,7 +483,7 @@ static int enable_camera(struct bm2835_mmal_dev *dev)
 
                ret = vchiq_mmal_component_enable(
                                dev->instance,
-                               dev->component[MMAL_COMPONENT_CAMERA]);
+                               dev->component[COMP_CAMERA]);
                if (ret < 0) {
                        v4l2_err(&dev->v4l2_dev,
                                 "Failed enabling camera, ret %d\n", ret);
@@ -454,7 +515,7 @@ static int disable_camera(struct bm2835_mmal_dev *dev)
                ret =
                    vchiq_mmal_component_disable(
                                dev->instance,
-                               dev->component[MMAL_COMPONENT_CAMERA]);
+                               dev->component[COMP_CAMERA]);
                if (ret < 0) {
                        v4l2_err(&dev->v4l2_dev,
                                 "Failed disabling camera, ret %d\n", ret);
@@ -462,7 +523,7 @@ static int disable_camera(struct bm2835_mmal_dev *dev)
                }
                vchiq_mmal_port_parameter_set(
                        dev->instance,
-                       &dev->component[MMAL_COMPONENT_CAMERA]->control,
+                       &dev->component[COMP_CAMERA]->control,
                        MMAL_PARAMETER_CAMERA_NUM, &i,
                        sizeof(i));
        }
@@ -475,14 +536,16 @@ static void buffer_queue(struct vb2_buffer *vb)
 {
        struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
        struct vb2_v4l2_buffer *vb2 = to_vb2_v4l2_buffer(vb);
-       struct mmal_buffer *buf = container_of(vb2, struct mmal_buffer, vb);
+       struct vb2_mmal_buffer *buf =
+                               container_of(vb2, struct vb2_mmal_buffer, vb);
        int ret;
 
        v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
                 "%s: dev:%p buf:%p, idx %u\n",
                 __func__, dev, buf, vb2->vb2_buf.index);
 
-       ret = vchiq_mmal_submit_buffer(dev->instance, dev->capture.port, buf);
+       ret = vchiq_mmal_submit_buffer(dev->instance, dev->capture.port,
+                                      &buf->mmal);
        if (ret < 0)
                v4l2_err(&dev->v4l2_dev, "%s: error submitting buffer\n",
                         __func__);
@@ -511,15 +574,18 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count)
        /* enable frame capture */
        dev->capture.frame_count = 1;
 
+       /* reset sequence number */
+       dev->capture.sequence = 0;
+
        /* if the preview is not already running, wait for a few frames for AGC
         * to settle down.
         */
-       if (!dev->component[MMAL_COMPONENT_PREVIEW]->enabled)
+       if (!dev->component[COMP_PREVIEW]->enabled)
                msleep(300);
 
        /* enable the connection from camera to encoder (if applicable) */
-       if (dev->capture.camera_port != dev->capture.port
-           && dev->capture.camera_port) {
+       if (dev->capture.camera_port != dev->capture.port &&
+           dev->capture.camera_port) {
                ret = vchiq_mmal_port_enable(dev->instance,
                                             dev->capture.camera_port, NULL);
                if (ret) {
@@ -542,12 +608,14 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count)
 
                /* Flag to indicate just to rely on kernel timestamps */
                dev->capture.vc_start_timestamp = -1;
-       } else
+       } else {
                v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
                         "Start time %lld size %d\n",
                         dev->capture.vc_start_timestamp, parameter_size);
+       }
 
        dev->capture.kernel_start_ts = ktime_get();
+       dev->capture.last_timestamp = 0;
 
        /* enable the camera port */
        dev->capture.port->cb_ctx = dev;
@@ -555,8 +623,8 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count)
            vchiq_mmal_port_enable(dev->instance, dev->capture.port, buffer_cb);
        if (ret) {
                v4l2_err(&dev->v4l2_dev,
-                       "Failed to enable capture port - error %d. Disabling camera port again\n",
-                       ret);
+                        "Failed to enable capture port - error %d. Disabling camera port again\n",
+                        ret);
 
                vchiq_mmal_port_disable(dev->instance,
                                        dev->capture.camera_port);
@@ -582,6 +650,7 @@ static void stop_streaming(struct vb2_queue *vq)
        int ret;
        unsigned long timeout;
        struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vq);
+       struct vchiq_mmal_port *port = dev->capture.port;
 
        v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "%s: dev:%p\n",
                 __func__, dev);
@@ -590,7 +659,7 @@ static void stop_streaming(struct vb2_queue *vq)
        dev->capture.frame_count = 0;
 
        /* ensure a format has actually been set */
-       if (!dev->capture.port) {
+       if (!port) {
                v4l2_err(&dev->v4l2_dev,
                         "no capture port - stream not started?\n");
                return;
@@ -605,26 +674,35 @@ static void stop_streaming(struct vb2_queue *vq)
                                      &dev->capture.frame_count,
                                      sizeof(dev->capture.frame_count));
 
-       /* wait for last frame to complete */
-       timeout = wait_for_completion_timeout(&dev->capture.frame_cmplt, HZ);
-       if (timeout == 0)
-               v4l2_err(&dev->v4l2_dev,
-                        "timed out waiting for frame completion\n");
-
        v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
                 "disabling connection\n");
 
        /* disable the connection from camera to encoder */
        ret = vchiq_mmal_port_disable(dev->instance, dev->capture.camera_port);
-       if (!ret && dev->capture.camera_port != dev->capture.port) {
+       if (!ret && dev->capture.camera_port != port) {
                v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
                         "disabling port\n");
-               ret = vchiq_mmal_port_disable(dev->instance, dev->capture.port);
-       } else if (dev->capture.camera_port != dev->capture.port) {
+               ret = vchiq_mmal_port_disable(dev->instance, port);
+       } else if (dev->capture.camera_port != port) {
                v4l2_err(&dev->v4l2_dev, "port_disable failed, error %d\n",
                         ret);
        }
 
+       /* wait for all buffers to be returned */
+       while (atomic_read(&port->buffers_with_vpu)) {
+               v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+                        "%s: Waiting for buffers to be returned - %d outstanding\n",
+                        __func__, atomic_read(&port->buffers_with_vpu));
+               timeout = wait_for_completion_timeout(&dev->capture.frame_cmplt,
+                                                     HZ);
+               if (timeout == 0) {
+                       v4l2_err(&dev->v4l2_dev, "%s: Timeout waiting for buffers to be returned - %d outstanding\n",
+                                __func__,
+                                atomic_read(&port->buffers_with_vpu));
+                       break;
+               }
+       }
+
        if (disable_camera(dev) < 0)
                v4l2_err(&dev->v4l2_dev, "Failed to disable camera\n");
 }
@@ -736,9 +814,9 @@ static int vidioc_s_fmt_vid_overlay(struct file *file, void *priv,
        vidioc_try_fmt_vid_overlay(file, priv, f);
 
        dev->overlay = f->fmt.win;
-       if (dev->component[MMAL_COMPONENT_PREVIEW]->enabled) {
+       if (dev->component[COMP_PREVIEW]->enabled) {
                set_overlay_params(dev,
-                                  &dev->component[MMAL_COMPONENT_PREVIEW]->input[0]);
+                                  &dev->component[COMP_PREVIEW]->input[0]);
        }
 
        return 0;
@@ -751,13 +829,12 @@ static int vidioc_overlay(struct file *file, void *f, unsigned int on)
        struct vchiq_mmal_port *src;
        struct vchiq_mmal_port *dst;
 
-       if ((on && dev->component[MMAL_COMPONENT_PREVIEW]->enabled) ||
-           (!on && !dev->component[MMAL_COMPONENT_PREVIEW]->enabled))
+       if ((on && dev->component[COMP_PREVIEW]->enabled) ||
+           (!on && !dev->component[COMP_PREVIEW]->enabled))
                return 0;       /* already in requested state */
 
        src =
-           &dev->component[MMAL_COMPONENT_CAMERA]->
-           output[MMAL_CAMERA_PORT_PREVIEW];
+           &dev->component[COMP_CAMERA]->output[CAM_PORT_PREVIEW];
 
        if (!on) {
                /* disconnect preview ports and disable component */
@@ -769,38 +846,40 @@ static int vidioc_overlay(struct file *file, void *f, unsigned int on)
                if (ret >= 0)
                        ret = vchiq_mmal_component_disable(
                                        dev->instance,
-                                       dev->component[MMAL_COMPONENT_PREVIEW]);
+                                       dev->component[COMP_PREVIEW]);
 
                disable_camera(dev);
                return ret;
        }
 
        /* set preview port format and connect it to output */
-       dst = &dev->component[MMAL_COMPONENT_PREVIEW]->input[0];
+       dst = &dev->component[COMP_PREVIEW]->input[0];
 
        ret = vchiq_mmal_port_set_format(dev->instance, src);
        if (ret < 0)
-               goto error;
+               return ret;
 
        ret = set_overlay_params(dev, dst);
        if (ret < 0)
-               goto error;
+               return ret;
 
-       if (enable_camera(dev) < 0)
-               goto error;
+       if (enable_camera(dev) < 0) {
+               ret = -EINVAL;
+               return ret;
+       }
 
        ret = vchiq_mmal_component_enable(
                        dev->instance,
-                       dev->component[MMAL_COMPONENT_PREVIEW]);
+                       dev->component[COMP_PREVIEW]);
        if (ret < 0)
-               goto error;
+               return ret;
 
        v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "connecting %p to %p\n",
                 src, dst);
        ret = vchiq_mmal_port_connect_tunnel(dev->instance, src, dst);
        if (!ret)
                ret = vchiq_mmal_port_enable(dev->instance, src, NULL);
-error:
+
        return ret;
 }
 
@@ -812,8 +891,7 @@ static int vidioc_g_fbuf(struct file *file, void *fh,
         */
        struct bm2835_mmal_dev *dev = video_drvdata(file);
        struct vchiq_mmal_port *preview_port =
-                   &dev->component[MMAL_COMPONENT_CAMERA]->
-                   output[MMAL_CAMERA_PORT_PREVIEW];
+               &dev->component[COMP_CAMERA]->output[CAM_PORT_PREVIEW];
 
        a->capability = V4L2_FBUF_CAP_EXTERNOVERLAY |
                        V4L2_FBUF_CAP_GLOBAL_ALPHA;
@@ -947,14 +1025,27 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
                              1, 0);
        f->fmt.pix.bytesperline = f->fmt.pix.width * mfmt->ybbp;
        if (!mfmt->remove_padding) {
-               int align_mask = ((32 * mfmt->depth) >> 3) - 1;
-               /* GPU isn't removing padding, so stride is aligned to 32 */
-               f->fmt.pix.bytesperline =
-                       (f->fmt.pix.bytesperline + align_mask) & ~align_mask;
+               if (mfmt->depth == 24) {
+                       /*
+                        * 24bpp is a pain as we can't use simple masking.
+                        * Min stride is width aligned to 16, times 24bpp.
+                        */
+                       f->fmt.pix.bytesperline =
+                               ((f->fmt.pix.width + 15) & ~15) * 3;
+               } else {
+                       /*
+                        * GPU isn't removing padding, so stride is aligned to
+                        * 32
+                        */
+                       int align_mask = ((32 * mfmt->depth) >> 3) - 1;
+
+                       f->fmt.pix.bytesperline =
+                               (f->fmt.pix.bytesperline + align_mask) &
+                                                       ~align_mask;
+               }
                v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
-                        "Not removing padding, so bytes/line = %d, "
-                        "(align_mask %d)\n",
-                        f->fmt.pix.bytesperline, align_mask);
+                        "Not removing padding, so bytes/line = %d\n",
+                        f->fmt.pix.bytesperline);
        }
 
        /* Image buffer has to be padded to allow for alignment, even though
@@ -1005,8 +1096,7 @@ static int mmal_setup_components(struct bm2835_mmal_dev *dev,
                                               dev->capture.camera_port, NULL);
                dev->capture.camera_port = NULL;
                ret = vchiq_mmal_component_disable(dev->instance,
-                                                  dev->capture.
-                                                  encode_component);
+                                                  dev->capture.encode_component);
                if (ret)
                        v4l2_err(&dev->v4l2_dev,
                                 "Failed to disable encode component %d\n",
@@ -1016,31 +1106,28 @@ static int mmal_setup_components(struct bm2835_mmal_dev *dev,
        }
        /* format dependent port setup */
        switch (mfmt->mmal_component) {
-       case MMAL_COMPONENT_CAMERA:
+       case COMP_CAMERA:
                /* Make a further decision on port based on resolution */
-               if (f->fmt.pix.width <= max_video_width
-                   && f->fmt.pix.height <= max_video_height)
-                       camera_port = port =
-                           &dev->component[MMAL_COMPONENT_CAMERA]->
-                           output[MMAL_CAMERA_PORT_VIDEO];
+               if (f->fmt.pix.width <= max_video_width &&
+                   f->fmt.pix.height <= max_video_height)
+                       camera_port =
+                           &dev->component[COMP_CAMERA]->output[CAM_PORT_VIDEO];
                else
-                       camera_port = port =
-                           &dev->component[MMAL_COMPONENT_CAMERA]->
-                           output[MMAL_CAMERA_PORT_CAPTURE];
+                       camera_port =
+                           &dev->component[COMP_CAMERA]->output[CAM_PORT_CAPTURE];
+               port = camera_port;
                break;
-       case MMAL_COMPONENT_IMAGE_ENCODE:
-               encode_component = dev->component[MMAL_COMPONENT_IMAGE_ENCODE];
-               port = &dev->component[MMAL_COMPONENT_IMAGE_ENCODE]->output[0];
+       case COMP_IMAGE_ENCODE:
+               encode_component = dev->component[COMP_IMAGE_ENCODE];
+               port = &dev->component[COMP_IMAGE_ENCODE]->output[0];
                camera_port =
-                   &dev->component[MMAL_COMPONENT_CAMERA]->
-                   output[MMAL_CAMERA_PORT_CAPTURE];
+                   &dev->component[COMP_CAMERA]->output[CAM_PORT_CAPTURE];
                break;
-       case MMAL_COMPONENT_VIDEO_ENCODE:
-               encode_component = dev->component[MMAL_COMPONENT_VIDEO_ENCODE];
-               port = &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->output[0];
+       case COMP_VIDEO_ENCODE:
+               encode_component = dev->component[COMP_VIDEO_ENCODE];
+               port = &dev->component[COMP_VIDEO_ENCODE]->output[0];
                camera_port =
-                   &dev->component[MMAL_COMPONENT_CAMERA]->
-                   output[MMAL_CAMERA_PORT_VIDEO];
+                   &dev->component[COMP_CAMERA]->output[CAM_PORT_VIDEO];
                break;
        default:
                break;
@@ -1080,15 +1167,13 @@ static int mmal_setup_components(struct bm2835_mmal_dev *dev,
 
        ret = vchiq_mmal_port_set_format(dev->instance, camera_port);
 
-       if (!ret
-           && camera_port ==
-           &dev->component[MMAL_COMPONENT_CAMERA]->
-           output[MMAL_CAMERA_PORT_VIDEO]) {
+       if (!ret &&
+           camera_port ==
+           &dev->component[COMP_CAMERA]->output[CAM_PORT_VIDEO]) {
                bool overlay_enabled =
-                   !!dev->component[MMAL_COMPONENT_PREVIEW]->enabled;
+                   !!dev->component[COMP_PREVIEW]->enabled;
                struct vchiq_mmal_port *preview_port =
-                   &dev->component[MMAL_COMPONENT_CAMERA]->
-                   output[MMAL_CAMERA_PORT_PREVIEW];
+                   &dev->component[COMP_CAMERA]->output[CAM_PORT_PREVIEW];
                /* Preview and encode ports need to match on resolution */
                if (overlay_enabled) {
                        /* Need to disable the overlay before we can update
@@ -1119,7 +1204,7 @@ static int mmal_setup_components(struct bm2835_mmal_dev *dev,
                        ret = vchiq_mmal_port_connect_tunnel(
                                dev->instance,
                                preview_port,
-                               &dev->component[MMAL_COMPONENT_PREVIEW]->input[0]);
+                               &dev->component[COMP_PREVIEW]->input[0]);
                        if (!ret)
                                ret = vchiq_mmal_port_enable(dev->instance,
                                                             preview_port,
@@ -1173,11 +1258,11 @@ static int mmal_setup_components(struct bm2835_mmal_dev *dev,
                                port->format.encoding_variant = 0;
                                /* Set any encoding specific parameters */
                                switch (mfmt->mmal_component) {
-                               case MMAL_COMPONENT_VIDEO_ENCODE:
+                               case COMP_VIDEO_ENCODE:
                                        port->format.bitrate =
                                            dev->capture.encode_bitrate;
                                        break;
-                               case MMAL_COMPONENT_IMAGE_ENCODE:
+                               case COMP_IMAGE_ENCODE:
                                        /* Could set EXIF parameters here */
                                        break;
                                default:
@@ -1221,9 +1306,8 @@ static int mmal_setup_components(struct bm2835_mmal_dev *dev,
                                                 port->current_buffer.size);
                                        port->current_buffer.size =
                                            (f->fmt.pix.sizeimage <
-                                            (100 << 10))
-                                           ? (100 << 10)
-                                           : f->fmt.pix.sizeimage;
+                                            (100 << 10)) ?
+                                           (100 << 10) : f->fmt.pix.sizeimage;
                                }
                                v4l2_dbg(1, bcm2835_v4l2_debug,
                                         &dev->v4l2_dev,
@@ -1307,7 +1391,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
 }
 
 static int vidioc_enum_framesizes(struct file *file, void *fh,
-                          struct v4l2_frmsizeenum *fsize)
+                                 struct v4l2_frmsizeenum *fsize)
 {
        struct bm2835_mmal_dev *dev = video_drvdata(file);
        static const struct v4l2_frmsize_stepwise sizes = {
@@ -1544,17 +1628,22 @@ static int mmal_init(struct bm2835_mmal_dev *dev)
        struct vchiq_mmal_component  *camera;
 
        ret = vchiq_mmal_init(&dev->instance);
-       if (ret < 0)
+       if (ret < 0) {
+               v4l2_err(&dev->v4l2_dev, "%s: vchiq mmal init failed %d\n",
+                        __func__, ret);
                return ret;
+       }
 
        /* get the camera component ready */
        ret = vchiq_mmal_component_init(dev->instance, "ril.camera",
-                                       &dev->component[MMAL_COMPONENT_CAMERA]);
+                                       &dev->component[COMP_CAMERA]);
        if (ret < 0)
                goto unreg_mmal;
 
-       camera = dev->component[MMAL_COMPONENT_CAMERA];
-       if (camera->outputs <  MMAL_CAMERA_PORT_COUNT) {
+       camera = dev->component[COMP_CAMERA];
+       if (camera->outputs < CAM_PORT_COUNT) {
+               v4l2_err(&dev->v4l2_dev, "%s: too few camera outputs %d needed %d\n",
+                        __func__, camera->outputs, CAM_PORT_COUNT);
                ret = -EINVAL;
                goto unreg_camera;
        }
@@ -1562,8 +1651,11 @@ static int mmal_init(struct bm2835_mmal_dev *dev)
        ret = set_camera_parameters(dev->instance,
                                    camera,
                                    dev);
-       if (ret < 0)
+       if (ret < 0) {
+               v4l2_err(&dev->v4l2_dev, "%s: unable to set camera parameters: %d\n",
+                        __func__, ret);
                goto unreg_camera;
+       }
 
        /* There was an error in the firmware that meant the camera component
         * produced BGR instead of RGB.
@@ -1573,7 +1665,7 @@ static int mmal_init(struct bm2835_mmal_dev *dev)
        dev->rgb_bgr_swapped = true;
        param_size = sizeof(supported_encodings);
        ret = vchiq_mmal_port_parameter_get(dev->instance,
-                                           &camera->output[MMAL_CAMERA_PORT_CAPTURE],
+                                           &camera->output[CAM_PORT_CAPTURE],
                                            MMAL_PARAMETER_SUPPORTED_ENCODINGS,
                                            &supported_encodings,
                                            &param_size);
@@ -1594,7 +1686,7 @@ static int mmal_init(struct bm2835_mmal_dev *dev)
                        }
                }
        }
-       format = &camera->output[MMAL_CAMERA_PORT_PREVIEW].format;
+       format = &camera->output[CAM_PORT_PREVIEW].format;
 
        format->encoding = MMAL_ENCODING_OPAQUE;
        format->encoding_variant = MMAL_ENCODING_I420;
@@ -1608,7 +1700,7 @@ static int mmal_init(struct bm2835_mmal_dev *dev)
        format->es->video.frame_rate.num = 0; /* Rely on fps_range */
        format->es->video.frame_rate.den = 1;
 
-       format = &camera->output[MMAL_CAMERA_PORT_VIDEO].format;
+       format = &camera->output[CAM_PORT_VIDEO].format;
 
        format->encoding = MMAL_ENCODING_OPAQUE;
        format->encoding_variant = MMAL_ENCODING_I420;
@@ -1622,7 +1714,7 @@ static int mmal_init(struct bm2835_mmal_dev *dev)
        format->es->video.frame_rate.num = 0; /* Rely on fps_range */
        format->es->video.frame_rate.den = 1;
 
-       format = &camera->output[MMAL_CAMERA_PORT_CAPTURE].format;
+       format = &camera->output[CAM_PORT_CAPTURE].format;
 
        format->encoding = MMAL_ENCODING_OPAQUE;
 
@@ -1646,50 +1738,49 @@ static int mmal_init(struct bm2835_mmal_dev *dev)
        /* get the preview component ready */
        ret = vchiq_mmal_component_init(
                        dev->instance, "ril.video_render",
-                       &dev->component[MMAL_COMPONENT_PREVIEW]);
+                       &dev->component[COMP_PREVIEW]);
        if (ret < 0)
                goto unreg_camera;
 
-       if (dev->component[MMAL_COMPONENT_PREVIEW]->inputs < 1) {
+       if (dev->component[COMP_PREVIEW]->inputs < 1) {
                ret = -EINVAL;
-               pr_debug("too few input ports %d needed %d\n",
-                        dev->component[MMAL_COMPONENT_PREVIEW]->inputs, 1);
+               v4l2_err(&dev->v4l2_dev, "%s: too few input ports %d needed %d\n",
+                        __func__, dev->component[COMP_PREVIEW]->inputs, 1);
                goto unreg_preview;
        }
 
        /* get the image encoder component ready */
        ret = vchiq_mmal_component_init(
                dev->instance, "ril.image_encode",
-               &dev->component[MMAL_COMPONENT_IMAGE_ENCODE]);
+               &dev->component[COMP_IMAGE_ENCODE]);
        if (ret < 0)
                goto unreg_preview;
 
-       if (dev->component[MMAL_COMPONENT_IMAGE_ENCODE]->inputs < 1) {
+       if (dev->component[COMP_IMAGE_ENCODE]->inputs < 1) {
                ret = -EINVAL;
-               v4l2_err(&dev->v4l2_dev, "too few input ports %d needed %d\n",
-                        dev->component[MMAL_COMPONENT_IMAGE_ENCODE]->inputs,
+               v4l2_err(&dev->v4l2_dev, "%s: too few input ports %d needed %d\n",
+                        __func__, dev->component[COMP_IMAGE_ENCODE]->inputs,
                         1);
                goto unreg_image_encoder;
        }
 
        /* get the video encoder component ready */
        ret = vchiq_mmal_component_init(dev->instance, "ril.video_encode",
-                                       &dev->
-                                       component[MMAL_COMPONENT_VIDEO_ENCODE]);
+                                       &dev->component[COMP_VIDEO_ENCODE]);
        if (ret < 0)
                goto unreg_image_encoder;
 
-       if (dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->inputs < 1) {
+       if (dev->component[COMP_VIDEO_ENCODE]->inputs < 1) {
                ret = -EINVAL;
-               v4l2_err(&dev->v4l2_dev, "too few input ports %d needed %d\n",
-                        dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->inputs,
+               v4l2_err(&dev->v4l2_dev, "%s: too few input ports %d needed %d\n",
+                        __func__, dev->component[COMP_VIDEO_ENCODE]->inputs,
                         1);
                goto unreg_vid_encoder;
        }
 
        {
                struct vchiq_mmal_port *encoder_port =
-                       &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->output[0];
+                       &dev->component[COMP_VIDEO_ENCODE]->output[0];
                encoder_port->format.encoding = MMAL_ENCODING_H264;
                ret = vchiq_mmal_port_set_format(dev->instance,
                                                 encoder_port);
@@ -1700,19 +1791,22 @@ static int mmal_init(struct bm2835_mmal_dev *dev)
 
                vchiq_mmal_port_parameter_set(
                        dev->instance,
-                       &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->control,
+                       &dev->component[COMP_VIDEO_ENCODE]->control,
                        MMAL_PARAMETER_VIDEO_IMMUTABLE_INPUT,
                        &enable, sizeof(enable));
 
                vchiq_mmal_port_parameter_set(dev->instance,
-                                             &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->control,
+                                             &dev->component[COMP_VIDEO_ENCODE]->control,
                                              MMAL_PARAMETER_MINIMISE_FRAGMENTATION,
                                              &enable,
                                              sizeof(enable));
        }
        ret = bm2835_mmal_set_all_camera_controls(dev);
-       if (ret < 0)
+       if (ret < 0) {
+               v4l2_err(&dev->v4l2_dev, "%s: failed to set all camera controls: %d\n",
+                        __func__, ret);
                goto unreg_vid_encoder;
+       }
 
        return 0;
 
@@ -1720,23 +1814,23 @@ unreg_vid_encoder:
        pr_err("Cleanup: Destroy video encoder\n");
        vchiq_mmal_component_finalise(
                dev->instance,
-               dev->component[MMAL_COMPONENT_VIDEO_ENCODE]);
+               dev->component[COMP_VIDEO_ENCODE]);
 
 unreg_image_encoder:
        pr_err("Cleanup: Destroy image encoder\n");
        vchiq_mmal_component_finalise(
                dev->instance,
-               dev->component[MMAL_COMPONENT_IMAGE_ENCODE]);
+               dev->component[COMP_IMAGE_ENCODE]);
 
 unreg_preview:
        pr_err("Cleanup: Destroy video render\n");
        vchiq_mmal_component_finalise(dev->instance,
-                                     dev->component[MMAL_COMPONENT_PREVIEW]);
+                                     dev->component[COMP_PREVIEW]);
 
 unreg_camera:
        pr_err("Cleanup: Destroy camera\n");
        vchiq_mmal_component_finalise(dev->instance,
-                                     dev->component[MMAL_COMPONENT_CAMERA]);
+                                     dev->component[COMP_CAMERA]);
 
 unreg_mmal:
        vchiq_mmal_finalise(dev->instance);
@@ -1792,21 +1886,19 @@ static void bcm2835_cleanup_instance(struct bm2835_mmal_dev *dev)
                                             dev->capture.encode_component);
        }
        vchiq_mmal_component_disable(dev->instance,
-                                    dev->component[MMAL_COMPONENT_CAMERA]);
+                                    dev->component[COMP_CAMERA]);
 
        vchiq_mmal_component_finalise(dev->instance,
-                                     dev->
-                                     component[MMAL_COMPONENT_VIDEO_ENCODE]);
+                                     dev->component[COMP_VIDEO_ENCODE]);
 
        vchiq_mmal_component_finalise(dev->instance,
-                                     dev->
-                                     component[MMAL_COMPONENT_IMAGE_ENCODE]);
+                                     dev->component[COMP_IMAGE_ENCODE]);
 
        vchiq_mmal_component_finalise(dev->instance,
-                                     dev->component[MMAL_COMPONENT_PREVIEW]);
+                                     dev->component[COMP_PREVIEW]);
 
        vchiq_mmal_component_finalise(dev->instance,
-                                     dev->component[MMAL_COMPONENT_CAMERA]);
+                                     dev->component[COMP_CAMERA]);
 
        v4l2_ctrl_handler_free(&dev->ctrl_handler);
 
@@ -1841,6 +1933,12 @@ static int bcm2835_mmal_probe(struct platform_device *pdev)
        num_cameras = get_num_cameras(instance,
                                      resolutions,
                                      MAX_BCM2835_CAMERAS);
+
+       if (num_cameras < 1) {
+               ret = -ENODEV;
+               goto cleanup_mmal;
+       }
+
        if (num_cameras > MAX_BCM2835_CAMERAS)
                num_cameras = MAX_BCM2835_CAMERAS;
 
@@ -1872,28 +1970,36 @@ static int bcm2835_mmal_probe(struct platform_device *pdev)
                snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name),
                         "%s", BM2835_MMAL_MODULE_NAME);
                ret = v4l2_device_register(NULL, &dev->v4l2_dev);
-               if (ret)
+               if (ret) {
+                       dev_err(&pdev->dev, "%s: could not register V4L2 device: %d\n",
+                               __func__, ret);
                        goto free_dev;
+               }
 
                /* setup v4l controls */
                ret = bm2835_mmal_init_controls(dev, &dev->ctrl_handler);
-               if (ret < 0)
+               if (ret < 0) {
+                       v4l2_err(&dev->v4l2_dev, "%s: could not init controls: %d\n",
+                                __func__, ret);
                        goto unreg_dev;
+               }
                dev->v4l2_dev.ctrl_handler = &dev->ctrl_handler;
 
                /* mmal init */
                dev->instance = instance;
                ret = mmal_init(dev);
-               if (ret < 0)
+               if (ret < 0) {
+                       v4l2_err(&dev->v4l2_dev, "%s: mmal init failed: %d\n",
+                                __func__, ret);
                        goto unreg_dev;
-
+               }
                /* initialize queue */
                q = &dev->capture.vb_vidq;
                memset(q, 0, sizeof(*q));
                q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
                q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
                q->drv_priv = dev;
-               q->buf_struct_size = sizeof(struct mmal_buffer);
+               q->buf_struct_size = sizeof(struct vb2_mmal_buffer);
                q->ops = &bm2835_mmal_video_qops;
                q->mem_ops = &vb2_vmalloc_memops;
                q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
@@ -1904,16 +2010,19 @@ static int bcm2835_mmal_probe(struct platform_device *pdev)
 
                /* initialise video devices */
                ret = bm2835_mmal_init_device(dev, &dev->vdev);
-               if (ret < 0)
+               if (ret < 0) {
+                       v4l2_err(&dev->v4l2_dev, "%s: could not init device: %d\n",
+                                __func__, ret);
                        goto unreg_dev;
+               }
 
                /* Really want to call vidioc_s_fmt_vid_cap with the default
                 * format, but currently the APIs don't join up.
                 */
                ret = mmal_setup_components(dev, &default_v4l2_format);
                if (ret < 0) {
-                       v4l2_err(&dev->v4l2_dev,
-                                "%s: could not setup components\n", __func__);
+                       v4l2_err(&dev->v4l2_dev, "%s: could not setup components: %d\n",
+                                __func__, ret);
                        goto unreg_dev;
                }
 
@@ -1937,8 +2046,9 @@ cleanup_gdev:
                bcm2835_cleanup_instance(gdev[i]);
                gdev[i] = NULL;
        }
-       pr_info("%s: error %d while loading driver\n",
-               BM2835_MMAL_MODULE_NAME, ret);
+
+cleanup_mmal:
+       vchiq_mmal_finalise(instance);
 
        return ret;
 }
@@ -1966,3 +2076,9 @@ static struct platform_driver bcm2835_camera_driver = {
 };
 
 module_platform_driver(bcm2835_camera_driver)
+
+MODULE_DESCRIPTION("Broadcom 2835 MMAL video capture");
+MODULE_AUTHOR("Vincent Sanders");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(BM2835_MMAL_VERSION);
+MODULE_ALIAS("platform:bcm2835-camera");