index 2cd0f87da8e29785ad38a87b05b219893024e720..bd141b3b9dde990a1e77f5cfb65d40ea75dd22c1 100644 (file)
.code = V4L2_MBUS_FMT_UYVY8_2X8,
.colorspace = V4L2_COLORSPACE_SMPTE170M,
.coplanar = 0,
- .vpdma_fmt = { &vpdma_yuv_fmts[VPDMA_DATA_FMT_CY422],
+ /* bus order is reversed so flip Y and UV bytes */
+ .vpdma_fmt = { &vpdma_yuv_fmts[VPDMA_DATA_FMT_CBY422],
},
},
{
.code = V4L2_MBUS_FMT_YUYV8_2X8,
.colorspace = V4L2_COLORSPACE_SMPTE170M,
.coplanar = 0,
- .vpdma_fmt = { &vpdma_yuv_fmts[VPDMA_DATA_FMT_YC422],
+ /* bus order is reversed so flip Y and UV bytes */
+ .vpdma_fmt = { &vpdma_yuv_fmts[VPDMA_DATA_FMT_YCB422],
},
},
{
.code = V4L2_MBUS_FMT_VYUY8_2X8,
.colorspace = V4L2_COLORSPACE_SMPTE170M,
.coplanar = 0,
- .vpdma_fmt = { &vpdma_yuv_fmts[VPDMA_DATA_FMT_YC422],
+ /* bus order is reversed so flip Y and UV bytes */
+ .vpdma_fmt = { &vpdma_yuv_fmts[VPDMA_DATA_FMT_CBY422],
+ },
+ },
+ {
+ .name = "YVYU 422 packed",
+ .fourcc = V4L2_PIX_FMT_YVYU,
+ .code = V4L2_MBUS_FMT_YVYU8_2X8,
+ .colorspace = V4L2_COLORSPACE_SMPTE170M,
+ .coplanar = 0,
+ /* bus order is reversed so flip Y and UV bytes */
+ .vpdma_fmt = { &vpdma_yuv_fmts[VPDMA_DATA_FMT_CBY422],
},
},
{
@@ -304,6 +317,7 @@ static inline struct vip_dev *notifier_to_vip_dev(struct v4l2_async_notifier *n)
static int alloc_port(struct vip_dev *, int);
static void free_port(struct vip_port *);
static int vip_setup_parser(struct vip_port *port);
+static void stop_dma(struct vip_stream *stream);
static inline u32 read_sreg(struct vip_shared *shared, int offset)
{
{
u32 val, ret, offset;
- if (polarity == 0 && port->dev->syscon) {
+ if (polarity == 1 && port->dev->syscon) {
/*
* When the VIP parser is configured to so that the pixel clock
* This will make sure that an abort descriptor for this channel
* would be submitted to VPDMA causing any ongoing transaction to be
* aborted and cleanup the VPDMA FSM for this channel */
- dev->vpdma_channels[channel] = 1;
+ stream->vpdma_channels[channel] = 1;
- vpdma_rawchan_add_out_dtd(&dev->desc_list, c_rect->width, c_rect,
+ vpdma_rawchan_add_out_dtd(&stream->desc_list, c_rect->width, c_rect,
fmt->vpdma_fmt[plane], dma_addr, max_width, max_height,
channel, flags);
add_out_dtd(stream, VIP_SRCE_CHROMA);
}
-static void enable_irqs(struct vip_dev *dev, int irq_num)
+static void enable_irqs(struct vip_dev *dev, int irq_num, int list_num)
{
u32 reg_addr = VIP_INT0_ENABLE0_SET +
VIP_INTC_INTX_OFFSET * irq_num;
- int list_num = dev->slice_id;
write_sreg(dev->shared, reg_addr, 1 << (list_num * 2));
irq_num, list_num, true);
}
-static void disable_irqs(struct vip_dev *dev, int irq_num)
+static void disable_irqs(struct vip_dev *dev, int irq_num, int list_num)
{
u32 reg_addr = VIP_INT0_ENABLE0_CLR +
VIP_INTC_INTX_OFFSET * irq_num;
- int list_num = dev->slice_id;
- write_sreg(dev->shared, reg_addr, 0xffffffff);
+ write_sreg(dev->shared, reg_addr, 1 << (list_num * 2));
vpdma_enable_list_complete_irq(dev->shared->vpdma,
irq_num, list_num, false);
}
-static void clear_irqs(struct vip_dev *dev, int irq_num)
+static void clear_irqs(struct vip_dev *dev, int irq_num, int list_num)
{
u32 reg_addr = VIP_INT0_STATUS0_CLR +
VIP_INTC_INTX_OFFSET * irq_num;
- write_sreg(dev->shared, reg_addr, 0xffffffff);
+ write_sreg(dev->shared, reg_addr, 1 << (list_num * 2));
vpdma_clear_list_stat(dev->shared->vpdma, irq_num, dev->slice_id);
}
struct vip_dev *dev = port->dev;
unsigned int list_length;
- dev->desc_next = dev->desc_list.buf.addr;
+ stream->desc_next = stream->desc_list.buf.addr;
add_stream_dtds(stream);
- list_length = dev->desc_next - dev->desc_list.buf.addr;
- vpdma_map_desc_buf(dev->shared->vpdma, &dev->desc_list.buf);
+ list_length = stream->desc_next - stream->desc_list.buf.addr;
+ vpdma_map_desc_buf(dev->shared->vpdma, &stream->desc_list.buf);
}
/*
* Should be called after a new vb is queued and on a vpdma list
* completion interrupt.
*/
-static void start_dma(struct vip_dev *dev, struct vip_buffer *buf)
+static void start_dma(struct vip_stream *stream, struct vip_buffer *buf)
{
+ struct vip_dev *dev = stream->port->dev;
struct vpdma_data *vpdma = dev->shared->vpdma;
+ int list_num = stream->list_num;
dma_addr_t dma_addr;
int drop_data;
- if (vpdma_list_busy(vpdma, dev->slice_id)) {
+ if (vpdma_list_busy(vpdma, list_num)) {
vip_err(dev, "vpdma list busy, cannot post");
return; /* nothing to do */
}
vip_dbg(4, dev, "start_dma: dropped\n");
}
- vpdma_update_dma_addr(dev->shared->vpdma, &dev->desc_list,
- dma_addr, dev->write_desc, drop_data);
- vpdma_submit_descs(dev->shared->vpdma, &dev->desc_list, dev->slice_id);
+ vpdma_update_dma_addr(dev->shared->vpdma, &stream->desc_list,
+ dma_addr, stream->write_desc, drop_data, 0);
+
+ if (stream->port->fmt->coplanar) {
+ dma_addr += stream->width * stream->height;
+ vpdma_update_dma_addr(dev->shared->vpdma, &stream->desc_list,
+ dma_addr, stream->write_desc + 1, drop_data, 1);
+ }
+
+ vpdma_submit_descs(dev->shared->vpdma,
+ &stream->desc_list, stream->list_num);
}
static void vip_schedule_next_buffer(struct vip_stream *stream)
struct vip_buffer, list);
buf->drop = true;
- list_move_tail(&buf->list, &dev->vip_bufs);
+ list_move_tail(&buf->list, &stream->post_bufs);
buf = NULL;
} else if (vb2_is_streaming(&stream->vb_vidq)) {
buf = list_entry(stream->vidq.next,
struct vip_buffer, list);
buf->drop = false;
- list_move_tail(&buf->list, &dev->vip_bufs);
+ list_move_tail(&buf->list, &stream->post_bufs);
vip_dbg(4, dev, "added next buffer\n");
} else {
vip_err(dev, "IRQ occurred when not streaming\n");
buf = list_entry(stream->dropq.next,
struct vip_buffer, list);
buf->drop = true;
- list_move_tail(&buf->list, &dev->vip_bufs);
+ list_move_tail(&buf->list, &stream->post_bufs);
buf = NULL;
}
spin_unlock_irqrestore(&dev->slock, flags);
- start_dma(dev, buf);
+ start_dma(stream, buf);
}
static void vip_process_buffer_complete(struct vip_stream *stream)
struct vb2_buffer *vb = NULL;
unsigned long flags, fld;
- buf = list_first_entry(&dev->vip_bufs, struct vip_buffer, list);
+ buf = list_first_entry(&stream->post_bufs, struct vip_buffer, list);
if (stream->port->flags & FLAG_INTERLACED) {
- vpdma_unmap_desc_buf(dev->shared->vpdma, &dev->desc_list.buf);
+ vpdma_unmap_desc_buf(dev->shared->vpdma,
+ &stream->desc_list.buf);
- fld = dtd_get_field(dev->write_desc);
+ fld = dtd_get_field(stream->write_desc);
stream->field = fld ? V4L2_FIELD_BOTTOM : V4L2_FIELD_TOP;
- vpdma_map_desc_buf(dev->shared->vpdma, &dev->desc_list.buf);
+ vpdma_map_desc_buf(dev->shared->vpdma, &stream->desc_list.buf);
}
if (buf) {
static irqreturn_t vip_irq(int irq_vip, void *data)
{
struct vip_dev *dev = (struct vip_dev *)data;
+ struct vpdma_data *vpdma = dev->shared->vpdma;
struct vip_stream *stream;
- int list_num = dev->slice_id;
+ int list_num;
int irq_num = dev->slice_id;
u32 irqst, reg_addr;
vip_dbg(8, dev, "IRQ %d VIP_INT%d_STATUS0 0x%x\n",
irq_vip, irq_num, irqst);
if (irqst) {
- vpdma_clear_list_stat(dev->shared->vpdma, irq_num, list_num);
-
reg_addr = VIP_INT0_STATUS0_CLR +
VIP_INTC_INTX_OFFSET * irq_num;
write_sreg(dev->shared, reg_addr, irqst);
- }
- stream = dev->ports[0]->cap_streams[0];
- if (dev->num_skip_irq)
- dev->num_skip_irq--;
- else
- vip_process_buffer_complete(stream);
+ for (list_num = 0; list_num < 8; list_num++) {
+ /* Check for LIST_COMPLETE IRQ */
+ if (!(irqst & (1 << list_num * 2)))
+ continue;
- vip_schedule_next_buffer(stream);
+ vip_dbg(8, dev, "IRQ %d: handling LIST%d_COMPLETE\n",
+ irq_num, list_num);
+
+ stream = vpdma_hwlist_get_priv(vpdma, list_num);
+ if (!stream || stream->list_num != list_num) {
+ vip_err(dev, "IRQ occured for unused list");
+ continue;
+ }
+
+ vpdma_clear_list_stat(vpdma, irq_num, list_num);
+
+ if (dev->num_skip_irq)
+ dev->num_skip_irq--;
+ else
+ vip_process_buffer_complete(stream);
+
+ vip_schedule_next_buffer(stream);
+ irqst &= ~((1 << list_num * 2));
+ }
+ }
return IRQ_HANDLED;
}
fourcc_to_str(f->fmt.pix.pixelformat),
f->fmt.pix.width, f->fmt.pix.height,
f->fmt.pix.bytesperline, f->fmt.pix.sizeimage);
+ vip_dbg(3, dev, "g_fmt vpdma data type: 0x%02X\n",
+ port->fmt->vpdma_fmt[0]->data_type);
return 0;
}
static void set_fmt_params(struct vip_stream *stream)
{
struct vip_dev *dev = stream->port->dev;
+ int data_path_reg;
stream->sequence = 0;
stream->field = V4L2_FIELD_TOP;
stream->port->fmt->vpdma_fmt[0],
0xff);
}
+
+ data_path_reg = VIP_VIP1_DATA_PATH_SELECT + 4 * dev->slice_id;
+ if (stream->port->fmt->coplanar) {
+ stream->port->flags &= ~FLAG_MULT_PORT;
+ write_vreg(dev, data_path_reg, 0x600);
+ } else {
+ stream->port->flags |= FLAG_MULT_PORT;
+ write_vreg(dev, data_path_reg, 0x8000);
+ }
}
int vip_s_fmt_vid_cap(struct file *file, void *priv,
vip_dbg(3, dev, "s_fmt subdev s_fmt mbus_code: %04X size: %dx%d\n",
mf->code,
mf->width, mf->height);
+ vip_dbg(3, dev, "s_fmt vpdma data type: 0x%02X\n",
+ port->fmt->vpdma_fmt[0]->data_type);
return 0;
}
dev->num_skip_irq = VIP_VPDMA_FIFO_SIZE;
spin_lock_irqsave(&dev->slock, flags);
- if (vpdma_list_busy(dev->shared->vpdma, dev->slice_id)) {
+ if (vpdma_list_busy(dev->shared->vpdma, stream->list_num)) {
spin_unlock_irqrestore(&dev->slock, flags);
- vpdma_unmap_desc_buf(dev->shared->vpdma, &dev->desc_list.buf);
- vpdma_reset_desc_list(&dev->desc_list);
+ vpdma_unmap_desc_buf(dev->shared->vpdma,
+ &stream->desc_list.buf);
+ vpdma_reset_desc_list(&stream->desc_list);
return -EBUSY;
}
- list_move_tail(&buf->list, &dev->vip_bufs);
+ list_move_tail(&buf->list, &stream->post_bufs);
spin_unlock_irqrestore(&dev->slock, flags);
vip_dbg(2, dev, "start_streaming: start_dma buf 0x%x\n",
(unsigned int)buf);
- start_dma(dev, buf);
+ start_dma(stream, buf);
/* We enable the irq after posting the vpdma descriptor
* to prevent sprurious interrupt coming in before the
* vb2 layer is completely ready to handle them
* otherwise the vb2_streaming test would fail early on
*/
- enable_irqs(dev, dev->slice_id);
+ enable_irqs(dev, dev->slice_id, stream->list_num);
+
return 0;
}
vip_dbg(1, dev, "stream on failed in subdev\n");
}
- disable_irqs(dev, dev->slice_id);
- clear_irqs(dev, dev->slice_id);
+ disable_irqs(dev, dev->slice_id, stream->list_num);
+ clear_irqs(dev, dev->slice_id, stream->list_num);
+ stop_dma(stream);
/* release all active buffers */
- while (!list_empty(&dev->vip_bufs)) {
- buf = list_entry(dev->vip_bufs.next, struct vip_buffer, list);
+ while (!list_empty(&stream->post_bufs)) {
+ buf = list_entry(stream->post_bufs.next,
+ struct vip_buffer, list);
list_del(&buf->list);
if (buf->drop == 1)
list_add_tail(&buf->list, &stream->dropq);
if (!vb2_is_streaming(vq))
return 0;
- vpdma_unmap_desc_buf(dev->shared->vpdma, &dev->desc_list.buf);
- vpdma_reset_desc_list(&dev->desc_list);
+ vpdma_unmap_desc_buf(dev->shared->vpdma, &stream->desc_list.buf);
+ vpdma_reset_desc_list(&stream->desc_list);
return 0;
}
*/
static int vip_init_dev(struct vip_dev *dev)
+{
+ if (dev->num_ports != 0)
+ goto done;
+
+ vip_set_clock_enable(dev, 1);
+done:
+ dev->num_ports++;
+
+ return 0;
+}
+
+static int vip_init_port(struct vip_port *port)
{
int ret;
- if (dev->num_ports != 0)
+ if (port->num_streams != 0)
goto done;
- ret = vpdma_create_desc_list(&dev->desc_list, VIP_DESC_LIST_SIZE,
+ ret = vip_init_dev(port->dev);
+ if (ret)
+ goto done;
+
+ port->fmt = port->dev->active_fmt[0];
+ port->src_colorspace = port->fmt->colorspace;
+ port->c_rect.left = 0;
+ port->c_rect.top = 0;
+
+done:
+ port->num_streams++;
+ return 0;
+}
+
+static int vip_init_stream(struct vip_stream *stream)
+{
+ int ret;
+
+ ret = vip_init_port(stream->port);
+ if (ret != 0)
+ return ret;
+
+ ret = vpdma_create_desc_list(&stream->desc_list, VIP_DESC_LIST_SIZE,
VPDMA_LIST_TYPE_NORMAL);
if (ret != 0)
return ret;
- dev->write_desc = (struct vpdma_dtd *)dev->desc_list.buf.addr
+ stream->write_desc = (struct vpdma_dtd *)stream->desc_list.buf.addr
+ 15;
- vip_set_clock_enable(dev, 1);
-done:
- dev->num_ports++;
-
return 0;
}
static void vip_release_dev(struct vip_dev *dev)
{
- vpdma_unmap_desc_buf(dev->shared->vpdma, &dev->desc_list.buf);
- vpdma_free_desc_buf(&dev->desc_list.buf);
- vpdma_free_desc_list(&dev->desc_list);
-
/*
* On last close, disable clocks to conserve power
*/
struct vip_dev *dev = port->dev;
struct v4l2_of_endpoint *endpoint = dev->endpoint;
int iface = DUAL_8B_INTERFACE;
- int sync_type;
+ int sync_type, pclk_type;
unsigned int flags;
+ flags = endpoint->bus.parallel.flags;
vip_reset_port(port);
vip_set_port_enable(port, 1);
break;
case 1:
default:
- sync_type = EMBEDDED_SYNC_SINGLE_YUV422;
+ sync_type =
+ EMBEDDED_SYNC_LINE_MULTIPLEXED_YUV422;
}
}
else
sync_type = DISCRETE_SYNC_SINGLE_YUV422;
- flags = endpoint->bus.parallel.flags;
if (flags & (V4L2_MBUS_HSYNC_ACTIVE_HIGH |
V4L2_MBUS_HSYNC_ACTIVE_LOW))
vip_set_vsync_polarity(port,
vip_set_hsync_polarity(port,
flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH ? 1 : 0);
- if (flags & (V4L2_MBUS_PCLK_SAMPLE_RISING |
- V4L2_MBUS_PCLK_SAMPLE_FALLING))
- vip_set_pclk_polarity(port,
- flags & V4L2_MBUS_PCLK_SAMPLE_RISING ? 1 : 0);
-
vip_xtra_set_repack_sel(port, 0);
vip_set_actvid_hsync_n(port, 0);
vip_set_actvid_polarity(port, 1);
return -EINVAL;
}
+ pclk_type = flags & V4L2_MBUS_PCLK_SAMPLE_RISING ? 0 : 1;
+ vip_set_pclk_polarity(port, pclk_type);
vip_set_data_interface(port, iface);
vip_sync_type(port, sync_type);
return 0;
}
-static int vip_init_port(struct vip_port *port)
+static void vip_release_stream(struct vip_stream *stream)
{
- int ret;
-
- if (port->num_streams != 0)
- goto done;
-
- ret = vip_init_dev(port->dev);
- if (ret)
- goto done;
-
- port->fmt = port->dev->active_fmt[0];
- port->src_colorspace = port->fmt->colorspace;
- port->c_rect.left = 0;
- port->c_rect.top = 0;
+ struct vip_dev *dev = stream->port->dev;
-done:
- port->num_streams++;
- return 0;
+ vpdma_unmap_desc_buf(dev->shared->vpdma, &stream->desc_list.buf);
+ vpdma_free_desc_buf(&stream->desc_list.buf);
+ vpdma_free_desc_list(&stream->desc_list);
}
-static void vip_release_port(struct vip_port *port)
+static void stop_dma(struct vip_stream *stream)
{
- struct vip_dev *dev = port->dev;
+ struct vip_dev *dev = stream->port->dev;
int ch, size = 0;
/* Create a list of channels to be cleared */
for (ch = 0; ch < VPDMA_MAX_CHANNELS; ch++) {
- if (dev->vpdma_channels[ch] == 1) {
- dev->vpdma_channels[size++] = ch;
+ if (stream->vpdma_channels[ch] == 1) {
+ stream->vpdma_channels[size++] = ch;
vip_dbg(2, dev, "Clear channel no: %d\n", ch);
}
}
/* Clear all the used channels for the list */
- vpdma_list_cleanup(dev->shared->vpdma, dev->slice_id,
- dev->vpdma_channels, size);
+ vpdma_list_cleanup(dev->shared->vpdma, stream->list_num,
+ stream->vpdma_channels, size);
for (ch = 0; ch < VPDMA_MAX_CHANNELS; ch++)
- dev->vpdma_channels[ch] = 0;
-
- if (--port->num_streams == 0)
- vip_release_dev(port->dev);
+ stream->vpdma_channels[ch] = 0;
}
int vip_open(struct file *file)
* Then initialize hw module.
*/
if (v4l2_fh_is_singular_file(file)) {
- if (vip_init_port(port)) {
+ if (vip_init_stream(stream)) {
goto free_fh;
ret = -ENODEV;
}
mutex_lock(&dev->mutex);
vip_stop_streaming(q);
- vip_release_port(stream->port);
+ vip_release_stream(stream);
+
+ if (--port->num_streams == 0)
+ vip_release_dev(port->dev);
mutex_unlock(&dev->mutex);
vip_dbg(1, dev, "Releasing stream instance %p\n", stream);
stream->stream_id = stream_id;
stream->vfl_type = vfl_type;
+ stream->list_num = vpdma_hwlist_alloc(dev->shared->vpdma, stream);
+ if (stream->list_num < 0) {
+ vip_err(dev, "Could not get VPDMA hwlist");
+ ret = -ENODEV;
+ goto do_free_stream;
+ }
+
+ INIT_LIST_HEAD(&stream->post_bufs);
+
if (vfl_type == VFL_TYPE_GRABBER)
port->cap_streams[stream_id] = stream;
else
video_unregister_device(stream->vfd);
video_device_release(stream->vfd);
+ vpdma_hwlist_release(dev->shared->vpdma, stream->list_num);
kfree(stream);
}
port->dev = dev;
port->port_id = id;
port->num_streams = 0;
+ port->flags |= FLAG_MULT_PORT;
ret = alloc_stream(port, 0, VFL_TYPE_GRABBER);
+ if (dev->endpoint->bus_type == V4L2_MBUS_BT656) {
+ /* Allocate streams for 4 channels */
+ ret = alloc_stream(port, 2, VFL_TYPE_GRABBER);
+ ret = alloc_stream(port, 4, VFL_TYPE_GRABBER);
+ ret = alloc_stream(port, 6, VFL_TYPE_GRABBER);
+ }
+
return 0;
}
}
}
+ if (find_active_format_by_pix(dev, V4L2_PIX_FMT_YUYV))
+ /* When YUYV format is supported, NV12 can also be supported */
+ dev->active_fmt[dev->num_active_fmt++] = &vip_formats[2];
+
if (dev->num_active_fmt == 0) {
vip_err(dev, "No suitable format reported by subdev %s\n",
if (dev->sensor) {
if (asd < dev->sensor->asd) {
/* Notified of a subdev earlier in the array */
+ dev->sensor = subdev;
+ dev->endpoint = &dev->config->endpoints[idx];
vip_info(dev, "Switching to subdev %s (High priority)",
subdev->name);
- } else {
+
+ } else
vip_info(dev, "Rejecting subdev %s (Low priority)",
subdev->name);
- return 0;
- }
- } else
- alloc_port(dev, 0);
+ return 0;
+ }
dev->sensor = subdev;
dev->endpoint = &dev->config->endpoints[idx];
- vip_info(dev, "Using sensor %s for capture\n",
- subdev->name);
+ vip_info(dev, "Using sensor %s for capture\n", subdev->name);
+ alloc_port(dev, 0);
return 0;
}
vip_shared_set_clock_enable(shared, 1);
vip_top_vpdma_reset(shared);
- shared->vpdma = vpdma_create(pdev, vip_vpdma_fw_cb);
- if (!shared->vpdma) {
- dev_err(&pdev->dev, "Creating VPDMA failed");
- goto do_iounmap;
- }
-
list_add_tail(&shared->list, &vip_shared_list);
platform_set_drvdata(pdev, shared);
atomic_set(&shared->devs_allocated, 0);
if (!dev)
return -ENOMEM;
+ dev->instance_id = (int)of_dev_id->data;
+ snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name),
+ "%s%d-s%d", VIP_MODULE_NAME, dev->instance_id, slice);
+
dev->irq = platform_get_irq(pdev, slice);
if (!dev->irq) {
dev_err(&pdev->dev, "Could not get IRQ");
}
if (devm_request_irq(&pdev->dev, dev->irq, vip_irq,
- 0, VIP_MODULE_NAME, dev) < 0) {
+ 0, dev->v4l2_dev.name, dev) < 0) {
ret = -ENOMEM;
goto dev_unreg;
}
spin_lock_init(&dev->slock);
spin_lock_init(&dev->lock);
- INIT_LIST_HEAD(&dev->vip_bufs);
-
- dev->instance_id = (int)of_dev_id->data;
-
- snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name),
- "%s%d-%d", VIP_MODULE_NAME, dev->instance_id, slice);
ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
if (ret)
goto err_runtime_get;
vip_set_slice_path(dev, VIP_MULTI_CHANNEL_DATA_SELECT);
}
+ shared->vpdma = vpdma_create(pdev, vip_vpdma_fw_cb);
+ if (!shared->vpdma) {
+ dev_err(&pdev->dev, "Creating VPDMA failed");
+ goto dev_unreg;
+ }
+
return 0;
dev_unreg:
},
{},
};
+MODULE_DEVICE_TABLE(of, vip_of_match);
#else
#define vip_of_match NULL
#endif