1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * TI OMAP4 ISS V4L2 Driver - Generic video node 4 * 5 * Copyright (C) 2012 Texas Instruments, Inc. 6 * 7 * Author: Sergio Aguirre <sergio.a.aguirre@gmail.com> 8 */ 9 10 #include <linux/clk.h> 11 #include <linux/mm.h> 12 #include <linux/pagemap.h> 13 #include <linux/sched.h> 14 #include <linux/slab.h> 15 #include <linux/vmalloc.h> 16 #include <linux/module.h> 17 18 #include <media/v4l2-dev.h> 19 #include <media/v4l2-ioctl.h> 20 #include <media/v4l2-mc.h> 21 22 #include <asm/cacheflush.h> 23 24 #include "iss_video.h" 25 #include "iss.h" 26 27 /* ----------------------------------------------------------------------------- 28 * Helper functions 29 */ 30 31 static struct iss_format_info formats[] = { 32 { MEDIA_BUS_FMT_Y8_1X8, MEDIA_BUS_FMT_Y8_1X8, 33 MEDIA_BUS_FMT_Y8_1X8, MEDIA_BUS_FMT_Y8_1X8, 34 V4L2_PIX_FMT_GREY, 8, }, 35 { MEDIA_BUS_FMT_Y10_1X10, MEDIA_BUS_FMT_Y10_1X10, 36 MEDIA_BUS_FMT_Y10_1X10, MEDIA_BUS_FMT_Y8_1X8, 37 V4L2_PIX_FMT_Y10, 10, }, 38 { MEDIA_BUS_FMT_Y12_1X12, MEDIA_BUS_FMT_Y10_1X10, 39 MEDIA_BUS_FMT_Y12_1X12, MEDIA_BUS_FMT_Y8_1X8, 40 V4L2_PIX_FMT_Y12, 12, }, 41 { MEDIA_BUS_FMT_SBGGR8_1X8, MEDIA_BUS_FMT_SBGGR8_1X8, 42 MEDIA_BUS_FMT_SBGGR8_1X8, MEDIA_BUS_FMT_SBGGR8_1X8, 43 V4L2_PIX_FMT_SBGGR8, 8, }, 44 { MEDIA_BUS_FMT_SGBRG8_1X8, MEDIA_BUS_FMT_SGBRG8_1X8, 45 MEDIA_BUS_FMT_SGBRG8_1X8, MEDIA_BUS_FMT_SGBRG8_1X8, 46 V4L2_PIX_FMT_SGBRG8, 8, }, 47 { MEDIA_BUS_FMT_SGRBG8_1X8, MEDIA_BUS_FMT_SGRBG8_1X8, 48 MEDIA_BUS_FMT_SGRBG8_1X8, MEDIA_BUS_FMT_SGRBG8_1X8, 49 V4L2_PIX_FMT_SGRBG8, 8, }, 50 { MEDIA_BUS_FMT_SRGGB8_1X8, MEDIA_BUS_FMT_SRGGB8_1X8, 51 MEDIA_BUS_FMT_SRGGB8_1X8, MEDIA_BUS_FMT_SRGGB8_1X8, 52 V4L2_PIX_FMT_SRGGB8, 8, }, 53 { MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, 54 MEDIA_BUS_FMT_SGRBG10_1X10, 0, 55 V4L2_PIX_FMT_SGRBG10DPCM8, 8, }, 56 { MEDIA_BUS_FMT_SBGGR10_1X10, MEDIA_BUS_FMT_SBGGR10_1X10, 57 MEDIA_BUS_FMT_SBGGR10_1X10, MEDIA_BUS_FMT_SBGGR8_1X8, 58 V4L2_PIX_FMT_SBGGR10, 10, }, 59 { MEDIA_BUS_FMT_SGBRG10_1X10, MEDIA_BUS_FMT_SGBRG10_1X10, 60 MEDIA_BUS_FMT_SGBRG10_1X10, MEDIA_BUS_FMT_SGBRG8_1X8, 61 V4L2_PIX_FMT_SGBRG10, 10, }, 62 { MEDIA_BUS_FMT_SGRBG10_1X10, MEDIA_BUS_FMT_SGRBG10_1X10, 63 MEDIA_BUS_FMT_SGRBG10_1X10, MEDIA_BUS_FMT_SGRBG8_1X8, 64 V4L2_PIX_FMT_SGRBG10, 10, }, 65 { MEDIA_BUS_FMT_SRGGB10_1X10, MEDIA_BUS_FMT_SRGGB10_1X10, 66 MEDIA_BUS_FMT_SRGGB10_1X10, MEDIA_BUS_FMT_SRGGB8_1X8, 67 V4L2_PIX_FMT_SRGGB10, 10, }, 68 { MEDIA_BUS_FMT_SBGGR12_1X12, MEDIA_BUS_FMT_SBGGR10_1X10, 69 MEDIA_BUS_FMT_SBGGR12_1X12, MEDIA_BUS_FMT_SBGGR8_1X8, 70 V4L2_PIX_FMT_SBGGR12, 12, }, 71 { MEDIA_BUS_FMT_SGBRG12_1X12, MEDIA_BUS_FMT_SGBRG10_1X10, 72 MEDIA_BUS_FMT_SGBRG12_1X12, MEDIA_BUS_FMT_SGBRG8_1X8, 73 V4L2_PIX_FMT_SGBRG12, 12, }, 74 { MEDIA_BUS_FMT_SGRBG12_1X12, MEDIA_BUS_FMT_SGRBG10_1X10, 75 MEDIA_BUS_FMT_SGRBG12_1X12, MEDIA_BUS_FMT_SGRBG8_1X8, 76 V4L2_PIX_FMT_SGRBG12, 12, }, 77 { MEDIA_BUS_FMT_SRGGB12_1X12, MEDIA_BUS_FMT_SRGGB10_1X10, 78 MEDIA_BUS_FMT_SRGGB12_1X12, MEDIA_BUS_FMT_SRGGB8_1X8, 79 V4L2_PIX_FMT_SRGGB12, 12, }, 80 { MEDIA_BUS_FMT_UYVY8_1X16, MEDIA_BUS_FMT_UYVY8_1X16, 81 MEDIA_BUS_FMT_UYVY8_1X16, 0, 82 V4L2_PIX_FMT_UYVY, 16, }, 83 { MEDIA_BUS_FMT_YUYV8_1X16, MEDIA_BUS_FMT_YUYV8_1X16, 84 MEDIA_BUS_FMT_YUYV8_1X16, 0, 85 V4L2_PIX_FMT_YUYV, 16, }, 86 { MEDIA_BUS_FMT_YUYV8_1_5X8, MEDIA_BUS_FMT_YUYV8_1_5X8, 87 MEDIA_BUS_FMT_YUYV8_1_5X8, 0, 88 V4L2_PIX_FMT_NV12, 8, }, 89 }; 90 91 const struct iss_format_info * 92 omap4iss_video_format_info(u32 code) 93 { 94 unsigned int i; 95 96 for (i = 0; i < ARRAY_SIZE(formats); ++i) { 97 if (formats[i].code == code) 98 return &formats[i]; 99 } 100 101 return NULL; 102 } 103 104 /* 105 * iss_video_mbus_to_pix - Convert v4l2_mbus_framefmt to v4l2_pix_format 106 * @video: ISS video instance 107 * @mbus: v4l2_mbus_framefmt format (input) 108 * @pix: v4l2_pix_format format (output) 109 * 110 * Fill the output pix structure with information from the input mbus format. 111 * The bytesperline and sizeimage fields are computed from the requested bytes 112 * per line value in the pix format and information from the video instance. 113 * 114 * Return the number of padding bytes at end of line. 115 */ 116 static unsigned int iss_video_mbus_to_pix(const struct iss_video *video, 117 const struct v4l2_mbus_framefmt *mbus, 118 struct v4l2_pix_format *pix) 119 { 120 unsigned int bpl = pix->bytesperline; 121 unsigned int min_bpl; 122 unsigned int i; 123 124 memset(pix, 0, sizeof(*pix)); 125 pix->width = mbus->width; 126 pix->height = mbus->height; 127 128 /* 129 * Skip the last format in the loop so that it will be selected if no 130 * match is found. 131 */ 132 for (i = 0; i < ARRAY_SIZE(formats) - 1; ++i) { 133 if (formats[i].code == mbus->code) 134 break; 135 } 136 137 min_bpl = pix->width * ALIGN(formats[i].bpp, 8) / 8; 138 139 /* 140 * Clamp the requested bytes per line value. If the maximum bytes per 141 * line value is zero, the module doesn't support user configurable line 142 * sizes. Override the requested value with the minimum in that case. 143 */ 144 if (video->bpl_max) 145 bpl = clamp(bpl, min_bpl, video->bpl_max); 146 else 147 bpl = min_bpl; 148 149 if (!video->bpl_zero_padding || bpl != min_bpl) 150 bpl = ALIGN(bpl, video->bpl_alignment); 151 152 pix->pixelformat = formats[i].pixelformat; 153 pix->bytesperline = bpl; 154 pix->sizeimage = pix->bytesperline * pix->height; 155 pix->colorspace = mbus->colorspace; 156 pix->field = mbus->field; 157 158 /* FIXME: Special case for NV12! We should make this nicer... */ 159 if (pix->pixelformat == V4L2_PIX_FMT_NV12) 160 pix->sizeimage += (pix->bytesperline * pix->height) / 2; 161 162 return bpl - min_bpl; 163 } 164 165 static void iss_video_pix_to_mbus(const struct v4l2_pix_format *pix, 166 struct v4l2_mbus_framefmt *mbus) 167 { 168 unsigned int i; 169 170 memset(mbus, 0, sizeof(*mbus)); 171 mbus->width = pix->width; 172 mbus->height = pix->height; 173 174 /* 175 * Skip the last format in the loop so that it will be selected if no 176 * match is found. 177 */ 178 for (i = 0; i < ARRAY_SIZE(formats) - 1; ++i) { 179 if (formats[i].pixelformat == pix->pixelformat) 180 break; 181 } 182 183 mbus->code = formats[i].code; 184 mbus->colorspace = pix->colorspace; 185 mbus->field = pix->field; 186 } 187 188 static struct v4l2_subdev * 189 iss_video_remote_subdev(struct iss_video *video, u32 *pad) 190 { 191 struct media_pad *remote; 192 193 remote = media_entity_remote_pad(&video->pad); 194 195 if (!remote || !is_media_entity_v4l2_subdev(remote->entity)) 196 return NULL; 197 198 if (pad) 199 *pad = remote->index; 200 201 return media_entity_to_v4l2_subdev(remote->entity); 202 } 203 204 /* Return a pointer to the ISS video instance at the far end of the pipeline. */ 205 static struct iss_video * 206 iss_video_far_end(struct iss_video *video) 207 { 208 struct media_graph graph; 209 struct media_entity *entity = &video->video.entity; 210 struct media_device *mdev = entity->graph_obj.mdev; 211 struct iss_video *far_end = NULL; 212 213 mutex_lock(&mdev->graph_mutex); 214 215 if (media_graph_walk_init(&graph, mdev)) { 216 mutex_unlock(&mdev->graph_mutex); 217 return NULL; 218 } 219 220 media_graph_walk_start(&graph, entity); 221 222 while ((entity = media_graph_walk_next(&graph))) { 223 if (entity == &video->video.entity) 224 continue; 225 226 if (!is_media_entity_v4l2_video_device(entity)) 227 continue; 228 229 far_end = to_iss_video(media_entity_to_video_device(entity)); 230 if (far_end->type != video->type) 231 break; 232 233 far_end = NULL; 234 } 235 236 mutex_unlock(&mdev->graph_mutex); 237 238 media_graph_walk_cleanup(&graph); 239 240 return far_end; 241 } 242 243 static int 244 __iss_video_get_format(struct iss_video *video, 245 struct v4l2_mbus_framefmt *format) 246 { 247 struct v4l2_subdev_format fmt; 248 struct v4l2_subdev *subdev; 249 u32 pad; 250 int ret; 251 252 subdev = iss_video_remote_subdev(video, &pad); 253 if (!subdev) 254 return -EINVAL; 255 256 memset(&fmt, 0, sizeof(fmt)); 257 fmt.pad = pad; 258 fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; 259 260 mutex_lock(&video->mutex); 261 ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt); 262 mutex_unlock(&video->mutex); 263 264 if (ret) 265 return ret; 266 267 *format = fmt.format; 268 return 0; 269 } 270 271 static int 272 iss_video_check_format(struct iss_video *video, struct iss_video_fh *vfh) 273 { 274 struct v4l2_mbus_framefmt format; 275 struct v4l2_pix_format pixfmt; 276 int ret; 277 278 ret = __iss_video_get_format(video, &format); 279 if (ret < 0) 280 return ret; 281 282 pixfmt.bytesperline = 0; 283 ret = iss_video_mbus_to_pix(video, &format, &pixfmt); 284 285 if (vfh->format.fmt.pix.pixelformat != pixfmt.pixelformat || 286 vfh->format.fmt.pix.height != pixfmt.height || 287 vfh->format.fmt.pix.width != pixfmt.width || 288 vfh->format.fmt.pix.bytesperline != pixfmt.bytesperline || 289 vfh->format.fmt.pix.sizeimage != pixfmt.sizeimage) 290 return -EINVAL; 291 292 return ret; 293 } 294 295 /* ----------------------------------------------------------------------------- 296 * Video queue operations 297 */ 298 299 static int iss_video_queue_setup(struct vb2_queue *vq, 300 unsigned int *count, unsigned int *num_planes, 301 unsigned int sizes[], 302 struct device *alloc_devs[]) 303 { 304 struct iss_video_fh *vfh = vb2_get_drv_priv(vq); 305 struct iss_video *video = vfh->video; 306 307 /* Revisit multi-planar support for NV12 */ 308 *num_planes = 1; 309 310 sizes[0] = vfh->format.fmt.pix.sizeimage; 311 if (sizes[0] == 0) 312 return -EINVAL; 313 314 *count = min(*count, video->capture_mem / PAGE_ALIGN(sizes[0])); 315 316 return 0; 317 } 318 319 static void iss_video_buf_cleanup(struct vb2_buffer *vb) 320 { 321 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 322 struct iss_buffer *buffer = container_of(vbuf, struct iss_buffer, vb); 323 324 if (buffer->iss_addr) 325 buffer->iss_addr = 0; 326 } 327 328 static int iss_video_buf_prepare(struct vb2_buffer *vb) 329 { 330 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 331 struct iss_video_fh *vfh = vb2_get_drv_priv(vb->vb2_queue); 332 struct iss_buffer *buffer = container_of(vbuf, struct iss_buffer, vb); 333 struct iss_video *video = vfh->video; 334 unsigned long size = vfh->format.fmt.pix.sizeimage; 335 dma_addr_t addr; 336 337 if (vb2_plane_size(vb, 0) < size) 338 return -ENOBUFS; 339 340 addr = vb2_dma_contig_plane_dma_addr(vb, 0); 341 if (!IS_ALIGNED(addr, 32)) { 342 dev_dbg(video->iss->dev, 343 "Buffer address must be aligned to 32 bytes boundary.\n"); 344 return -EINVAL; 345 } 346 347 vb2_set_plane_payload(vb, 0, size); 348 buffer->iss_addr = addr; 349 return 0; 350 } 351 352 static void iss_video_buf_queue(struct vb2_buffer *vb) 353 { 354 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 355 struct iss_video_fh *vfh = vb2_get_drv_priv(vb->vb2_queue); 356 struct iss_video *video = vfh->video; 357 struct iss_buffer *buffer = container_of(vbuf, struct iss_buffer, vb); 358 struct iss_pipeline *pipe = to_iss_pipeline(&video->video.entity); 359 unsigned long flags; 360 bool empty; 361 362 spin_lock_irqsave(&video->qlock, flags); 363 364 /* 365 * Mark the buffer is faulty and give it back to the queue immediately 366 * if the video node has registered an error. vb2 will perform the same 367 * check when preparing the buffer, but that is inherently racy, so we 368 * need to handle the race condition with an authoritative check here. 369 */ 370 if (unlikely(video->error)) { 371 vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); 372 spin_unlock_irqrestore(&video->qlock, flags); 373 return; 374 } 375 376 empty = list_empty(&video->dmaqueue); 377 list_add_tail(&buffer->list, &video->dmaqueue); 378 379 spin_unlock_irqrestore(&video->qlock, flags); 380 381 if (empty) { 382 enum iss_pipeline_state state; 383 unsigned int start; 384 385 if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) 386 state = ISS_PIPELINE_QUEUE_OUTPUT; 387 else 388 state = ISS_PIPELINE_QUEUE_INPUT; 389 390 spin_lock_irqsave(&pipe->lock, flags); 391 pipe->state |= state; 392 video->ops->queue(video, buffer); 393 video->dmaqueue_flags |= ISS_VIDEO_DMAQUEUE_QUEUED; 394 395 start = iss_pipeline_ready(pipe); 396 if (start) 397 pipe->state |= ISS_PIPELINE_STREAM; 398 spin_unlock_irqrestore(&pipe->lock, flags); 399 400 if (start) 401 omap4iss_pipeline_set_stream(pipe, 402 ISS_PIPELINE_STREAM_SINGLESHOT); 403 } 404 } 405 406 static const struct vb2_ops iss_video_vb2ops = { 407 .queue_setup = iss_video_queue_setup, 408 .buf_prepare = iss_video_buf_prepare, 409 .buf_queue = iss_video_buf_queue, 410 .buf_cleanup = iss_video_buf_cleanup, 411 }; 412 413 /* 414 * omap4iss_video_buffer_next - Complete the current buffer and return the next 415 * @video: ISS video object 416 * 417 * Remove the current video buffer from the DMA queue and fill its timestamp, 418 * field count and state fields before waking up its completion handler. 419 * 420 * For capture video nodes, the buffer state is set to VB2_BUF_STATE_DONE if no 421 * error has been flagged in the pipeline, or to VB2_BUF_STATE_ERROR otherwise. 422 * 423 * The DMA queue is expected to contain at least one buffer. 424 * 425 * Return a pointer to the next buffer in the DMA queue, or NULL if the queue is 426 * empty. 427 */ 428 struct iss_buffer *omap4iss_video_buffer_next(struct iss_video *video) 429 { 430 struct iss_pipeline *pipe = to_iss_pipeline(&video->video.entity); 431 enum iss_pipeline_state state; 432 struct iss_buffer *buf; 433 unsigned long flags; 434 435 spin_lock_irqsave(&video->qlock, flags); 436 if (WARN_ON(list_empty(&video->dmaqueue))) { 437 spin_unlock_irqrestore(&video->qlock, flags); 438 return NULL; 439 } 440 441 buf = list_first_entry(&video->dmaqueue, struct iss_buffer, 442 list); 443 list_del(&buf->list); 444 spin_unlock_irqrestore(&video->qlock, flags); 445 446 buf->vb.vb2_buf.timestamp = ktime_get_ns(); 447 448 /* 449 * Do frame number propagation only if this is the output video node. 450 * Frame number either comes from the CSI receivers or it gets 451 * incremented here if H3A is not active. 452 * Note: There is no guarantee that the output buffer will finish 453 * first, so the input number might lag behind by 1 in some cases. 454 */ 455 if (video == pipe->output && !pipe->do_propagation) 456 buf->vb.sequence = 457 atomic_inc_return(&pipe->frame_number); 458 else 459 buf->vb.sequence = atomic_read(&pipe->frame_number); 460 461 vb2_buffer_done(&buf->vb.vb2_buf, pipe->error ? 462 VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); 463 pipe->error = false; 464 465 spin_lock_irqsave(&video->qlock, flags); 466 if (list_empty(&video->dmaqueue)) { 467 spin_unlock_irqrestore(&video->qlock, flags); 468 if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) 469 state = ISS_PIPELINE_QUEUE_OUTPUT 470 | ISS_PIPELINE_STREAM; 471 else 472 state = ISS_PIPELINE_QUEUE_INPUT 473 | ISS_PIPELINE_STREAM; 474 475 spin_lock_irqsave(&pipe->lock, flags); 476 pipe->state &= ~state; 477 if (video->pipe.stream_state == ISS_PIPELINE_STREAM_CONTINUOUS) 478 video->dmaqueue_flags |= ISS_VIDEO_DMAQUEUE_UNDERRUN; 479 spin_unlock_irqrestore(&pipe->lock, flags); 480 return NULL; 481 } 482 483 if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && pipe->input) { 484 spin_lock(&pipe->lock); 485 pipe->state &= ~ISS_PIPELINE_STREAM; 486 spin_unlock(&pipe->lock); 487 } 488 489 buf = list_first_entry(&video->dmaqueue, struct iss_buffer, 490 list); 491 spin_unlock_irqrestore(&video->qlock, flags); 492 buf->vb.vb2_buf.state = VB2_BUF_STATE_ACTIVE; 493 return buf; 494 } 495 496 /* 497 * omap4iss_video_cancel_stream - Cancel stream on a video node 498 * @video: ISS video object 499 * 500 * Cancelling a stream mark all buffers on the video node as erroneous and makes 501 * sure no new buffer can be queued. 502 */ 503 void omap4iss_video_cancel_stream(struct iss_video *video) 504 { 505 unsigned long flags; 506 507 spin_lock_irqsave(&video->qlock, flags); 508 509 while (!list_empty(&video->dmaqueue)) { 510 struct iss_buffer *buf; 511 512 buf = list_first_entry(&video->dmaqueue, struct iss_buffer, 513 list); 514 list_del(&buf->list); 515 vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); 516 } 517 518 vb2_queue_error(video->queue); 519 video->error = true; 520 521 spin_unlock_irqrestore(&video->qlock, flags); 522 } 523 524 /* ----------------------------------------------------------------------------- 525 * V4L2 ioctls 526 */ 527 528 static int 529 iss_video_querycap(struct file *file, void *fh, struct v4l2_capability *cap) 530 { 531 struct iss_video *video = video_drvdata(file); 532 533 strscpy(cap->driver, ISS_VIDEO_DRIVER_NAME, sizeof(cap->driver)); 534 strscpy(cap->card, video->video.name, sizeof(cap->card)); 535 strscpy(cap->bus_info, "media", sizeof(cap->bus_info)); 536 cap->capabilities = V4L2_CAP_DEVICE_CAPS | V4L2_CAP_STREAMING 537 | V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT; 538 539 return 0; 540 } 541 542 static int 543 iss_video_enum_format(struct file *file, void *fh, struct v4l2_fmtdesc *f) 544 { 545 struct iss_video *video = video_drvdata(file); 546 struct v4l2_mbus_framefmt format; 547 unsigned int index = f->index; 548 unsigned int i; 549 int ret; 550 551 if (f->type != video->type) 552 return -EINVAL; 553 554 ret = __iss_video_get_format(video, &format); 555 if (ret < 0) 556 return ret; 557 558 for (i = 0; i < ARRAY_SIZE(formats); ++i) { 559 const struct iss_format_info *info = &formats[i]; 560 561 if (format.code != info->code) 562 continue; 563 564 if (index == 0) { 565 f->pixelformat = info->pixelformat; 566 return 0; 567 } 568 569 index--; 570 } 571 572 return -EINVAL; 573 } 574 575 static int 576 iss_video_get_format(struct file *file, void *fh, struct v4l2_format *format) 577 { 578 struct iss_video_fh *vfh = to_iss_video_fh(fh); 579 struct iss_video *video = video_drvdata(file); 580 581 if (format->type != video->type) 582 return -EINVAL; 583 584 mutex_lock(&video->mutex); 585 *format = vfh->format; 586 mutex_unlock(&video->mutex); 587 588 return 0; 589 } 590 591 static int 592 iss_video_set_format(struct file *file, void *fh, struct v4l2_format *format) 593 { 594 struct iss_video_fh *vfh = to_iss_video_fh(fh); 595 struct iss_video *video = video_drvdata(file); 596 struct v4l2_mbus_framefmt fmt; 597 598 if (format->type != video->type) 599 return -EINVAL; 600 601 mutex_lock(&video->mutex); 602 603 /* 604 * Fill the bytesperline and sizeimage fields by converting to media bus 605 * format and back to pixel format. 606 */ 607 iss_video_pix_to_mbus(&format->fmt.pix, &fmt); 608 iss_video_mbus_to_pix(video, &fmt, &format->fmt.pix); 609 610 vfh->format = *format; 611 612 mutex_unlock(&video->mutex); 613 return 0; 614 } 615 616 static int 617 iss_video_try_format(struct file *file, void *fh, struct v4l2_format *format) 618 { 619 struct iss_video *video = video_drvdata(file); 620 struct v4l2_subdev_format fmt; 621 struct v4l2_subdev *subdev; 622 u32 pad; 623 int ret; 624 625 if (format->type != video->type) 626 return -EINVAL; 627 628 subdev = iss_video_remote_subdev(video, &pad); 629 if (!subdev) 630 return -EINVAL; 631 632 iss_video_pix_to_mbus(&format->fmt.pix, &fmt.format); 633 634 fmt.pad = pad; 635 fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; 636 ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt); 637 if (ret) 638 return ret; 639 640 iss_video_mbus_to_pix(video, &fmt.format, &format->fmt.pix); 641 return 0; 642 } 643 644 static int 645 iss_video_get_selection(struct file *file, void *fh, struct v4l2_selection *sel) 646 { 647 struct iss_video *video = video_drvdata(file); 648 struct v4l2_subdev_format format; 649 struct v4l2_subdev *subdev; 650 struct v4l2_subdev_selection sdsel = { 651 .which = V4L2_SUBDEV_FORMAT_ACTIVE, 652 .target = sel->target, 653 }; 654 u32 pad; 655 int ret; 656 657 switch (sel->target) { 658 case V4L2_SEL_TGT_CROP: 659 case V4L2_SEL_TGT_CROP_BOUNDS: 660 case V4L2_SEL_TGT_CROP_DEFAULT: 661 if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) 662 return -EINVAL; 663 break; 664 case V4L2_SEL_TGT_COMPOSE: 665 case V4L2_SEL_TGT_COMPOSE_BOUNDS: 666 case V4L2_SEL_TGT_COMPOSE_DEFAULT: 667 if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) 668 return -EINVAL; 669 break; 670 default: 671 return -EINVAL; 672 } 673 subdev = iss_video_remote_subdev(video, &pad); 674 if (!subdev) 675 return -EINVAL; 676 677 /* 678 * Try the get selection operation first and fallback to get format if 679 * not implemented. 680 */ 681 sdsel.pad = pad; 682 ret = v4l2_subdev_call(subdev, pad, get_selection, NULL, &sdsel); 683 if (!ret) 684 sel->r = sdsel.r; 685 if (ret != -ENOIOCTLCMD) 686 return ret; 687 688 format.pad = pad; 689 format.which = V4L2_SUBDEV_FORMAT_ACTIVE; 690 ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &format); 691 if (ret < 0) 692 return ret == -ENOIOCTLCMD ? -ENOTTY : ret; 693 694 sel->r.left = 0; 695 sel->r.top = 0; 696 sel->r.width = format.format.width; 697 sel->r.height = format.format.height; 698 699 return 0; 700 } 701 702 static int 703 iss_video_set_selection(struct file *file, void *fh, struct v4l2_selection *sel) 704 { 705 struct iss_video *video = video_drvdata(file); 706 struct v4l2_subdev *subdev; 707 struct v4l2_subdev_selection sdsel = { 708 .which = V4L2_SUBDEV_FORMAT_ACTIVE, 709 .target = sel->target, 710 .flags = sel->flags, 711 .r = sel->r, 712 }; 713 u32 pad; 714 int ret; 715 716 switch (sel->target) { 717 case V4L2_SEL_TGT_CROP: 718 if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) 719 return -EINVAL; 720 break; 721 case V4L2_SEL_TGT_COMPOSE: 722 if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) 723 return -EINVAL; 724 break; 725 default: 726 return -EINVAL; 727 } 728 subdev = iss_video_remote_subdev(video, &pad); 729 if (!subdev) 730 return -EINVAL; 731 732 sdsel.pad = pad; 733 mutex_lock(&video->mutex); 734 ret = v4l2_subdev_call(subdev, pad, set_selection, NULL, &sdsel); 735 mutex_unlock(&video->mutex); 736 if (!ret) 737 sel->r = sdsel.r; 738 739 return ret == -ENOIOCTLCMD ? -ENOTTY : ret; 740 } 741 742 static int 743 iss_video_get_param(struct file *file, void *fh, struct v4l2_streamparm *a) 744 { 745 struct iss_video_fh *vfh = to_iss_video_fh(fh); 746 struct iss_video *video = video_drvdata(file); 747 748 if (video->type != V4L2_BUF_TYPE_VIDEO_OUTPUT || 749 video->type != a->type) 750 return -EINVAL; 751 752 memset(a, 0, sizeof(*a)); 753 a->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; 754 a->parm.output.capability = V4L2_CAP_TIMEPERFRAME; 755 a->parm.output.timeperframe = vfh->timeperframe; 756 757 return 0; 758 } 759 760 static int 761 iss_video_set_param(struct file *file, void *fh, struct v4l2_streamparm *a) 762 { 763 struct iss_video_fh *vfh = to_iss_video_fh(fh); 764 struct iss_video *video = video_drvdata(file); 765 766 if (video->type != V4L2_BUF_TYPE_VIDEO_OUTPUT || 767 video->type != a->type) 768 return -EINVAL; 769 770 if (a->parm.output.timeperframe.denominator == 0) 771 a->parm.output.timeperframe.denominator = 1; 772 773 vfh->timeperframe = a->parm.output.timeperframe; 774 775 return 0; 776 } 777 778 static int 779 iss_video_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *rb) 780 { 781 struct iss_video_fh *vfh = to_iss_video_fh(fh); 782 783 return vb2_reqbufs(&vfh->queue, rb); 784 } 785 786 static int 787 iss_video_querybuf(struct file *file, void *fh, struct v4l2_buffer *b) 788 { 789 struct iss_video_fh *vfh = to_iss_video_fh(fh); 790 791 return vb2_querybuf(&vfh->queue, b); 792 } 793 794 static int 795 iss_video_qbuf(struct file *file, void *fh, struct v4l2_buffer *b) 796 { 797 struct iss_video *video = video_drvdata(file); 798 struct iss_video_fh *vfh = to_iss_video_fh(fh); 799 800 return vb2_qbuf(&vfh->queue, video->video.v4l2_dev->mdev, b); 801 } 802 803 static int 804 iss_video_expbuf(struct file *file, void *fh, struct v4l2_exportbuffer *e) 805 { 806 struct iss_video_fh *vfh = to_iss_video_fh(fh); 807 808 return vb2_expbuf(&vfh->queue, e); 809 } 810 811 static int 812 iss_video_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b) 813 { 814 struct iss_video_fh *vfh = to_iss_video_fh(fh); 815 816 return vb2_dqbuf(&vfh->queue, b, file->f_flags & O_NONBLOCK); 817 } 818 819 /* 820 * Stream management 821 * 822 * Every ISS pipeline has a single input and a single output. The input can be 823 * either a sensor or a video node. The output is always a video node. 824 * 825 * As every pipeline has an output video node, the ISS video objects at the 826 * pipeline output stores the pipeline state. It tracks the streaming state of 827 * both the input and output, as well as the availability of buffers. 828 * 829 * In sensor-to-memory mode, frames are always available at the pipeline input. 830 * Starting the sensor usually requires I2C transfers and must be done in 831 * interruptible context. The pipeline is started and stopped synchronously 832 * to the stream on/off commands. All modules in the pipeline will get their 833 * subdev set stream handler called. The module at the end of the pipeline must 834 * delay starting the hardware until buffers are available at its output. 835 * 836 * In memory-to-memory mode, starting/stopping the stream requires 837 * synchronization between the input and output. ISS modules can't be stopped 838 * in the middle of a frame, and at least some of the modules seem to become 839 * busy as soon as they're started, even if they don't receive a frame start 840 * event. For that reason frames need to be processed in single-shot mode. The 841 * driver needs to wait until a frame is completely processed and written to 842 * memory before restarting the pipeline for the next frame. Pipelined 843 * processing might be possible but requires more testing. 844 * 845 * Stream start must be delayed until buffers are available at both the input 846 * and output. The pipeline must be started in the videobuf queue callback with 847 * the buffers queue spinlock held. The modules subdev set stream operation must 848 * not sleep. 849 */ 850 static int 851 iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) 852 { 853 struct iss_video_fh *vfh = to_iss_video_fh(fh); 854 struct iss_video *video = video_drvdata(file); 855 struct media_graph graph; 856 struct media_entity *entity = &video->video.entity; 857 enum iss_pipeline_state state; 858 struct iss_pipeline *pipe; 859 struct iss_video *far_end; 860 unsigned long flags; 861 int ret; 862 863 if (type != video->type) 864 return -EINVAL; 865 866 mutex_lock(&video->stream_lock); 867 868 /* 869 * Start streaming on the pipeline. No link touching an entity in the 870 * pipeline can be activated or deactivated once streaming is started. 871 */ 872 pipe = entity->pipe 873 ? to_iss_pipeline(entity) : &video->pipe; 874 pipe->external = NULL; 875 pipe->external_rate = 0; 876 pipe->external_bpp = 0; 877 878 ret = media_entity_enum_init(&pipe->ent_enum, entity->graph_obj.mdev); 879 if (ret) 880 goto err_graph_walk_init; 881 882 ret = media_graph_walk_init(&graph, entity->graph_obj.mdev); 883 if (ret) 884 goto err_graph_walk_init; 885 886 if (video->iss->pdata->set_constraints) 887 video->iss->pdata->set_constraints(video->iss, true); 888 889 ret = media_pipeline_start(entity, &pipe->pipe); 890 if (ret < 0) 891 goto err_media_pipeline_start; 892 893 media_graph_walk_start(&graph, entity); 894 while ((entity = media_graph_walk_next(&graph))) 895 media_entity_enum_set(&pipe->ent_enum, entity); 896 897 /* 898 * Verify that the currently configured format matches the output of 899 * the connected subdev. 900 */ 901 ret = iss_video_check_format(video, vfh); 902 if (ret < 0) 903 goto err_iss_video_check_format; 904 905 video->bpl_padding = ret; 906 video->bpl_value = vfh->format.fmt.pix.bytesperline; 907 908 /* 909 * Find the ISS video node connected at the far end of the pipeline and 910 * update the pipeline. 911 */ 912 far_end = iss_video_far_end(video); 913 914 if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { 915 state = ISS_PIPELINE_STREAM_OUTPUT | ISS_PIPELINE_IDLE_OUTPUT; 916 pipe->input = far_end; 917 pipe->output = video; 918 } else { 919 if (!far_end) { 920 ret = -EPIPE; 921 goto err_iss_video_check_format; 922 } 923 924 state = ISS_PIPELINE_STREAM_INPUT | ISS_PIPELINE_IDLE_INPUT; 925 pipe->input = video; 926 pipe->output = far_end; 927 } 928 929 spin_lock_irqsave(&pipe->lock, flags); 930 pipe->state &= ~ISS_PIPELINE_STREAM; 931 pipe->state |= state; 932 spin_unlock_irqrestore(&pipe->lock, flags); 933 934 /* 935 * Set the maximum time per frame as the value requested by userspace. 936 * This is a soft limit that can be overridden if the hardware doesn't 937 * support the request limit. 938 */ 939 if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) 940 pipe->max_timeperframe = vfh->timeperframe; 941 942 video->queue = &vfh->queue; 943 INIT_LIST_HEAD(&video->dmaqueue); 944 video->error = false; 945 atomic_set(&pipe->frame_number, -1); 946 947 ret = vb2_streamon(&vfh->queue, type); 948 if (ret < 0) 949 goto err_iss_video_check_format; 950 951 /* 952 * In sensor-to-memory mode, the stream can be started synchronously 953 * to the stream on command. In memory-to-memory mode, it will be 954 * started when buffers are queued on both the input and output. 955 */ 956 if (!pipe->input) { 957 unsigned long flags; 958 959 ret = omap4iss_pipeline_set_stream(pipe, 960 ISS_PIPELINE_STREAM_CONTINUOUS); 961 if (ret < 0) 962 goto err_omap4iss_set_stream; 963 spin_lock_irqsave(&video->qlock, flags); 964 if (list_empty(&video->dmaqueue)) 965 video->dmaqueue_flags |= ISS_VIDEO_DMAQUEUE_UNDERRUN; 966 spin_unlock_irqrestore(&video->qlock, flags); 967 } 968 969 media_graph_walk_cleanup(&graph); 970 971 mutex_unlock(&video->stream_lock); 972 973 return 0; 974 975 err_omap4iss_set_stream: 976 vb2_streamoff(&vfh->queue, type); 977 err_iss_video_check_format: 978 media_pipeline_stop(&video->video.entity); 979 err_media_pipeline_start: 980 if (video->iss->pdata->set_constraints) 981 video->iss->pdata->set_constraints(video->iss, false); 982 video->queue = NULL; 983 984 media_graph_walk_cleanup(&graph); 985 986 err_graph_walk_init: 987 media_entity_enum_cleanup(&pipe->ent_enum); 988 989 mutex_unlock(&video->stream_lock); 990 991 return ret; 992 } 993 994 static int 995 iss_video_streamoff(struct file *file, void *fh, enum v4l2_buf_type type) 996 { 997 struct iss_video_fh *vfh = to_iss_video_fh(fh); 998 struct iss_video *video = video_drvdata(file); 999 struct iss_pipeline *pipe = to_iss_pipeline(&video->video.entity); 1000 enum iss_pipeline_state state; 1001 unsigned long flags; 1002 1003 if (type != video->type) 1004 return -EINVAL; 1005 1006 mutex_lock(&video->stream_lock); 1007 1008 if (!vb2_is_streaming(&vfh->queue)) 1009 goto done; 1010 1011 /* Update the pipeline state. */ 1012 if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) 1013 state = ISS_PIPELINE_STREAM_OUTPUT 1014 | ISS_PIPELINE_QUEUE_OUTPUT; 1015 else 1016 state = ISS_PIPELINE_STREAM_INPUT 1017 | ISS_PIPELINE_QUEUE_INPUT; 1018 1019 spin_lock_irqsave(&pipe->lock, flags); 1020 pipe->state &= ~state; 1021 spin_unlock_irqrestore(&pipe->lock, flags); 1022 1023 /* Stop the stream. */ 1024 omap4iss_pipeline_set_stream(pipe, ISS_PIPELINE_STREAM_STOPPED); 1025 vb2_streamoff(&vfh->queue, type); 1026 video->queue = NULL; 1027 1028 media_entity_enum_cleanup(&pipe->ent_enum); 1029 1030 if (video->iss->pdata->set_constraints) 1031 video->iss->pdata->set_constraints(video->iss, false); 1032 media_pipeline_stop(&video->video.entity); 1033 1034 done: 1035 mutex_unlock(&video->stream_lock); 1036 return 0; 1037 } 1038 1039 static int 1040 iss_video_enum_input(struct file *file, void *fh, struct v4l2_input *input) 1041 { 1042 if (input->index > 0) 1043 return -EINVAL; 1044 1045 strscpy(input->name, "camera", sizeof(input->name)); 1046 input->type = V4L2_INPUT_TYPE_CAMERA; 1047 1048 return 0; 1049 } 1050 1051 static int 1052 iss_video_g_input(struct file *file, void *fh, unsigned int *input) 1053 { 1054 *input = 0; 1055 1056 return 0; 1057 } 1058 1059 static int 1060 iss_video_s_input(struct file *file, void *fh, unsigned int input) 1061 { 1062 return input == 0 ? 0 : -EINVAL; 1063 } 1064 1065 static const struct v4l2_ioctl_ops iss_video_ioctl_ops = { 1066 .vidioc_querycap = iss_video_querycap, 1067 .vidioc_enum_fmt_vid_cap = iss_video_enum_format, 1068 .vidioc_g_fmt_vid_cap = iss_video_get_format, 1069 .vidioc_s_fmt_vid_cap = iss_video_set_format, 1070 .vidioc_try_fmt_vid_cap = iss_video_try_format, 1071 .vidioc_g_fmt_vid_out = iss_video_get_format, 1072 .vidioc_s_fmt_vid_out = iss_video_set_format, 1073 .vidioc_try_fmt_vid_out = iss_video_try_format, 1074 .vidioc_g_selection = iss_video_get_selection, 1075 .vidioc_s_selection = iss_video_set_selection, 1076 .vidioc_g_parm = iss_video_get_param, 1077 .vidioc_s_parm = iss_video_set_param, 1078 .vidioc_reqbufs = iss_video_reqbufs, 1079 .vidioc_querybuf = iss_video_querybuf, 1080 .vidioc_qbuf = iss_video_qbuf, 1081 .vidioc_expbuf = iss_video_expbuf, 1082 .vidioc_dqbuf = iss_video_dqbuf, 1083 .vidioc_streamon = iss_video_streamon, 1084 .vidioc_streamoff = iss_video_streamoff, 1085 .vidioc_enum_input = iss_video_enum_input, 1086 .vidioc_g_input = iss_video_g_input, 1087 .vidioc_s_input = iss_video_s_input, 1088 }; 1089 1090 /* ----------------------------------------------------------------------------- 1091 * V4L2 file operations 1092 */ 1093 1094 static int iss_video_open(struct file *file) 1095 { 1096 struct iss_video *video = video_drvdata(file); 1097 struct iss_video_fh *handle; 1098 struct vb2_queue *q; 1099 int ret = 0; 1100 1101 handle = kzalloc(sizeof(*handle), GFP_KERNEL); 1102 if (!handle) 1103 return -ENOMEM; 1104 1105 v4l2_fh_init(&handle->vfh, &video->video); 1106 v4l2_fh_add(&handle->vfh); 1107 1108 /* If this is the first user, initialise the pipeline. */ 1109 if (!omap4iss_get(video->iss)) { 1110 ret = -EBUSY; 1111 goto done; 1112 } 1113 1114 ret = v4l2_pipeline_pm_get(&video->video.entity); 1115 if (ret < 0) { 1116 omap4iss_put(video->iss); 1117 goto done; 1118 } 1119 1120 q = &handle->queue; 1121 1122 q->type = video->type; 1123 q->io_modes = VB2_MMAP | VB2_DMABUF; 1124 q->drv_priv = handle; 1125 q->ops = &iss_video_vb2ops; 1126 q->mem_ops = &vb2_dma_contig_memops; 1127 q->buf_struct_size = sizeof(struct iss_buffer); 1128 q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; 1129 q->dev = video->iss->dev; 1130 1131 ret = vb2_queue_init(q); 1132 if (ret) { 1133 omap4iss_put(video->iss); 1134 goto done; 1135 } 1136 1137 memset(&handle->format, 0, sizeof(handle->format)); 1138 handle->format.type = video->type; 1139 handle->timeperframe.denominator = 1; 1140 1141 handle->video = video; 1142 file->private_data = &handle->vfh; 1143 1144 done: 1145 if (ret < 0) { 1146 v4l2_fh_del(&handle->vfh); 1147 v4l2_fh_exit(&handle->vfh); 1148 kfree(handle); 1149 } 1150 1151 return ret; 1152 } 1153 1154 static int iss_video_release(struct file *file) 1155 { 1156 struct iss_video *video = video_drvdata(file); 1157 struct v4l2_fh *vfh = file->private_data; 1158 struct iss_video_fh *handle = to_iss_video_fh(vfh); 1159 1160 /* Disable streaming and free the buffers queue resources. */ 1161 iss_video_streamoff(file, vfh, video->type); 1162 1163 v4l2_pipeline_pm_put(&video->video.entity); 1164 1165 /* Release the videobuf2 queue */ 1166 vb2_queue_release(&handle->queue); 1167 1168 v4l2_fh_del(vfh); 1169 v4l2_fh_exit(vfh); 1170 kfree(handle); 1171 file->private_data = NULL; 1172 1173 omap4iss_put(video->iss); 1174 1175 return 0; 1176 } 1177 1178 static __poll_t iss_video_poll(struct file *file, poll_table *wait) 1179 { 1180 struct iss_video_fh *vfh = to_iss_video_fh(file->private_data); 1181 1182 return vb2_poll(&vfh->queue, file, wait); 1183 } 1184 1185 static int iss_video_mmap(struct file *file, struct vm_area_struct *vma) 1186 { 1187 struct iss_video_fh *vfh = to_iss_video_fh(file->private_data); 1188 1189 return vb2_mmap(&vfh->queue, vma); 1190 } 1191 1192 static const struct v4l2_file_operations iss_video_fops = { 1193 .owner = THIS_MODULE, 1194 .unlocked_ioctl = video_ioctl2, 1195 .open = iss_video_open, 1196 .release = iss_video_release, 1197 .poll = iss_video_poll, 1198 .mmap = iss_video_mmap, 1199 }; 1200 1201 /* ----------------------------------------------------------------------------- 1202 * ISS video core 1203 */ 1204 1205 static const struct iss_video_operations iss_video_dummy_ops = { 1206 }; 1207 1208 int omap4iss_video_init(struct iss_video *video, const char *name) 1209 { 1210 const char *direction; 1211 int ret; 1212 1213 switch (video->type) { 1214 case V4L2_BUF_TYPE_VIDEO_CAPTURE: 1215 direction = "output"; 1216 video->pad.flags = MEDIA_PAD_FL_SINK; 1217 break; 1218 case V4L2_BUF_TYPE_VIDEO_OUTPUT: 1219 direction = "input"; 1220 video->pad.flags = MEDIA_PAD_FL_SOURCE; 1221 break; 1222 1223 default: 1224 return -EINVAL; 1225 } 1226 1227 ret = media_entity_pads_init(&video->video.entity, 1, &video->pad); 1228 if (ret < 0) 1229 return ret; 1230 1231 spin_lock_init(&video->qlock); 1232 mutex_init(&video->mutex); 1233 atomic_set(&video->active, 0); 1234 1235 spin_lock_init(&video->pipe.lock); 1236 mutex_init(&video->stream_lock); 1237 1238 /* Initialize the video device. */ 1239 if (!video->ops) 1240 video->ops = &iss_video_dummy_ops; 1241 1242 video->video.fops = &iss_video_fops; 1243 snprintf(video->video.name, sizeof(video->video.name), 1244 "OMAP4 ISS %s %s", name, direction); 1245 video->video.vfl_type = VFL_TYPE_VIDEO; 1246 video->video.release = video_device_release_empty; 1247 video->video.ioctl_ops = &iss_video_ioctl_ops; 1248 video->pipe.stream_state = ISS_PIPELINE_STREAM_STOPPED; 1249 1250 video_set_drvdata(&video->video, video); 1251 1252 return 0; 1253 } 1254 1255 void omap4iss_video_cleanup(struct iss_video *video) 1256 { 1257 media_entity_cleanup(&video->video.entity); 1258 mutex_destroy(&video->stream_lock); 1259 mutex_destroy(&video->mutex); 1260 } 1261 1262 int omap4iss_video_register(struct iss_video *video, struct v4l2_device *vdev) 1263 { 1264 int ret; 1265 1266 video->video.v4l2_dev = vdev; 1267 if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) 1268 video->video.device_caps = V4L2_CAP_VIDEO_CAPTURE; 1269 else 1270 video->video.device_caps = V4L2_CAP_VIDEO_OUTPUT; 1271 video->video.device_caps |= V4L2_CAP_STREAMING; 1272 1273 ret = video_register_device(&video->video, VFL_TYPE_VIDEO, -1); 1274 if (ret < 0) 1275 dev_err(video->iss->dev, 1276 "could not register video device (%d)\n", ret); 1277 1278 return ret; 1279 } 1280 1281 void omap4iss_video_unregister(struct iss_video *video) 1282 { 1283 video_unregister_device(&video->video); 1284 } 1285