1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Driver for Renesas R-Car VIN 4 * 5 * Copyright (C) 2025 Niklas Söderlund <niklas.soderlund@ragnatech.se> 6 * Copyright (C) 2016 Renesas Electronics Corp. 7 * Copyright (C) 2011-2013 Renesas Solutions Corp. 8 * Copyright (C) 2013 Cogent Embedded, Inc., <source@cogentembedded.com> 9 * Copyright (C) 2008 Magnus Damm 10 */ 11 12 #include <linux/pm_runtime.h> 13 14 #include <media/v4l2-event.h> 15 #include <media/v4l2-ioctl.h> 16 #include <media/v4l2-mc.h> 17 #include <media/v4l2-rect.h> 18 19 #include "rcar-vin.h" 20 21 #define RVIN_DEFAULT_FORMAT V4L2_PIX_FMT_YUYV 22 #define RVIN_DEFAULT_WIDTH 800 23 #define RVIN_DEFAULT_HEIGHT 600 24 #define RVIN_DEFAULT_FIELD V4L2_FIELD_NONE 25 #define RVIN_DEFAULT_COLORSPACE V4L2_COLORSPACE_SRGB 26 27 /* ----------------------------------------------------------------------------- 28 * Format Conversions 29 */ 30 31 static const struct rvin_video_format rvin_formats[] = { 32 { 33 .fourcc = V4L2_PIX_FMT_NV12, 34 .bpp = 1, 35 }, 36 { 37 .fourcc = V4L2_PIX_FMT_NV16, 38 .bpp = 1, 39 }, 40 { 41 .fourcc = V4L2_PIX_FMT_YUYV, 42 .bpp = 2, 43 }, 44 { 45 .fourcc = V4L2_PIX_FMT_UYVY, 46 .bpp = 2, 47 }, 48 { 49 .fourcc = V4L2_PIX_FMT_RGB565, 50 .bpp = 2, 51 }, 52 { 53 .fourcc = V4L2_PIX_FMT_XRGB555, 54 .bpp = 2, 55 }, 56 { 57 .fourcc = V4L2_PIX_FMT_XBGR32, 58 .bpp = 4, 59 }, 60 { 61 .fourcc = V4L2_PIX_FMT_ARGB555, 62 .bpp = 2, 63 }, 64 { 65 .fourcc = V4L2_PIX_FMT_ABGR32, 66 .bpp = 4, 67 }, 68 { 69 .fourcc = V4L2_PIX_FMT_SBGGR8, 70 .bpp = 1, 71 }, 72 { 73 .fourcc = V4L2_PIX_FMT_SGBRG8, 74 .bpp = 1, 75 }, 76 { 77 .fourcc = V4L2_PIX_FMT_SGRBG8, 78 .bpp = 1, 79 }, 80 { 81 .fourcc = V4L2_PIX_FMT_SRGGB8, 82 .bpp = 1, 83 }, 84 { 85 .fourcc = V4L2_PIX_FMT_GREY, 86 .bpp = 1, 87 }, 88 { 89 .fourcc = V4L2_PIX_FMT_SBGGR10, 90 .bpp = 2, 91 }, 92 { 93 .fourcc = V4L2_PIX_FMT_SGBRG10, 94 .bpp = 2, 95 }, 96 { 97 .fourcc = V4L2_PIX_FMT_SGRBG10, 98 .bpp = 2, 99 }, 100 { 101 .fourcc = V4L2_PIX_FMT_SRGGB10, 102 .bpp = 2, 103 }, 104 }; 105 106 const struct rvin_video_format *rvin_format_from_pixel(struct rvin_dev *vin, 107 u32 pixelformat) 108 { 109 int i; 110 111 switch (pixelformat) { 112 case V4L2_PIX_FMT_XBGR32: 113 if (vin->info->model == RCAR_M1) 114 return NULL; 115 break; 116 case V4L2_PIX_FMT_NV12: 117 /* 118 * If NV12 is supported it's only supported on channels 0, 1, 4, 119 * 5, 8, 9, 12 and 13. 120 */ 121 if (!vin->info->nv12 || !(BIT(vin->id) & 0x3333)) 122 return NULL; 123 break; 124 case V4L2_PIX_FMT_SBGGR10: 125 case V4L2_PIX_FMT_SGBRG10: 126 case V4L2_PIX_FMT_SGRBG10: 127 case V4L2_PIX_FMT_SRGGB10: 128 if (!vin->info->raw10) 129 return NULL; 130 break; 131 default: 132 break; 133 } 134 135 for (i = 0; i < ARRAY_SIZE(rvin_formats); i++) 136 if (rvin_formats[i].fourcc == pixelformat) 137 return rvin_formats + i; 138 139 return NULL; 140 } 141 142 static u32 rvin_format_bytesperline(struct rvin_dev *vin, 143 struct v4l2_pix_format *pix) 144 { 145 const struct rvin_video_format *fmt; 146 u32 align; 147 148 fmt = rvin_format_from_pixel(vin, pix->pixelformat); 149 150 if (WARN_ON(!fmt)) 151 return -EINVAL; 152 153 switch (pix->pixelformat) { 154 case V4L2_PIX_FMT_NV12: 155 case V4L2_PIX_FMT_NV16: 156 align = 0x20; 157 break; 158 default: 159 align = 0x10; 160 break; 161 } 162 163 return ALIGN(pix->width, align) * fmt->bpp; 164 } 165 166 static u32 rvin_format_sizeimage(struct v4l2_pix_format *pix) 167 { 168 switch (pix->pixelformat) { 169 case V4L2_PIX_FMT_NV12: 170 return pix->bytesperline * pix->height * 3 / 2; 171 case V4L2_PIX_FMT_NV16: 172 return pix->bytesperline * pix->height * 2; 173 default: 174 return pix->bytesperline * pix->height; 175 } 176 } 177 178 static void rvin_format_align(struct rvin_dev *vin, struct v4l2_pix_format *pix) 179 { 180 u32 walign; 181 182 if (!rvin_format_from_pixel(vin, pix->pixelformat)) 183 pix->pixelformat = RVIN_DEFAULT_FORMAT; 184 185 switch (pix->field) { 186 case V4L2_FIELD_TOP: 187 case V4L2_FIELD_BOTTOM: 188 case V4L2_FIELD_NONE: 189 case V4L2_FIELD_INTERLACED_TB: 190 case V4L2_FIELD_INTERLACED_BT: 191 case V4L2_FIELD_INTERLACED: 192 case V4L2_FIELD_ALTERNATE: 193 break; 194 default: 195 pix->field = RVIN_DEFAULT_FIELD; 196 break; 197 } 198 199 /* Hardware limits width alignment based on format. */ 200 switch (pix->pixelformat) { 201 /* Multiple of 32 (2^5) for NV12/16. */ 202 case V4L2_PIX_FMT_NV12: 203 case V4L2_PIX_FMT_NV16: 204 walign = 5; 205 break; 206 /* Multiple of 2 (2^1) for YUV. */ 207 case V4L2_PIX_FMT_YUYV: 208 case V4L2_PIX_FMT_UYVY: 209 walign = 1; 210 break; 211 /* No multiple for RGB. */ 212 default: 213 walign = 0; 214 break; 215 } 216 217 /* Limit to VIN capabilities */ 218 v4l_bound_align_image(&pix->width, 5, vin->info->max_width, walign, 219 &pix->height, 2, vin->info->max_height, 0, 0); 220 221 pix->bytesperline = rvin_format_bytesperline(vin, pix); 222 pix->sizeimage = rvin_format_sizeimage(pix); 223 224 vin_dbg(vin, "Format %ux%u bpl: %u size: %u\n", 225 pix->width, pix->height, pix->bytesperline, pix->sizeimage); 226 } 227 228 /* ----------------------------------------------------------------------------- 229 * V4L2 230 */ 231 232 static int rvin_querycap(struct file *file, void *priv, 233 struct v4l2_capability *cap) 234 { 235 strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver)); 236 strscpy(cap->card, "R_Car_VIN", sizeof(cap->card)); 237 return 0; 238 } 239 240 static int rvin_g_fmt_vid_cap(struct file *file, void *priv, 241 struct v4l2_format *f) 242 { 243 struct rvin_dev *vin = video_drvdata(file); 244 245 f->fmt.pix = vin->format; 246 247 return 0; 248 } 249 250 static int rvin_enum_fmt_vid_cap(struct file *file, void *priv, 251 struct v4l2_fmtdesc *f) 252 { 253 struct rvin_dev *vin = video_drvdata(file); 254 unsigned int i; 255 int matched; 256 257 /* 258 * If mbus_code is set only enumerate supported pixel formats for that 259 * bus code. Converting from YCbCr to RGB and RGB to YCbCr is possible 260 * with VIN, so all supported YCbCr and RGB media bus codes can produce 261 * all of the related pixel formats. If mbus_code is not set enumerate 262 * all possible pixelformats. 263 * 264 * TODO: Once raw MEDIA_BUS_FMT_SRGGB12_1X12 format is added to the 265 * driver this needs to be extended so raw media bus code only result in 266 * raw pixel format. 267 */ 268 switch (f->mbus_code) { 269 case 0: 270 case MEDIA_BUS_FMT_YUYV8_1X16: 271 case MEDIA_BUS_FMT_UYVY8_1X16: 272 case MEDIA_BUS_FMT_UYVY8_2X8: 273 case MEDIA_BUS_FMT_UYVY10_2X10: 274 case MEDIA_BUS_FMT_RGB888_1X24: 275 break; 276 case MEDIA_BUS_FMT_SBGGR8_1X8: 277 if (f->index) 278 return -EINVAL; 279 f->pixelformat = V4L2_PIX_FMT_SBGGR8; 280 return 0; 281 case MEDIA_BUS_FMT_SGBRG8_1X8: 282 if (f->index) 283 return -EINVAL; 284 f->pixelformat = V4L2_PIX_FMT_SGBRG8; 285 return 0; 286 case MEDIA_BUS_FMT_SGRBG8_1X8: 287 if (f->index) 288 return -EINVAL; 289 f->pixelformat = V4L2_PIX_FMT_SGRBG8; 290 return 0; 291 case MEDIA_BUS_FMT_SRGGB8_1X8: 292 if (f->index) 293 return -EINVAL; 294 f->pixelformat = V4L2_PIX_FMT_SRGGB8; 295 return 0; 296 case MEDIA_BUS_FMT_SBGGR10_1X10: 297 if (f->index) 298 return -EINVAL; 299 f->pixelformat = V4L2_PIX_FMT_SBGGR10; 300 return 0; 301 case MEDIA_BUS_FMT_SGBRG10_1X10: 302 if (f->index) 303 return -EINVAL; 304 f->pixelformat = V4L2_PIX_FMT_SGBRG10; 305 return 0; 306 case MEDIA_BUS_FMT_SGRBG10_1X10: 307 if (f->index) 308 return -EINVAL; 309 f->pixelformat = V4L2_PIX_FMT_SGRBG10; 310 return 0; 311 case MEDIA_BUS_FMT_SRGGB10_1X10: 312 if (f->index) 313 return -EINVAL; 314 f->pixelformat = V4L2_PIX_FMT_SRGGB10; 315 return 0; 316 default: 317 return -EINVAL; 318 } 319 320 matched = -1; 321 for (i = 0; i < ARRAY_SIZE(rvin_formats); i++) { 322 if (rvin_format_from_pixel(vin, rvin_formats[i].fourcc)) 323 matched++; 324 325 if (matched == f->index) { 326 f->pixelformat = rvin_formats[i].fourcc; 327 return 0; 328 } 329 } 330 331 return -EINVAL; 332 } 333 334 static int rvin_remote_rectangle(struct rvin_dev *vin, struct v4l2_rect *rect) 335 { 336 struct media_pad *pad = media_pad_remote_pad_first(&vin->pad); 337 struct v4l2_subdev_format fmt = { 338 .which = V4L2_SUBDEV_FORMAT_ACTIVE, 339 }; 340 struct v4l2_subdev *sd; 341 unsigned int index; 342 int ret; 343 344 if (!pad) 345 return -EINVAL; 346 347 sd = media_entity_to_v4l2_subdev(pad->entity); 348 index = pad->index; 349 350 fmt.pad = index; 351 ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt); 352 if (ret) 353 return ret; 354 355 rect->left = rect->top = 0; 356 rect->width = fmt.format.width; 357 rect->height = fmt.format.height; 358 359 if (fmt.format.field == V4L2_FIELD_ALTERNATE) { 360 switch (vin->format.field) { 361 case V4L2_FIELD_INTERLACED_TB: 362 case V4L2_FIELD_INTERLACED_BT: 363 case V4L2_FIELD_INTERLACED: 364 rect->height *= 2; 365 break; 366 } 367 } 368 369 return 0; 370 } 371 372 static int rvin_g_selection(struct file *file, void *fh, 373 struct v4l2_selection *s) 374 { 375 struct rvin_dev *vin = video_drvdata(file); 376 int ret; 377 378 if (!vin->scaler) 379 return -ENOIOCTLCMD; 380 381 if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 382 return -EINVAL; 383 384 switch (s->target) { 385 case V4L2_SEL_TGT_CROP_BOUNDS: 386 case V4L2_SEL_TGT_CROP_DEFAULT: 387 ret = rvin_remote_rectangle(vin, &s->r); 388 if (ret) 389 return ret; 390 391 break; 392 case V4L2_SEL_TGT_CROP: 393 s->r = vin->crop; 394 break; 395 case V4L2_SEL_TGT_COMPOSE_BOUNDS: 396 case V4L2_SEL_TGT_COMPOSE_DEFAULT: 397 s->r.left = s->r.top = 0; 398 s->r.width = vin->format.width; 399 s->r.height = vin->format.height; 400 break; 401 case V4L2_SEL_TGT_COMPOSE: 402 s->r = vin->compose; 403 break; 404 default: 405 return -EINVAL; 406 } 407 408 return 0; 409 } 410 411 static int rvin_s_selection(struct file *file, void *fh, 412 struct v4l2_selection *s) 413 { 414 struct rvin_dev *vin = video_drvdata(file); 415 const struct rvin_video_format *fmt; 416 struct v4l2_rect r = s->r; 417 struct v4l2_rect max_rect; 418 struct v4l2_rect min_rect = { 419 .width = 6, 420 .height = 2, 421 }; 422 int ret; 423 424 if (!vin->scaler) 425 return -ENOIOCTLCMD; 426 427 if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 428 return -EINVAL; 429 430 v4l2_rect_set_min_size(&r, &min_rect); 431 432 switch (s->target) { 433 case V4L2_SEL_TGT_CROP: 434 /* Can't crop outside of source input */ 435 ret = rvin_remote_rectangle(vin, &max_rect); 436 if (ret) 437 return ret; 438 439 v4l2_rect_map_inside(&r, &max_rect); 440 441 v4l_bound_align_image(&r.width, 6, max_rect.width, 0, 442 &r.height, 2, max_rect.height, 0, 0); 443 444 r.top = clamp_t(s32, r.top, 0, max_rect.height - r.height); 445 r.left = clamp_t(s32, r.left, 0, max_rect.width - r.width); 446 447 vin->crop = s->r = r; 448 449 vin_dbg(vin, "Cropped (%d,%d)/%ux%u of %dx%d\n", 450 r.left, r.top, r.width, r.height, 451 max_rect.width, max_rect.height); 452 break; 453 case V4L2_SEL_TGT_COMPOSE: 454 /* Make sure compose rect fits inside output format */ 455 max_rect.top = max_rect.left = 0; 456 max_rect.width = vin->format.width; 457 max_rect.height = vin->format.height; 458 v4l2_rect_map_inside(&r, &max_rect); 459 460 /* 461 * Composing is done by adding a offset to the buffer address, 462 * the HW wants this address to be aligned to HW_BUFFER_MASK. 463 * Make sure the top and left values meets this requirement. 464 */ 465 while ((r.top * vin->format.bytesperline) & HW_BUFFER_MASK) 466 r.top--; 467 468 fmt = rvin_format_from_pixel(vin, vin->format.pixelformat); 469 while ((r.left * fmt->bpp) & HW_BUFFER_MASK) 470 r.left--; 471 472 vin->compose = s->r = r; 473 474 vin_dbg(vin, "Compose (%d,%d)/%ux%u in %dx%d\n", 475 r.left, r.top, r.width, r.height, 476 vin->format.width, vin->format.height); 477 break; 478 default: 479 return -EINVAL; 480 } 481 482 /* HW supports modifying configuration while running */ 483 rvin_crop_scale_comp(vin); 484 485 return 0; 486 } 487 488 static int rvin_subscribe_event(struct v4l2_fh *fh, 489 const struct v4l2_event_subscription *sub) 490 { 491 switch (sub->type) { 492 case V4L2_EVENT_FRAME_SYNC: 493 return v4l2_event_subscribe(fh, sub, 2, NULL); 494 case V4L2_EVENT_SOURCE_CHANGE: 495 return v4l2_event_subscribe(fh, sub, 4, NULL); 496 } 497 return v4l2_ctrl_subscribe_event(fh, sub); 498 } 499 500 static void rvin_mc_try_format(struct rvin_dev *vin, 501 struct v4l2_pix_format *pix) 502 { 503 /* 504 * The V4L2 specification clearly documents the colorspace fields 505 * as being set by drivers for capture devices. Using the values 506 * supplied by userspace thus wouldn't comply with the API. Until 507 * the API is updated force fixed values. 508 */ 509 pix->colorspace = RVIN_DEFAULT_COLORSPACE; 510 pix->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(pix->colorspace); 511 pix->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(pix->colorspace); 512 pix->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true, pix->colorspace, 513 pix->ycbcr_enc); 514 515 rvin_format_align(vin, pix); 516 } 517 518 static int rvin_mc_try_fmt_vid_cap(struct file *file, void *priv, 519 struct v4l2_format *f) 520 { 521 struct rvin_dev *vin = video_drvdata(file); 522 523 rvin_mc_try_format(vin, &f->fmt.pix); 524 525 return 0; 526 } 527 528 static int rvin_mc_s_fmt_vid_cap(struct file *file, void *priv, 529 struct v4l2_format *f) 530 { 531 struct rvin_dev *vin = video_drvdata(file); 532 533 if (vb2_is_busy(&vin->queue)) 534 return -EBUSY; 535 536 rvin_mc_try_format(vin, &f->fmt.pix); 537 538 vin->format = f->fmt.pix; 539 540 vin->crop.top = 0; 541 vin->crop.left = 0; 542 vin->crop.width = vin->format.width; 543 vin->crop.height = vin->format.height; 544 vin->compose = vin->crop; 545 546 return 0; 547 } 548 549 static const struct v4l2_ioctl_ops rvin_mc_ioctl_ops = { 550 .vidioc_querycap = rvin_querycap, 551 .vidioc_try_fmt_vid_cap = rvin_mc_try_fmt_vid_cap, 552 .vidioc_g_fmt_vid_cap = rvin_g_fmt_vid_cap, 553 .vidioc_s_fmt_vid_cap = rvin_mc_s_fmt_vid_cap, 554 .vidioc_enum_fmt_vid_cap = rvin_enum_fmt_vid_cap, 555 556 .vidioc_g_selection = rvin_g_selection, 557 .vidioc_s_selection = rvin_s_selection, 558 559 .vidioc_reqbufs = vb2_ioctl_reqbufs, 560 .vidioc_create_bufs = vb2_ioctl_create_bufs, 561 .vidioc_querybuf = vb2_ioctl_querybuf, 562 .vidioc_qbuf = vb2_ioctl_qbuf, 563 .vidioc_dqbuf = vb2_ioctl_dqbuf, 564 .vidioc_expbuf = vb2_ioctl_expbuf, 565 .vidioc_prepare_buf = vb2_ioctl_prepare_buf, 566 .vidioc_streamon = vb2_ioctl_streamon, 567 .vidioc_streamoff = vb2_ioctl_streamoff, 568 569 .vidioc_log_status = v4l2_ctrl_log_status, 570 .vidioc_subscribe_event = rvin_subscribe_event, 571 .vidioc_unsubscribe_event = v4l2_event_unsubscribe, 572 }; 573 574 /* ----------------------------------------------------------------------------- 575 * File Operations 576 */ 577 578 static int rvin_open(struct file *file) 579 { 580 struct rvin_dev *vin = video_drvdata(file); 581 int ret; 582 583 ret = pm_runtime_resume_and_get(vin->dev); 584 if (ret < 0) 585 return ret; 586 587 ret = mutex_lock_interruptible(&vin->lock); 588 if (ret) 589 goto err_pm; 590 591 file->private_data = vin; 592 593 ret = v4l2_fh_open(file); 594 if (ret) 595 goto err_unlock; 596 597 ret = v4l2_pipeline_pm_get(&vin->vdev.entity); 598 if (ret < 0) 599 goto err_open; 600 601 ret = v4l2_ctrl_handler_setup(&vin->ctrl_handler); 602 if (ret) 603 goto err_power; 604 605 mutex_unlock(&vin->lock); 606 607 return 0; 608 err_power: 609 v4l2_pipeline_pm_put(&vin->vdev.entity); 610 err_open: 611 v4l2_fh_release(file); 612 err_unlock: 613 mutex_unlock(&vin->lock); 614 err_pm: 615 pm_runtime_put(vin->dev); 616 617 return ret; 618 } 619 620 static int rvin_release(struct file *file) 621 { 622 struct rvin_dev *vin = video_drvdata(file); 623 int ret; 624 625 mutex_lock(&vin->lock); 626 627 /* the release helper will cleanup any on-going streaming */ 628 ret = _vb2_fop_release(file, NULL); 629 630 v4l2_pipeline_pm_put(&vin->vdev.entity); 631 632 mutex_unlock(&vin->lock); 633 634 pm_runtime_put(vin->dev); 635 636 return ret; 637 } 638 639 static const struct v4l2_file_operations rvin_fops = { 640 .owner = THIS_MODULE, 641 .unlocked_ioctl = video_ioctl2, 642 .open = rvin_open, 643 .release = rvin_release, 644 .poll = vb2_fop_poll, 645 .mmap = vb2_fop_mmap, 646 .read = vb2_fop_read, 647 }; 648 649 void rvin_v4l2_unregister(struct rvin_dev *vin) 650 { 651 if (!video_is_registered(&vin->vdev)) 652 return; 653 654 v4l2_info(&vin->v4l2_dev, "Removing %s\n", 655 video_device_node_name(&vin->vdev)); 656 657 /* Checks internally if vdev have been init or not */ 658 video_unregister_device(&vin->vdev); 659 } 660 661 static void rvin_notify(struct v4l2_subdev *sd, 662 unsigned int notification, void *arg) 663 { 664 struct v4l2_subdev *remote; 665 struct rvin_group *group; 666 struct media_pad *pad; 667 struct rvin_dev *vin = 668 container_of(sd->v4l2_dev, struct rvin_dev, v4l2_dev); 669 unsigned int i; 670 671 group = vin->group; 672 673 for (i = 0; i < RCAR_VIN_NUM; i++) { 674 vin = group->vin[i]; 675 if (!vin) 676 continue; 677 678 pad = media_pad_remote_pad_first(&vin->pad); 679 if (!pad) 680 continue; 681 682 remote = media_entity_to_v4l2_subdev(pad->entity); 683 if (remote != sd) 684 continue; 685 686 switch (notification) { 687 case V4L2_DEVICE_NOTIFY_EVENT: 688 v4l2_event_queue(&vin->vdev, arg); 689 break; 690 default: 691 break; 692 } 693 } 694 } 695 696 int rvin_v4l2_register(struct rvin_dev *vin) 697 { 698 struct video_device *vdev = &vin->vdev; 699 int ret; 700 701 vin->v4l2_dev.notify = rvin_notify; 702 703 /* video node */ 704 vdev->v4l2_dev = &vin->v4l2_dev; 705 vdev->queue = &vin->queue; 706 snprintf(vdev->name, sizeof(vdev->name), "VIN%u output", vin->id); 707 vdev->release = video_device_release_empty; 708 vdev->lock = &vin->lock; 709 vdev->fops = &rvin_fops; 710 vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | 711 V4L2_CAP_READWRITE | V4L2_CAP_IO_MC; 712 vdev->ioctl_ops = &rvin_mc_ioctl_ops; 713 714 /* Set a default format */ 715 vin->format.pixelformat = RVIN_DEFAULT_FORMAT; 716 vin->format.width = RVIN_DEFAULT_WIDTH; 717 vin->format.height = RVIN_DEFAULT_HEIGHT; 718 vin->format.field = RVIN_DEFAULT_FIELD; 719 vin->format.colorspace = RVIN_DEFAULT_COLORSPACE; 720 721 rvin_format_align(vin, &vin->format); 722 723 ret = video_register_device(&vin->vdev, VFL_TYPE_VIDEO, -1); 724 if (ret) { 725 vin_err(vin, "Failed to register video device\n"); 726 return ret; 727 } 728 729 video_set_drvdata(&vin->vdev, vin); 730 731 v4l2_info(&vin->v4l2_dev, "Device registered as %s\n", 732 video_device_node_name(&vin->vdev)); 733 734 return ret; 735 } 736