bcm27xx: remove linux 5.10 compatibility
[openwrt/staging/chunkeey.git] / target / linux / bcm27xx / patches-5.10 / 950-0213-media-bcm2835-unicam-Add-embedded-data-node.patch
diff --git a/target/linux/bcm27xx/patches-5.10/950-0213-media-bcm2835-unicam-Add-embedded-data-node.patch b/target/linux/bcm27xx/patches-5.10/950-0213-media-bcm2835-unicam-Add-embedded-data-node.patch
deleted file mode 100644 (file)
index 4fc8270..0000000
+++ /dev/null
@@ -1,1170 +0,0 @@
-From 0dae2f81f08fc6f8641e10b99c61e73314553d79 Mon Sep 17 00:00:00 2001
-From: Naushir Patuck <naush@raspberrypi.com>
-Date: Thu, 16 Apr 2020 11:35:41 +0100
-Subject: [PATCH] media: bcm2835-unicam: Add embedded data node.
-
-This patch adds a new node in the bcm2835-unicam driver to support
-CSI-2 embedded data streams.  The subdevice is queried to see if
-embedded data is available from the sensor.
-
-Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
----
- .../media/platform/bcm2835/bcm2835-unicam.c   | 667 +++++++++++++-----
- 1 file changed, 474 insertions(+), 193 deletions(-)
-
---- a/drivers/media/platform/bcm2835/bcm2835-unicam.c
-+++ b/drivers/media/platform/bcm2835/bcm2835-unicam.c
-@@ -109,8 +109,15 @@ MODULE_PARM_DESC(debug, "Debug level 0-3
- /* Define a nominal minimum image size */
- #define MIN_WIDTH     16
- #define MIN_HEIGHT    16
--/* Maximum number of simulataneous streams Uncaim can handle. */
--#define MAX_NODES     2
-+/* Default size of the embedded buffer */
-+#define UNICAM_EMBEDDED_SIZE  8192
-+
-+enum pad_types {
-+      IMAGE_PAD,
-+      METADATA_PAD,
-+      MAX_NODES
-+};
-+
- /*
-  * struct unicam_fmt - Unicam media bus format information
-  * @pixelformat: V4L2 pixel format FCC identifier. 0 if n/a.
-@@ -327,6 +334,12 @@ static const struct unicam_fmt formats[]
-               .depth          = 12,
-               .csi_dt         = 0x2c,
-       },
-+      /* Embedded data format */
-+      {
-+              .fourcc         = V4L2_META_FMT_SENSOR_DATA,
-+              .code           = MEDIA_BUS_FMT_SENSOR_DATA,
-+              .depth          = 8,
-+      }
- };
- struct unicam_dmaqueue {
-@@ -348,7 +361,9 @@ struct unicam_cfg {
- #define MAX_POSSIBLE_PIX_FMTS (ARRAY_SIZE(formats))
- struct unicam_node {
--      bool registered;
-+      int registered;
-+      int open;
-+      int streaming;
-       unsigned int pad_id;
-       /* Pointer pointing to current v4l2_buffer */
-       struct unicam_buffer *cur_frm;
-@@ -374,6 +389,7 @@ struct unicam_node {
-       struct unicam_device *dev;
-       struct media_pad pad;
-       struct v4l2_ctrl_handler ctrl_handler;
-+      unsigned int embedded_lines;
- };
- struct unicam_device {
-@@ -401,8 +417,6 @@ struct unicam_device {
-       struct v4l2_subdev *sensor;
-       /* Pad config for the sensor */
-       struct v4l2_subdev_pad_config *sensor_config;
--      /* current input at the sub device */
--      int current_input;
-       unsigned int virtual_channel;
-       enum v4l2_mbus_type bus_type;
-@@ -413,10 +427,7 @@ struct unicam_device {
-       unsigned int bus_flags;
-       unsigned int max_data_lanes;
-       unsigned int active_data_lanes;
--
--      struct v4l2_rect crop;
--      /* Flag to denote that we are processing buffers */
--      int streaming;
-+      bool sensor_embedded_data;
-       struct unicam_node node[MAX_NODES];
- };
-@@ -488,6 +499,7 @@ static int check_mbus_format(struct unic
-       for (i = 0; !ret && i < MAX_ENUM_MBUS_CODE; i++) {
-               memset(&mbus_code, 0, sizeof(mbus_code));
-               mbus_code.index = i;
-+              mbus_code.pad = IMAGE_PAD;
-               mbus_code.which = V4L2_SUBDEV_FORMAT_ACTIVE;
-               ret = v4l2_subdev_call(dev->sensor, pad, enum_mbus_code,
-@@ -552,10 +564,11 @@ static int __subdev_get_format(struct un
- }
- static int __subdev_set_format(struct unicam_device *dev,
--                             struct v4l2_mbus_framefmt *fmt)
-+                             struct v4l2_mbus_framefmt *fmt, int pad_id)
- {
-       struct v4l2_subdev_format sd_fmt = {
-               .which = V4L2_SUBDEV_FORMAT_ACTIVE,
-+              .pad = pad_id
-       };
-       int ret;
-@@ -566,8 +579,12 @@ static int __subdev_set_format(struct un
-       if (ret < 0)
-               return ret;
--      unicam_dbg(1, dev, "%s %dx%d code:%04x\n", __func__,
--                 fmt->width, fmt->height, fmt->code);
-+      if (pad_id == IMAGE_PAD)
-+              unicam_dbg(1, dev, "%s %dx%d code:%04x\n", __func__, fmt->width,
-+                         fmt->height, fmt->code);
-+      else
-+              unicam_dbg(1, dev, "%s Embedded data code:%04x\n", __func__,
-+                         sd_fmt.format.code);
-       return 0;
- }
-@@ -609,46 +626,70 @@ static int unicam_reset_format(struct un
-       struct v4l2_mbus_framefmt mbus_fmt;
-       int ret;
--      ret = __subdev_get_format(dev, &mbus_fmt, node->pad_id);
--      if (ret) {
--              unicam_err(dev, "Failed to get_format - ret %d\n", ret);
--              return ret;
--      }
-+      if (dev->sensor_embedded_data || node->pad_id != METADATA_PAD) {
-+              ret = __subdev_get_format(dev, &mbus_fmt, node->pad_id);
-+              if (ret) {
-+                      unicam_err(dev, "Failed to get_format - ret %d\n", ret);
-+                      return ret;
-+              }
--      if (mbus_fmt.code != dev->node[0].fmt->code) {
--              unicam_err(dev, "code mismatch - fmt->code %08x, mbus_fmt.code %08x\n",
--                         dev->node[0].fmt->code, mbus_fmt.code);
--              return ret;
-+              if (mbus_fmt.code != node->fmt->code) {
-+                      unicam_err(dev, "code mismatch - fmt->code %08x, mbus_fmt.code %08x\n",
-+                                 node->fmt->code, mbus_fmt.code);
-+                      return ret;
-+              }
-       }
--      v4l2_fill_pix_format(&dev->node[0].v_fmt.fmt.pix, &mbus_fmt);
--      dev->node[0].v_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
--
--      unicam_calc_format_size_bpl(dev, dev->node[0].fmt, &dev->node[0].v_fmt);
--
--      dev->node[0].m_fmt = mbus_fmt;
-+      if (node->pad_id == IMAGE_PAD) {
-+              v4l2_fill_pix_format(&node->v_fmt.fmt.pix, &mbus_fmt);
-+              node->v_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-+              unicam_calc_format_size_bpl(dev, node->fmt, &node->v_fmt);
-+      } else {
-+              node->v_fmt.type = V4L2_BUF_TYPE_META_CAPTURE;
-+              node->v_fmt.fmt.meta.dataformat = V4L2_META_FMT_SENSOR_DATA;
-+              if (dev->sensor_embedded_data) {
-+                      node->v_fmt.fmt.meta.buffersize =
-+                                      mbus_fmt.width * mbus_fmt.height;
-+                      node->embedded_lines = mbus_fmt.height;
-+              } else {
-+                      node->v_fmt.fmt.meta.buffersize = UNICAM_EMBEDDED_SIZE;
-+                      node->embedded_lines = 1;
-+              }
-+      }
-+      node->m_fmt = mbus_fmt;
-       return 0;
- }
--static void unicam_wr_dma_addr(struct unicam_device *dev, dma_addr_t dmaaddr)
-+static void unicam_wr_dma_addr(struct unicam_device *dev, dma_addr_t dmaaddr,
-+                             int pad_id)
- {
-+      dma_addr_t endaddr;
-+
-       /*
-        * dmaaddr should be a 32-bit address with the top two bits set to 0x3
-        * to signify uncached access through the Videocore memory controller.
-        */
-       BUG_ON((dmaaddr >> 30) != 0x3);
--      reg_write(&dev->cfg, UNICAM_IBSA0, dmaaddr);
--      reg_write(&dev->cfg, UNICAM_IBEA0,
--                dmaaddr + dev->node[0].v_fmt.fmt.pix.sizeimage);
-+      if (pad_id == IMAGE_PAD) {
-+              endaddr = dmaaddr +
-+                        dev->node[IMAGE_PAD].v_fmt.fmt.pix.sizeimage;
-+              reg_write(&dev->cfg, UNICAM_IBSA0, dmaaddr);
-+              reg_write(&dev->cfg, UNICAM_IBEA0, endaddr);
-+      } else {
-+              endaddr = dmaaddr +
-+                        dev->node[METADATA_PAD].v_fmt.fmt.meta.buffersize;
-+              reg_write(&dev->cfg, UNICAM_DBSA0, dmaaddr);
-+              reg_write(&dev->cfg, UNICAM_DBEA0, endaddr);
-+      }
- }
- static inline unsigned int unicam_get_lines_done(struct unicam_device *dev)
- {
-       dma_addr_t start_addr, cur_addr;
--      unsigned int stride = dev->node[0].v_fmt.fmt.pix.bytesperline;
--      struct unicam_buffer *frm = dev->node[0].cur_frm;
-+      unsigned int stride = dev->node[IMAGE_PAD].v_fmt.fmt.pix.bytesperline;
-+      struct unicam_buffer *frm = dev->node[IMAGE_PAD].cur_frm;
-       if (!frm)
-               return 0;
-@@ -658,27 +699,51 @@ static inline unsigned int unicam_get_li
-       return (unsigned int)(cur_addr - start_addr) / stride;
- }
--static inline void unicam_schedule_next_buffer(struct unicam_device *dev)
-+static inline void unicam_schedule_next_buffer(struct unicam_node *node)
- {
--      struct unicam_dmaqueue *dma_q = &dev->node[0].dma_queue;
-+      struct unicam_device *dev = node->dev;
-+      struct unicam_dmaqueue *dma_q = &node->dma_queue;
-       struct unicam_buffer *buf;
-       dma_addr_t addr;
-       buf = list_entry(dma_q->active.next, struct unicam_buffer, list);
--      dev->node[0].next_frm = buf;
-+      node->next_frm = buf;
-       list_del(&buf->list);
-       addr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0);
--      unicam_wr_dma_addr(dev, addr);
-+      unicam_wr_dma_addr(dev, addr, node->pad_id);
- }
--static inline void unicam_process_buffer_complete(struct unicam_device *dev)
-+static inline void unicam_process_buffer_complete(struct unicam_node *node,
-+                                                unsigned int sequence)
- {
--      dev->node[0].cur_frm->vb.field = dev->node[0].m_fmt.field;
--      dev->node[0].cur_frm->vb.sequence = dev->sequence++;
-+      node->cur_frm->vb.field = node->m_fmt.field;
-+      node->cur_frm->vb.sequence = sequence;
-+
-+      vb2_buffer_done(&node->cur_frm->vb.vb2_buf, VB2_BUF_STATE_DONE);
-+      node->cur_frm = node->next_frm;
-+}
--      vb2_buffer_done(&dev->node[0].cur_frm->vb.vb2_buf, VB2_BUF_STATE_DONE);
--      dev->node[0].cur_frm = dev->node[0].next_frm;
-+static int unicam_num_nodes_streaming(struct unicam_device *dev)
-+{
-+      return dev->node[IMAGE_PAD].streaming +
-+             dev->node[METADATA_PAD].streaming;
-+}
-+
-+static int unicam_all_nodes_streaming(struct unicam_device *dev)
-+{
-+      int ret;
-+
-+      ret = dev->node[IMAGE_PAD].open && dev->node[IMAGE_PAD].streaming;
-+      ret &= !dev->node[METADATA_PAD].open ||
-+             dev->node[METADATA_PAD].streaming;
-+      return ret;
-+}
-+
-+static int unicam_all_nodes_disabled(struct unicam_device *dev)
-+{
-+      return !dev->node[IMAGE_PAD].streaming &&
-+             !dev->node[METADATA_PAD].streaming;
- }
- /*
-@@ -693,10 +758,12 @@ static irqreturn_t unicam_isr(int irq, v
- {
-       struct unicam_device *unicam = (struct unicam_device *)dev;
-       struct unicam_cfg *cfg = &unicam->cfg;
--      struct unicam_dmaqueue *dma_q = &unicam->node[0].dma_queue;
-       unsigned int lines_done = unicam_get_lines_done(dev);
-       unsigned int sequence = unicam->sequence;
-+      int num_nodes_streaming = unicam_num_nodes_streaming(dev);
-       int ista, sta;
-+      u64 ts;
-+      int i;
-       /*
-        * Don't service interrupts if not streaming.
-@@ -704,7 +771,7 @@ static irqreturn_t unicam_isr(int irq, v
-        * peripheral without the kernel knowing (that
-        * shouldn't happen, but causes issues if it does).
-        */
--      if (!unicam->streaming)
-+      if (unicam_all_nodes_disabled(unicam))
-               return IRQ_HANDLED;
-       sta = reg_read(cfg, UNICAM_STA);
-@@ -726,9 +793,12 @@ static irqreturn_t unicam_isr(int irq, v
-                * Timestamp is to be when the first data byte was captured,
-                * aka frame start.
-                */
--              if (unicam->node[0].cur_frm)
--                      unicam->node[0].cur_frm->vb.vb2_buf.timestamp =
--                              ktime_get_ns();
-+              ts = ktime_get_ns();
-+              for (i = 0; i < num_nodes_streaming; i++) {
-+                      if (unicam->node[i].cur_frm)
-+                              unicam->node[i].cur_frm->vb.vb2_buf.timestamp =
-+                                                              ts;
-+              }
-       }
-       if (ista & UNICAM_FEI || sta & UNICAM_PI0) {
-               /*
-@@ -736,9 +806,13 @@ static irqreturn_t unicam_isr(int irq, v
-                * stop the peripheral. Overwrite the frame we've just
-                * captured instead.
-                */
--              if (unicam->node[0].cur_frm &&
--                  unicam->node[0].cur_frm != unicam->node[0].next_frm)
--                      unicam_process_buffer_complete(unicam);
-+              for (i = 0; i < num_nodes_streaming; i++) {
-+                      if (unicam->node[i].cur_frm &&
-+                          unicam->node[i].cur_frm != unicam->node[i].next_frm)
-+                              unicam_process_buffer_complete(&unicam->node[i],
-+                                                             sequence);
-+              }
-+              unicam->sequence++;
-       }
-       /* Cannot swap buffer at frame end, there may be a race condition
-@@ -746,11 +820,13 @@ static irqreturn_t unicam_isr(int irq, v
-        * already started.
-        */
-       if (ista & (UNICAM_FSI | UNICAM_LCI) && !(ista & UNICAM_FEI)) {
--              spin_lock(&unicam->node[0].dma_queue_lock);
--              if (!list_empty(&dma_q->active) &&
--                  unicam->node[0].cur_frm == unicam->node[0].next_frm)
--                      unicam_schedule_next_buffer(unicam);
--              spin_unlock(&unicam->node[0].dma_queue_lock);
-+              for (i = 0; i < num_nodes_streaming; i++) {
-+                      spin_lock(&unicam->node[i].dma_queue_lock);
-+                      if (!list_empty(&unicam->node[i].dma_queue.active) &&
-+                          unicam->node[i].cur_frm == unicam->node[i].next_frm)
-+                              unicam_schedule_next_buffer(&unicam->node[i]);
-+                      spin_unlock(&unicam->node[i].dma_queue_lock);
-+              }
-       }
-       if (reg_read(&unicam->cfg, UNICAM_ICTL) & UNICAM_FCM) {
-@@ -773,6 +849,15 @@ static int unicam_querycap(struct file *
-       snprintf(cap->bus_info, sizeof(cap->bus_info),
-                "platform:%s", dev->v4l2_dev.name);
-+      cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
-+                          V4L2_CAP_READWRITE | V4L2_CAP_DEVICE_CAPS |
-+                          V4L2_CAP_META_CAPTURE;
-+
-+      if (node->pad_id == IMAGE_PAD)
-+              cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
-+      else
-+              cap->device_caps = V4L2_CAP_META_CAPTURE | V4L2_CAP_STREAMING;
-+
-       return 0;
- }
-@@ -787,9 +872,14 @@ static int unicam_enum_fmt_vid_cap(struc
-       int ret = 0;
-       int i;
-+      if (node->pad_id == METADATA_PAD)
-+              return -EINVAL;
-+
-       for (i = 0; !ret && i < MAX_ENUM_MBUS_CODE; i++) {
-               memset(&mbus_code, 0, sizeof(mbus_code));
-               mbus_code.index = i;
-+              mbus_code.pad = IMAGE_PAD;
-+              mbus_code.which = V4L2_SUBDEV_FORMAT_ACTIVE;
-               ret = v4l2_subdev_call(dev->sensor, pad, enum_mbus_code,
-                                      NULL, &mbus_code);
-@@ -827,6 +917,9 @@ static int unicam_g_fmt_vid_cap(struct f
- {
-       struct unicam_node *node = video_drvdata(file);
-+      if (node->pad_id == METADATA_PAD)
-+              return -EINVAL;
-+
-       *f = node->v_fmt;
-       return 0;
-@@ -843,6 +936,9 @@ const struct unicam_fmt *get_first_suppo
-       for (j = 0; ret != -EINVAL && ret != -ENOIOCTLCMD; ++j) {
-               memset(&mbus_code, 0, sizeof(mbus_code));
-               mbus_code.index = j;
-+              mbus_code.pad = IMAGE_PAD;
-+              mbus_code.which = V4L2_SUBDEV_FORMAT_ACTIVE;
-+
-               ret = v4l2_subdev_call(dev->sensor, pad, enum_mbus_code, NULL,
-                                      &mbus_code);
-               if (ret < 0) {
-@@ -873,12 +969,15 @@ static int unicam_try_fmt_vid_cap(struct
-       struct unicam_device *dev = node->dev;
-       struct v4l2_subdev_format sd_fmt = {
-               .which = V4L2_SUBDEV_FORMAT_TRY,
--              .pad = 0
-+              .pad = IMAGE_PAD
-       };
-       struct v4l2_mbus_framefmt *mbus_fmt = &sd_fmt.format;
-       const struct unicam_fmt *fmt;
-       int ret;
-+      if (node->pad_id == METADATA_PAD)
-+              return -EINVAL;
-+
-       fmt = find_format_by_pix(dev, f->fmt.pix.pixelformat);
-       if (!fmt) {
-               /* Pixel format not supported by unicam. Choose the first
-@@ -983,7 +1082,7 @@ static int unicam_s_fmt_vid_cap(struct f
-       v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, fmt->code);
--      ret = __subdev_set_format(dev, &mbus_fmt);
-+      ret = __subdev_set_format(dev, &mbus_fmt, node->pad_id);
-       if (ret) {
-               unicam_dbg(3, dev, "%s __subdev_set_format failed %d\n",
-                          __func__, ret);
-@@ -1014,6 +1113,106 @@ static int unicam_s_fmt_vid_cap(struct f
-       return 0;
- }
-+static int unicam_enum_fmt_meta_cap(struct file *file, void *priv,
-+                                  struct v4l2_fmtdesc *f)
-+{
-+      struct unicam_node *node = video_drvdata(file);
-+      struct unicam_device *dev = node->dev;
-+      struct v4l2_subdev_mbus_code_enum mbus_code;
-+      const struct unicam_fmt *fmt = NULL;
-+      int ret = 0;
-+
-+      if (node->pad_id != METADATA_PAD || f->index != 0)
-+              return -EINVAL;
-+
-+      if (dev->sensor_embedded_data) {
-+              memset(&mbus_code, 0, sizeof(mbus_code));
-+              mbus_code.index = f->index;
-+              mbus_code.which = V4L2_SUBDEV_FORMAT_ACTIVE;
-+              mbus_code.pad = METADATA_PAD;
-+
-+              ret = v4l2_subdev_call(dev->sensor, pad, enum_mbus_code, NULL,
-+                                     &mbus_code);
-+              if (ret < 0) {
-+                      unicam_dbg(2, dev,
-+                                 "subdev->enum_mbus_code idx 0 returned %d - index invalid\n",
-+                                 ret);
-+                      return -EINVAL;
-+              }
-+      } else {
-+              mbus_code.code = MEDIA_BUS_FMT_SENSOR_DATA;
-+      }
-+
-+      fmt = find_format_by_code(mbus_code.code);
-+      if (fmt)
-+              f->pixelformat = fmt->fourcc;
-+
-+      return 0;
-+}
-+
-+static int unicam_g_fmt_meta_cap(struct file *file, void *priv,
-+                               struct v4l2_format *f)
-+{
-+      struct unicam_node *node = video_drvdata(file);
-+
-+      if (node->pad_id != METADATA_PAD)
-+              return -EINVAL;
-+
-+      *f = node->v_fmt;
-+
-+      return 0;
-+}
-+
-+static int unicam_try_fmt_meta_cap(struct file *file, void *priv,
-+                                 struct v4l2_format *f)
-+{
-+      struct unicam_node *node = video_drvdata(file);
-+
-+      if (node->pad_id != METADATA_PAD)
-+              return -EINVAL;
-+
-+      *f = node->v_fmt;
-+
-+      return 0;
-+}
-+
-+static int unicam_s_fmt_meta_cap(struct file *file, void *priv,
-+                               struct v4l2_format *f)
-+{
-+      struct unicam_node *node = video_drvdata(file);
-+      struct unicam_device *dev = node->dev;
-+      struct v4l2_mbus_framefmt mbus_fmt = { 0 };
-+      const struct unicam_fmt *fmt;
-+      int ret;
-+
-+      if (node->pad_id == IMAGE_PAD)
-+              return -EINVAL;
-+
-+      if (dev->sensor_embedded_data) {
-+              fmt = find_format_by_pix(dev, f->fmt.meta.dataformat);
-+              if (!fmt) {
-+                      unicam_err(dev, "unknown format: V4L2 pix 0x%08x\n",
-+                                 f->fmt.meta.dataformat);
-+                      return -EINVAL;
-+              }
-+              mbus_fmt.code = fmt->code;
-+              ret = __subdev_set_format(dev, &mbus_fmt, node->pad_id);
-+              if (ret) {
-+                      unicam_dbg(3, dev, "%s __subdev_set_format failed %d\n",
-+                                 __func__, ret);
-+                      return ret;
-+              }
-+      }
-+
-+      *f = node->v_fmt;
-+
-+      unicam_dbg(3, dev, "%s size %d, V4L2 pix 0x%08x\n",
-+                 __func__, node->v_fmt.fmt.meta.buffersize,
-+                 node->v_fmt.fmt.meta.dataformat);
-+
-+      return 0;
-+}
-+
- static int unicam_queue_setup(struct vb2_queue *vq,
-                             unsigned int *nbuffers,
-                             unsigned int *nplanes,
-@@ -1022,7 +1221,9 @@ static int unicam_queue_setup(struct vb2
- {
-       struct unicam_node *node = vb2_get_drv_priv(vq);
-       struct unicam_device *dev = node->dev;
--      unsigned int size = node->v_fmt.fmt.pix.sizeimage;
-+      unsigned int size = node->pad_id == IMAGE_PAD ?
-+                                  node->v_fmt.fmt.pix.sizeimage :
-+                                  node->v_fmt.fmt.meta.buffersize;
-       if (vq->num_buffers + *nbuffers < 3)
-               *nbuffers = 3 - vq->num_buffers;
-@@ -1053,7 +1254,8 @@ static int unicam_buffer_prepare(struct
-       if (WARN_ON(!node->fmt))
-               return -EINVAL;
--      size = node->v_fmt.fmt.pix.sizeimage;
-+      size = node->pad_id == IMAGE_PAD ? node->v_fmt.fmt.pix.sizeimage :
-+                                         node->v_fmt.fmt.meta.buffersize;
-       if (vb2_plane_size(vb, 0) < size) {
-               unicam_err(dev, "data will not fit into plane (%lu < %lu)\n",
-                          vb2_plane_size(vb, 0), size);
-@@ -1082,12 +1284,12 @@ static void unicam_set_packing_config(st
-       int pack, unpack;
-       u32 val;
--      if (dev->node[0].v_fmt.fmt.pix.pixelformat ==
--          dev->node[0].fmt->fourcc) {
-+      if (dev->node[IMAGE_PAD].v_fmt.fmt.pix.pixelformat ==
-+          dev->node[IMAGE_PAD].fmt->fourcc) {
-               unpack = UNICAM_PUM_NONE;
-               pack = UNICAM_PPM_NONE;
-       } else {
--              switch (dev->node[0].fmt->depth) {
-+              switch (dev->node[IMAGE_PAD].fmt->depth) {
-               case 8:
-                       unpack = UNICAM_PUM_UNPACK8;
-                       break;
-@@ -1125,17 +1327,31 @@ static void unicam_cfg_image_id(struct u
-       if (dev->bus_type == V4L2_MBUS_CSI2_DPHY) {
-               /* CSI2 mode */
-               reg_write(cfg, UNICAM_IDI0,
--                      (dev->virtual_channel << 6) | dev->node[0].fmt->csi_dt);
-+                        (dev->virtual_channel << 6) |
-+                                            dev->node[IMAGE_PAD].fmt->csi_dt);
-       } else {
-               /* CCP2 mode */
--              reg_write(cfg, UNICAM_IDI0, (0x80 | dev->node[0].fmt->csi_dt));
-+              reg_write(cfg, UNICAM_IDI0,
-+                        0x80 | dev->node[IMAGE_PAD].fmt->csi_dt);
-       }
- }
--static void unicam_start_rx(struct unicam_device *dev, unsigned long addr)
-+static void unicam_enable_ed(struct unicam_device *dev)
-+{
-+      struct unicam_cfg *cfg = &dev->cfg;
-+      u32 val = reg_read(cfg, UNICAM_DCS);
-+
-+      set_field(&val, 2, UNICAM_EDL_MASK);
-+      /* Do not wrap at the end of the embedded data buffer */
-+      set_field(&val, 0, UNICAM_DBOB);
-+
-+      reg_write(cfg, UNICAM_DCS, val);
-+}
-+
-+static void unicam_start_rx(struct unicam_device *dev, dma_addr_t *addr)
- {
-       struct unicam_cfg *cfg = &dev->cfg;
--      int line_int_freq = dev->node[0].v_fmt.fmt.pix.height >> 2;
-+      int line_int_freq = dev->node[IMAGE_PAD].v_fmt.fmt.pix.height >> 2;
-       unsigned int i;
-       u32 val;
-@@ -1284,27 +1500,31 @@ static void unicam_start_rx(struct unica
-       }
-       reg_write(&dev->cfg, UNICAM_IBLS,
--                dev->node[0].v_fmt.fmt.pix.bytesperline);
--      unicam_wr_dma_addr(dev, addr);
-+                dev->node[IMAGE_PAD].v_fmt.fmt.pix.bytesperline);
-+      unicam_wr_dma_addr(dev, addr[IMAGE_PAD], IMAGE_PAD);
-       unicam_set_packing_config(dev);
-       unicam_cfg_image_id(dev);
--      /* Disabled embedded data */
--      val = 0;
--      set_field(&val, 0, UNICAM_EDL_MASK);
--      reg_write(cfg, UNICAM_DCS, val);
--
-       val = reg_read(cfg, UNICAM_MISC);
-       set_field(&val, 1, UNICAM_FL0);
-       set_field(&val, 1, UNICAM_FL1);
-       reg_write(cfg, UNICAM_MISC, val);
-+      if (dev->node[METADATA_PAD].streaming && dev->sensor_embedded_data) {
-+              unicam_enable_ed(dev);
-+              unicam_wr_dma_addr(dev, addr[METADATA_PAD], METADATA_PAD);
-+      }
-+
-       /* Enable peripheral */
-       reg_write_field(cfg, UNICAM_CTRL, 1, UNICAM_CPE);
-       /* Load image pointers */
-       reg_write_field(cfg, UNICAM_ICTL, 1, UNICAM_LIP_MASK);
-+      /* Load embedded data buffer pointers if needed */
-+      if (dev->node[METADATA_PAD].streaming && dev->sensor_embedded_data)
-+              reg_write_field(cfg, UNICAM_DCS, 1, UNICAM_LDP);
-+
-       /*
-        * Enable trigger only for the first frame to
-        * sync correctly to the FS from the source.
-@@ -1339,6 +1559,9 @@ static void unicam_disable(struct unicam
-       /* Disable peripheral */
-       reg_write_field(cfg, UNICAM_CTRL, 0, UNICAM_CPE);
-+      /* Clear ED setup */
-+      reg_write(cfg, UNICAM_DCS, 0);
-+
-       /* Disable all lane clocks */
-       clk_write(cfg, 0);
- }
-@@ -1347,26 +1570,23 @@ static int unicam_start_streaming(struct
- {
-       struct unicam_node *node = vb2_get_drv_priv(vq);
-       struct unicam_device *dev = node->dev;
--      struct unicam_dmaqueue *dma_q = &node->dma_queue;
--      struct unicam_buffer *buf, *tmp;
--      unsigned long addr = 0;
-+      struct unicam_buffer *buf;
-+      dma_addr_t buffer_addr[MAX_NODES] = { 0 };
-+      int num_nodes_streaming;
-       unsigned long flags;
--      int ret;
-+      int ret, i;
--      spin_lock_irqsave(&node->dma_queue_lock, flags);
--      buf = list_entry(dma_q->active.next, struct unicam_buffer, list);
--      node->cur_frm = buf;
--      node->next_frm = buf;
--      list_del(&buf->list);
--      spin_unlock_irqrestore(&node->dma_queue_lock, flags);
-+      node->streaming = 1;
-+      if (!unicam_all_nodes_streaming(dev)) {
-+              unicam_dbg(3, dev, "Not all nodes are streaming yet.");
-+              return 0;
-+      }
--      addr = vb2_dma_contig_plane_dma_addr(&node->cur_frm->vb.vb2_buf, 0);
-       dev->sequence = 0;
--
-       ret = unicam_runtime_get(dev);
-       if (ret < 0) {
-               unicam_dbg(3, dev, "unicam_runtime_get failed\n");
--              goto err_release_buffers;
-+              return ret;
-       }
-       dev->active_data_lanes = dev->max_data_lanes;
-@@ -1388,7 +1608,7 @@ static int unicam_start_streaming(struct
-                       dev->active_data_lanes = dev->max_data_lanes;
-       }
-       if (dev->active_data_lanes > dev->max_data_lanes) {
--              unicam_err(dev, "Device has requested %u data lanes, which is >%u configured in DT\n",
-+              unicam_err(dev, "Device has requested %u data lanes, which is >%u configured in DT\n",
-                          dev->active_data_lanes, dev->max_data_lanes);
-               ret = -EINVAL;
-               goto err_pm_put;
-@@ -1408,9 +1628,22 @@ static int unicam_start_streaming(struct
-               unicam_err(dev, "Failed to enable CSI clock: %d\n", ret);
-               goto err_pm_put;
-       }
--      dev->streaming = 1;
--      unicam_start_rx(dev, addr);
-+      num_nodes_streaming = unicam_num_nodes_streaming(dev);
-+      for (i = 0; i < num_nodes_streaming; i++) {
-+              spin_lock_irqsave(&dev->node[i].dma_queue_lock, flags);
-+              buf = list_entry(dev->node[i].dma_queue.active.next,
-+                               struct unicam_buffer, list);
-+              dev->node[i].cur_frm = buf;
-+              dev->node[i].next_frm = buf;
-+              list_del(&buf->list);
-+              spin_unlock_irqrestore(&dev->node[i].dma_queue_lock, flags);
-+              buffer_addr[i] =
-+              vb2_dma_contig_plane_dma_addr(&dev->node[i].cur_frm->vb.vb2_buf,
-+                                            0);
-+      }
-+
-+      unicam_start_rx(dev, buffer_addr);
-       ret = v4l2_subdev_call(dev->sensor, video, s_stream, 1);
-       if (ret < 0) {
-@@ -1421,21 +1654,11 @@ static int unicam_start_streaming(struct
-       return 0;
- err_disable_unicam:
-+      node->streaming = 0;
-       unicam_disable(dev);
-       clk_disable_unprepare(dev->clock);
- err_pm_put:
-       unicam_runtime_put(dev);
--err_release_buffers:
--      list_for_each_entry_safe(buf, tmp, &dma_q->active, list) {
--              list_del(&buf->list);
--              vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED);
--      }
--      if (node->cur_frm != node->next_frm)
--              vb2_buffer_done(&node->next_frm->vb.vb2_buf,
--                              VB2_BUF_STATE_QUEUED);
--      vb2_buffer_done(&node->cur_frm->vb.vb2_buf, VB2_BUF_STATE_QUEUED);
--      node->next_frm = NULL;
--      node->cur_frm = NULL;
-       return ret;
- }
-@@ -1448,33 +1671,47 @@ static void unicam_stop_streaming(struct
-       struct unicam_buffer *buf, *tmp;
-       unsigned long flags;
--      if (v4l2_subdev_call(dev->sensor, video, s_stream, 0) < 0)
--              unicam_err(dev, "stream off failed in subdev\n");
-+      node->streaming = 0;
--      unicam_disable(dev);
-+      if (node->pad_id == IMAGE_PAD) {
-+              /* Stop streaming the sensor and disable the peripheral.
-+               * We cannot continue streaming embedded data with the
-+               * image pad disabled.
-+               */
-+              if (v4l2_subdev_call(dev->sensor, video, s_stream, 0) < 0)
-+                      unicam_err(dev, "stream off failed in subdev\n");
--      /* Release all active buffers */
-+              unicam_disable(dev);
-+              clk_disable_unprepare(dev->clock);
-+              unicam_runtime_put(dev);
-+
-+      } else if (node->pad_id == METADATA_PAD) {
-+              /* Null out the embedded data buffer address so the HW does
-+               * not use it.  This is only really needed if the embedded data
-+               * pad is disabled before the image pad.  The 0x3 in the top two
-+               * bits signifies uncached accesses through the Videocore
-+               * memory controller.
-+               */
-+              unicam_wr_dma_addr(dev, 0xc0000000, METADATA_PAD);
-+      }
-+
-+      /* Clear all queued buffers for the node */
-       spin_lock_irqsave(&node->dma_queue_lock, flags);
-       list_for_each_entry_safe(buf, tmp, &dma_q->active, list) {
-               list_del(&buf->list);
-               vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
-       }
--      if (node->cur_frm == node->next_frm) {
--              vb2_buffer_done(&node->cur_frm->vb.vb2_buf,
--                              VB2_BUF_STATE_ERROR);
--      } else {
-+      if (node->cur_frm)
-               vb2_buffer_done(&node->cur_frm->vb.vb2_buf,
-                               VB2_BUF_STATE_ERROR);
-+      if (node->next_frm && node->cur_frm != node->next_frm)
-               vb2_buffer_done(&node->next_frm->vb.vb2_buf,
-                               VB2_BUF_STATE_ERROR);
--      }
-+
-       node->cur_frm = NULL;
-       node->next_frm = NULL;
-       spin_unlock_irqrestore(&node->dma_queue_lock, flags);
--
--      clk_disable_unprepare(dev->clock);
--      unicam_runtime_put(dev);
- }
- static int unicam_enum_input(struct file *file, void *priv,
-@@ -1595,17 +1832,23 @@ static int unicam_enum_framesizes(struct
-       struct v4l2_subdev_frame_size_enum fse;
-       int ret;
--      /* check for valid format */
--      fmt = find_format_by_pix(dev, fsize->pixel_format);
--      if (!fmt) {
--              unicam_dbg(3, dev, "Invalid pixel code: %x\n",
--                         fsize->pixel_format);
--              return -EINVAL;
-+      if (node->pad_id == IMAGE_PAD) {
-+              /* check for valid format */
-+              fmt = find_format_by_pix(dev, fsize->pixel_format);
-+              if (!fmt) {
-+                      unicam_dbg(3, dev, "Invalid pixel code: %x\n",
-+                                 fsize->pixel_format);
-+                      return -EINVAL;
-+              }
-+              fse.code = fmt->code;
-+      } else {
-+              /* This pad is for embedded data, so just set the format */
-+              fse.code = MEDIA_BUS_FMT_SENSOR_DATA;
-       }
-+      fse.which = V4L2_SUBDEV_FORMAT_ACTIVE;
-       fse.index = fsize->index;
--      fse.pad = 0;
--      fse.code = fmt->code;
-+      fse.pad = node->pad_id;
-       ret = v4l2_subdev_call(dev->sensor, pad, enum_frame_size, NULL, &fse);
-       if (ret)
-@@ -1782,7 +2025,7 @@ static void unicam_notify(struct v4l2_su
-       switch (notification) {
-       case V4L2_DEVICE_NOTIFY_EVENT:
--              v4l2_event_queue(&dev->node[0].video_dev, arg);
-+              v4l2_event_queue(&dev->node[IMAGE_PAD].video_dev, arg);
-               break;
-       default:
-               break;
-@@ -1826,6 +2069,7 @@ static int unicam_open(struct file *file
-               goto unlock;
-       }
-+      node->open++;
-       ret = 0;
- unlock:
-@@ -1850,6 +2094,10 @@ static int unicam_release(struct file *f
-       if (fh_singular)
-               v4l2_subdev_call(sd, core, s_power, 0);
-+      if (node->streaming)
-+              unicam_stop_streaming(&node->buffer_queue);
-+
-+      node->open--;
-       mutex_unlock(&node->lock);
-       return ret;
-@@ -1874,6 +2122,11 @@ static const struct v4l2_ioctl_ops unica
-       .vidioc_s_fmt_vid_cap           = unicam_s_fmt_vid_cap,
-       .vidioc_try_fmt_vid_cap         = unicam_try_fmt_vid_cap,
-+      .vidioc_enum_fmt_meta_cap       = unicam_enum_fmt_meta_cap,
-+      .vidioc_g_fmt_meta_cap          = unicam_g_fmt_meta_cap,
-+      .vidioc_s_fmt_meta_cap          = unicam_s_fmt_meta_cap,
-+      .vidioc_try_fmt_meta_cap        = unicam_try_fmt_meta_cap,
-+
-       .vidioc_enum_input              = unicam_enum_input,
-       .vidioc_g_input                 = unicam_g_input,
-       .vidioc_s_input                 = unicam_s_input,
-@@ -1941,42 +2194,53 @@ static int register_node(struct unicam_d
-       const struct unicam_fmt *fmt;
-       int ret;
--      ret = __subdev_get_format(unicam, &mbus_fmt, pad_id);
--      if (ret) {
--              unicam_err(unicam, "Failed to get_format - ret %d\n", ret);
--              return ret;
--      }
--
--      fmt = find_format_by_code(mbus_fmt.code);
--      if (!fmt) {
--              /* Find the first format that the sensor and unicam both
--               * support
--               */
--              fmt = get_first_supported_format(unicam);
-+      if (unicam->sensor_embedded_data || pad_id != METADATA_PAD) {
-+              ret = __subdev_get_format(unicam, &mbus_fmt, pad_id);
-+              if (ret) {
-+                      unicam_err(unicam, "Failed to get_format - ret %d\n",
-+                                 ret);
-+                      return ret;
-+              }
--              if (!fmt)
--                      /* No compatible formats */
--                      return -EINVAL;
-+              fmt = find_format_by_code(mbus_fmt.code);
-+              if (!fmt) {
-+                      /* Find the first format that the sensor and unicam both
-+                       * support
-+                       */
-+                      fmt = get_first_supported_format(unicam);
--              mbus_fmt.code = fmt->code;
--              ret = __subdev_set_format(unicam, &mbus_fmt);
--              if (ret)
--                      return -EINVAL;
--      }
--      if (mbus_fmt.field != V4L2_FIELD_NONE) {
--              /* Interlaced not supported - disable it now. */
--              mbus_fmt.field = V4L2_FIELD_NONE;
--              ret = __subdev_set_format(unicam, &mbus_fmt);
--              if (ret)
--                      return -EINVAL;
-+                      if (!fmt)
-+                              /* No compatible formats */
-+                              return -EINVAL;
-+
-+                      mbus_fmt.code = fmt->code;
-+                      ret = __subdev_set_format(unicam, &mbus_fmt, pad_id);
-+                      if (ret)
-+                              return -EINVAL;
-+              }
-+              if (mbus_fmt.field != V4L2_FIELD_NONE) {
-+                      /* Interlaced not supported - disable it now. */
-+                      mbus_fmt.field = V4L2_FIELD_NONE;
-+                      ret = __subdev_set_format(unicam, &mbus_fmt, pad_id);
-+                      if (ret)
-+                              return -EINVAL;
-+              }
-+      } else {
-+              /* Fix this node format as embedded data. */
-+              fmt = find_format_by_code(MEDIA_BUS_FMT_SENSOR_DATA);
-       }
-+      node->dev = unicam;
-       node->pad_id = pad_id;
-       node->fmt = fmt;
--      if (fmt->fourcc)
--              node->v_fmt.fmt.pix.pixelformat = fmt->fourcc;
--      else
-+      if (fmt->fourcc) {
-+              if (fmt->fourcc != V4L2_META_FMT_SENSOR_DATA)
-+                      node->v_fmt.fmt.pix.pixelformat = fmt->fourcc;
-+              else
-+                      node->v_fmt.fmt.meta.dataformat = fmt->fourcc;
-+      } else {
-               node->v_fmt.fmt.pix.pixelformat = fmt->repacked_fourcc;
-+      }
-       /* Read current subdev format */
-       unicam_reset_format(node);
-@@ -2002,13 +2266,21 @@ static int register_node(struct unicam_d
-       spin_lock_init(&node->dma_queue_lock);
-       mutex_init(&node->lock);
--      if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-+      vdev = &node->video_dev;
-+      if (pad_id == IMAGE_PAD) {
-               /* Add controls from the subdevice */
-               ret = v4l2_ctrl_add_handler(&node->ctrl_handler,
-                                           unicam->sensor->ctrl_handler, NULL,
-                                           true);
-               if (ret < 0)
-                       return ret;
-+
-+              /*
-+               * If the sensor subdevice has any controls, associate the node
-+               *  with the ctrl handler to allow access from userland.
-+               */
-+              if (!list_empty(&node->ctrl_handler.ctrls))
-+                      vdev->ctrl_handler = &node->ctrl_handler;
-       }
-       q = &node->buffer_queue;
-@@ -2031,8 +2303,6 @@ static int register_node(struct unicam_d
-       INIT_LIST_HEAD(&node->dma_queue.active);
--      vdev = &node->video_dev;
--      strlcpy(vdev->name, UNICAM_MODULE_NAME, sizeof(vdev->name));
-       vdev->release = video_device_release_empty;
-       vdev->fops = &unicam_fops;
-       vdev->ioctl_ops = &unicam_ioctl_ops;
-@@ -2040,24 +2310,28 @@ static int register_node(struct unicam_d
-       vdev->vfl_dir = VFL_DIR_RX;
-       vdev->queue = q;
-       vdev->lock = &node->lock;
--      vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
--                          V4L2_CAP_READWRITE;
--      /* If the source has no controls then remove our ctrl handler. */
--      if (list_empty(&node->ctrl_handler.ctrls))
--              unicam->v4l2_dev.ctrl_handler = NULL;
-+      vdev->device_caps = (pad_id == IMAGE_PAD) ?
-+                          (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING) :
-+                          (V4L2_CAP_META_CAPTURE | V4L2_CAP_STREAMING);
-+
-+      /* Define the device names */
-+      snprintf(vdev->name, sizeof(vdev->name), "%s-%s", UNICAM_MODULE_NAME,
-+               node->pad_id == IMAGE_PAD ? "image" : "embedded");
--      node->dev = unicam;
-       video_set_drvdata(vdev, node);
-       vdev->entity.flags |= MEDIA_ENT_FL_DEFAULT;
--      if (!v4l2_subdev_has_op(unicam->sensor, video, s_std)) {
-+      if (node->pad_id == METADATA_PAD ||
-+          !v4l2_subdev_has_op(unicam->sensor, video, s_std)) {
-               v4l2_disable_ioctl(&node->video_dev, VIDIOC_S_STD);
-               v4l2_disable_ioctl(&node->video_dev, VIDIOC_G_STD);
-               v4l2_disable_ioctl(&node->video_dev, VIDIOC_ENUMSTD);
-       }
--      if (!v4l2_subdev_has_op(unicam->sensor, video, querystd))
-+      if (node->pad_id == METADATA_PAD ||
-+          !v4l2_subdev_has_op(unicam->sensor, video, querystd))
-               v4l2_disable_ioctl(&node->video_dev, VIDIOC_QUERYSTD);
--      if (!v4l2_subdev_has_op(unicam->sensor, video, s_dv_timings)) {
-+      if (node->pad_id == METADATA_PAD ||
-+          !v4l2_subdev_has_op(unicam->sensor, video, s_dv_timings)) {
-               v4l2_disable_ioctl(&node->video_dev, VIDIOC_S_EDID);
-               v4l2_disable_ioctl(&node->video_dev, VIDIOC_G_EDID);
-               v4l2_disable_ioctl(&node->video_dev, VIDIOC_DV_TIMINGS_CAP);
-@@ -2066,15 +2340,19 @@ static int register_node(struct unicam_d
-               v4l2_disable_ioctl(&node->video_dev, VIDIOC_ENUM_DV_TIMINGS);
-               v4l2_disable_ioctl(&node->video_dev, VIDIOC_QUERY_DV_TIMINGS);
-       }
--      if (!v4l2_subdev_has_op(unicam->sensor, pad, enum_frame_interval))
-+      if (node->pad_id == METADATA_PAD ||
-+          !v4l2_subdev_has_op(unicam->sensor, pad, enum_frame_interval))
-               v4l2_disable_ioctl(&node->video_dev,
-                                  VIDIOC_ENUM_FRAMEINTERVALS);
--      if (!v4l2_subdev_has_op(unicam->sensor, video, g_frame_interval))
-+      if (node->pad_id == METADATA_PAD ||
-+          !v4l2_subdev_has_op(unicam->sensor, video, g_frame_interval))
-               v4l2_disable_ioctl(&node->video_dev, VIDIOC_G_PARM);
--      if (!v4l2_subdev_has_op(unicam->sensor, video, s_frame_interval))
-+      if (node->pad_id == METADATA_PAD ||
-+          !v4l2_subdev_has_op(unicam->sensor, video, s_frame_interval))
-               v4l2_disable_ioctl(&node->video_dev, VIDIOC_S_PARM);
--      if (!v4l2_subdev_has_op(unicam->sensor, pad, enum_frame_size))
-+      if (node->pad_id == METADATA_PAD ||
-+          !v4l2_subdev_has_op(unicam->sensor, pad, enum_frame_size))
-               v4l2_disable_ioctl(&node->video_dev, VIDIOC_ENUM_FRAMESIZES);
-       ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
-@@ -2082,27 +2360,29 @@ static int register_node(struct unicam_d
-               unicam_err(unicam, "Unable to register video device.\n");
-               return ret;
-       }
--      node->registered = true;
-+      node->registered = 1;
--      ret = media_create_pad_link(&unicam->sensor->entity,
--                                  0, &node->video_dev.entity, 0,
--                                  MEDIA_LNK_FL_ENABLED |
--                                  MEDIA_LNK_FL_IMMUTABLE);
--      if (ret)
--              unicam_err(unicam, "Unable to create pad links.\n");
-+      if (unicam->sensor_embedded_data) {
-+              ret = media_create_pad_link(&unicam->sensor->entity, pad_id,
-+                                          &node->video_dev.entity, 0,
-+                                          MEDIA_LNK_FL_ENABLED |
-+                                          MEDIA_LNK_FL_IMMUTABLE);
-+              if (ret)
-+                      unicam_err(unicam, "Unable to create pad links.\n");
-+      }
-       return ret;
- }
- static void unregister_nodes(struct unicam_device *unicam)
- {
--      if (unicam->node[0].registered) {
--              video_unregister_device(&unicam->node[0].video_dev);
--              unicam->node[0].registered = false;
--      }
--      if (unicam->node[1].registered) {
--              video_unregister_device(&unicam->node[1].video_dev);
--              unicam->node[1].registered = false;
-+      if (unicam->node[IMAGE_PAD].registered) {
-+              video_unregister_device(&unicam->node[IMAGE_PAD].video_dev);
-+              unicam->node[IMAGE_PAD].registered = 0;
-+      }
-+      if (unicam->node[METADATA_PAD].registered) {
-+              video_unregister_device(&unicam->node[METADATA_PAD].video_dev);
-+              unicam->node[METADATA_PAD].registered = 0;
-       }
- }
-@@ -2118,20 +2398,20 @@ static int unicam_probe_complete(struct
-       if (!unicam->sensor_config)
-               return -ENOMEM;
--      ret = register_node(unicam, &unicam->node[0],
--                          V4L2_BUF_TYPE_VIDEO_CAPTURE, 0);
-+      unicam->sensor_embedded_data = (unicam->sensor->entity.num_pads >= 2);
-+
-+      ret = register_node(unicam, &unicam->node[IMAGE_PAD],
-+                          V4L2_BUF_TYPE_VIDEO_CAPTURE, IMAGE_PAD);
-       if (ret) {
-               unicam_err(unicam, "Unable to register subdev node 0.\n");
-               goto unregister;
-       }
--      if (unicam->sensor->entity.num_pads >= 2) {
--              ret = register_node(unicam, &unicam->node[1],
--                                  V4L2_BUF_TYPE_META_CAPTURE, 1);
--              if (ret) {
--                      unicam_err(unicam,
--                                 "Unable to register subdev node 1.\n");
--                      goto unregister;
--              }
-+
-+      ret = register_node(unicam, &unicam->node[METADATA_PAD],
-+                          V4L2_BUF_TYPE_META_CAPTURE, METADATA_PAD);
-+      if (ret) {
-+              unicam_err(unicam, "Unable to register subdev node 1.\n");
-+              goto unregister;
-       }
-       ret = v4l2_device_register_ro_subdev_nodes(&unicam->v4l2_dev);
-@@ -2355,8 +2635,10 @@ static int unicam_probe(struct platform_
-                pdev->dev.driver->name, dev_name(&pdev->dev));
-       unicam->mdev.hw_revision = 1;
--      media_entity_pads_init(&unicam->node[0].video_dev.entity, 1,
--                             &unicam->node[0].pad);
-+      media_entity_pads_init(&unicam->node[IMAGE_PAD].video_dev.entity, 1,
-+                             &unicam->node[IMAGE_PAD].pad);
-+      media_entity_pads_init(&unicam->node[METADATA_PAD].video_dev.entity, 1,
-+                             &unicam->node[METADATA_PAD].pad);
-       media_device_init(&unicam->mdev);
-       unicam->v4l2_dev.mdev = &unicam->mdev;
-@@ -2376,11 +2658,10 @@ static int unicam_probe(struct platform_
-       }
-       /* Reserve space for the controls */
--      hdl = &unicam->node[0].ctrl_handler;
-+      hdl = &unicam->node[IMAGE_PAD].ctrl_handler;
-       ret = v4l2_ctrl_handler_init(hdl, 16);
-       if (ret < 0)
-               goto media_unregister;
--      unicam->v4l2_dev.ctrl_handler = hdl;
-       /* set the driver data in platform device */
-       platform_set_drvdata(pdev, unicam);
-@@ -2417,7 +2698,7 @@ static int unicam_remove(struct platform
-       pm_runtime_disable(&pdev->dev);
-       v4l2_async_notifier_unregister(&unicam->notifier);
--      v4l2_ctrl_handler_free(&unicam->node[0].ctrl_handler);
-+      v4l2_ctrl_handler_free(&unicam->node[IMAGE_PAD].ctrl_handler);
-       v4l2_device_unregister(&unicam->v4l2_dev);
-       unregister_nodes(unicam);
-       if (unicam->sensor_config)