162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Driver for Renesas R-Car VIN 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2016 Renesas Electronics Corp. 662306a36Sopenharmony_ci * Copyright (C) 2011-2013 Renesas Solutions Corp. 762306a36Sopenharmony_ci * Copyright (C) 2013 Cogent Embedded, Inc., <source@cogentembedded.com> 862306a36Sopenharmony_ci * Copyright (C) 2008 Magnus Damm 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Based on the soc-camera rcar_vin driver 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/pm_runtime.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <media/v4l2-event.h> 1662306a36Sopenharmony_ci#include <media/v4l2-ioctl.h> 1762306a36Sopenharmony_ci#include <media/v4l2-mc.h> 1862306a36Sopenharmony_ci#include <media/v4l2-rect.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include "rcar-vin.h" 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#define RVIN_DEFAULT_FORMAT V4L2_PIX_FMT_YUYV 2362306a36Sopenharmony_ci#define RVIN_DEFAULT_WIDTH 800 2462306a36Sopenharmony_ci#define RVIN_DEFAULT_HEIGHT 600 2562306a36Sopenharmony_ci#define RVIN_DEFAULT_FIELD V4L2_FIELD_NONE 2662306a36Sopenharmony_ci#define RVIN_DEFAULT_COLORSPACE V4L2_COLORSPACE_SRGB 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/* ----------------------------------------------------------------------------- 2962306a36Sopenharmony_ci * Format Conversions 3062306a36Sopenharmony_ci */ 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistatic const struct rvin_video_format rvin_formats[] = { 3362306a36Sopenharmony_ci { 3462306a36Sopenharmony_ci .fourcc = V4L2_PIX_FMT_NV12, 3562306a36Sopenharmony_ci .bpp = 1, 3662306a36Sopenharmony_ci }, 3762306a36Sopenharmony_ci { 3862306a36Sopenharmony_ci .fourcc = V4L2_PIX_FMT_NV16, 3962306a36Sopenharmony_ci .bpp = 1, 4062306a36Sopenharmony_ci }, 4162306a36Sopenharmony_ci { 4262306a36Sopenharmony_ci .fourcc = V4L2_PIX_FMT_YUYV, 4362306a36Sopenharmony_ci .bpp = 2, 4462306a36Sopenharmony_ci }, 4562306a36Sopenharmony_ci { 4662306a36Sopenharmony_ci .fourcc = V4L2_PIX_FMT_UYVY, 4762306a36Sopenharmony_ci .bpp = 2, 4862306a36Sopenharmony_ci }, 4962306a36Sopenharmony_ci { 5062306a36Sopenharmony_ci .fourcc = V4L2_PIX_FMT_RGB565, 5162306a36Sopenharmony_ci .bpp = 2, 5262306a36Sopenharmony_ci }, 5362306a36Sopenharmony_ci { 5462306a36Sopenharmony_ci .fourcc = V4L2_PIX_FMT_XRGB555, 5562306a36Sopenharmony_ci .bpp = 2, 5662306a36Sopenharmony_ci }, 5762306a36Sopenharmony_ci { 5862306a36Sopenharmony_ci .fourcc = V4L2_PIX_FMT_XBGR32, 5962306a36Sopenharmony_ci .bpp = 4, 6062306a36Sopenharmony_ci }, 6162306a36Sopenharmony_ci { 6262306a36Sopenharmony_ci .fourcc = V4L2_PIX_FMT_ARGB555, 6362306a36Sopenharmony_ci .bpp = 2, 6462306a36Sopenharmony_ci }, 6562306a36Sopenharmony_ci { 6662306a36Sopenharmony_ci .fourcc = V4L2_PIX_FMT_ABGR32, 6762306a36Sopenharmony_ci .bpp = 4, 6862306a36Sopenharmony_ci }, 6962306a36Sopenharmony_ci { 7062306a36Sopenharmony_ci .fourcc = V4L2_PIX_FMT_SBGGR8, 7162306a36Sopenharmony_ci .bpp = 1, 7262306a36Sopenharmony_ci }, 7362306a36Sopenharmony_ci { 7462306a36Sopenharmony_ci .fourcc = V4L2_PIX_FMT_SGBRG8, 7562306a36Sopenharmony_ci .bpp = 1, 7662306a36Sopenharmony_ci }, 7762306a36Sopenharmony_ci { 7862306a36Sopenharmony_ci .fourcc = V4L2_PIX_FMT_SGRBG8, 7962306a36Sopenharmony_ci .bpp = 1, 8062306a36Sopenharmony_ci }, 8162306a36Sopenharmony_ci { 8262306a36Sopenharmony_ci .fourcc = V4L2_PIX_FMT_SRGGB8, 8362306a36Sopenharmony_ci .bpp = 1, 8462306a36Sopenharmony_ci }, 8562306a36Sopenharmony_ci { 8662306a36Sopenharmony_ci .fourcc = V4L2_PIX_FMT_GREY, 8762306a36Sopenharmony_ci .bpp = 1, 8862306a36Sopenharmony_ci }, 8962306a36Sopenharmony_ci}; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ciconst struct rvin_video_format *rvin_format_from_pixel(struct rvin_dev *vin, 9262306a36Sopenharmony_ci u32 pixelformat) 9362306a36Sopenharmony_ci{ 9462306a36Sopenharmony_ci int i; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci switch (pixelformat) { 9762306a36Sopenharmony_ci case V4L2_PIX_FMT_XBGR32: 9862306a36Sopenharmony_ci if (vin->info->model == RCAR_M1) 9962306a36Sopenharmony_ci return NULL; 10062306a36Sopenharmony_ci break; 10162306a36Sopenharmony_ci case V4L2_PIX_FMT_NV12: 10262306a36Sopenharmony_ci /* 10362306a36Sopenharmony_ci * If NV12 is supported it's only supported on channels 0, 1, 4, 10462306a36Sopenharmony_ci * 5, 8, 9, 12 and 13. 10562306a36Sopenharmony_ci */ 10662306a36Sopenharmony_ci if (!vin->info->nv12 || !(BIT(vin->id) & 0x3333)) 10762306a36Sopenharmony_ci return NULL; 10862306a36Sopenharmony_ci break; 10962306a36Sopenharmony_ci default: 11062306a36Sopenharmony_ci break; 11162306a36Sopenharmony_ci } 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(rvin_formats); i++) 11462306a36Sopenharmony_ci if (rvin_formats[i].fourcc == pixelformat) 11562306a36Sopenharmony_ci return rvin_formats + i; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci return NULL; 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cistatic u32 rvin_format_bytesperline(struct rvin_dev *vin, 12162306a36Sopenharmony_ci struct v4l2_pix_format *pix) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci const struct rvin_video_format *fmt; 12462306a36Sopenharmony_ci u32 align; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci fmt = rvin_format_from_pixel(vin, pix->pixelformat); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci if (WARN_ON(!fmt)) 12962306a36Sopenharmony_ci return -EINVAL; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci switch (pix->pixelformat) { 13262306a36Sopenharmony_ci case V4L2_PIX_FMT_NV12: 13362306a36Sopenharmony_ci case V4L2_PIX_FMT_NV16: 13462306a36Sopenharmony_ci align = 0x20; 13562306a36Sopenharmony_ci break; 13662306a36Sopenharmony_ci default: 13762306a36Sopenharmony_ci align = 0x10; 13862306a36Sopenharmony_ci break; 13962306a36Sopenharmony_ci } 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci if (V4L2_FIELD_IS_SEQUENTIAL(pix->field)) 14262306a36Sopenharmony_ci align = 0x80; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci return ALIGN(pix->width, align) * fmt->bpp; 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_cistatic u32 rvin_format_sizeimage(struct v4l2_pix_format *pix) 14862306a36Sopenharmony_ci{ 14962306a36Sopenharmony_ci switch (pix->pixelformat) { 15062306a36Sopenharmony_ci case V4L2_PIX_FMT_NV12: 15162306a36Sopenharmony_ci return pix->bytesperline * pix->height * 3 / 2; 15262306a36Sopenharmony_ci case V4L2_PIX_FMT_NV16: 15362306a36Sopenharmony_ci return pix->bytesperline * pix->height * 2; 15462306a36Sopenharmony_ci default: 15562306a36Sopenharmony_ci return pix->bytesperline * pix->height; 15662306a36Sopenharmony_ci } 15762306a36Sopenharmony_ci} 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_cistatic void rvin_format_align(struct rvin_dev *vin, struct v4l2_pix_format *pix) 16062306a36Sopenharmony_ci{ 16162306a36Sopenharmony_ci u32 walign; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci if (!rvin_format_from_pixel(vin, pix->pixelformat)) 16462306a36Sopenharmony_ci pix->pixelformat = RVIN_DEFAULT_FORMAT; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci switch (pix->field) { 16762306a36Sopenharmony_ci case V4L2_FIELD_TOP: 16862306a36Sopenharmony_ci case V4L2_FIELD_BOTTOM: 16962306a36Sopenharmony_ci case V4L2_FIELD_NONE: 17062306a36Sopenharmony_ci case V4L2_FIELD_INTERLACED_TB: 17162306a36Sopenharmony_ci case V4L2_FIELD_INTERLACED_BT: 17262306a36Sopenharmony_ci case V4L2_FIELD_INTERLACED: 17362306a36Sopenharmony_ci case V4L2_FIELD_ALTERNATE: 17462306a36Sopenharmony_ci case V4L2_FIELD_SEQ_TB: 17562306a36Sopenharmony_ci case V4L2_FIELD_SEQ_BT: 17662306a36Sopenharmony_ci break; 17762306a36Sopenharmony_ci default: 17862306a36Sopenharmony_ci pix->field = RVIN_DEFAULT_FIELD; 17962306a36Sopenharmony_ci break; 18062306a36Sopenharmony_ci } 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci /* Hardware limits width alignment based on format. */ 18362306a36Sopenharmony_ci switch (pix->pixelformat) { 18462306a36Sopenharmony_ci /* Multiple of 32 (2^5) for NV12/16. */ 18562306a36Sopenharmony_ci case V4L2_PIX_FMT_NV12: 18662306a36Sopenharmony_ci case V4L2_PIX_FMT_NV16: 18762306a36Sopenharmony_ci walign = 5; 18862306a36Sopenharmony_ci break; 18962306a36Sopenharmony_ci /* Multiple of 2 (2^1) for YUV. */ 19062306a36Sopenharmony_ci case V4L2_PIX_FMT_YUYV: 19162306a36Sopenharmony_ci case V4L2_PIX_FMT_UYVY: 19262306a36Sopenharmony_ci walign = 1; 19362306a36Sopenharmony_ci break; 19462306a36Sopenharmony_ci /* No multiple for RGB. */ 19562306a36Sopenharmony_ci default: 19662306a36Sopenharmony_ci walign = 0; 19762306a36Sopenharmony_ci break; 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci /* Limit to VIN capabilities */ 20162306a36Sopenharmony_ci v4l_bound_align_image(&pix->width, 5, vin->info->max_width, walign, 20262306a36Sopenharmony_ci &pix->height, 2, vin->info->max_height, 0, 0); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci pix->bytesperline = rvin_format_bytesperline(vin, pix); 20562306a36Sopenharmony_ci pix->sizeimage = rvin_format_sizeimage(pix); 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci vin_dbg(vin, "Format %ux%u bpl: %u size: %u\n", 20862306a36Sopenharmony_ci pix->width, pix->height, pix->bytesperline, pix->sizeimage); 20962306a36Sopenharmony_ci} 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci/* ----------------------------------------------------------------------------- 21262306a36Sopenharmony_ci * V4L2 21362306a36Sopenharmony_ci */ 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_cistatic int rvin_reset_format(struct rvin_dev *vin) 21662306a36Sopenharmony_ci{ 21762306a36Sopenharmony_ci struct v4l2_subdev_format fmt = { 21862306a36Sopenharmony_ci .which = V4L2_SUBDEV_FORMAT_ACTIVE, 21962306a36Sopenharmony_ci .pad = vin->parallel.source_pad, 22062306a36Sopenharmony_ci }; 22162306a36Sopenharmony_ci int ret; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci ret = v4l2_subdev_call(vin_to_source(vin), pad, get_fmt, NULL, &fmt); 22462306a36Sopenharmony_ci if (ret) 22562306a36Sopenharmony_ci return ret; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci v4l2_fill_pix_format(&vin->format, &fmt.format); 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci vin->crop.top = 0; 23062306a36Sopenharmony_ci vin->crop.left = 0; 23162306a36Sopenharmony_ci vin->crop.width = vin->format.width; 23262306a36Sopenharmony_ci vin->crop.height = vin->format.height; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci /* Make use of the hardware interlacer by default. */ 23562306a36Sopenharmony_ci if (vin->format.field == V4L2_FIELD_ALTERNATE) { 23662306a36Sopenharmony_ci vin->format.field = V4L2_FIELD_INTERLACED; 23762306a36Sopenharmony_ci vin->format.height *= 2; 23862306a36Sopenharmony_ci } 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci rvin_format_align(vin, &vin->format); 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci vin->compose.top = 0; 24362306a36Sopenharmony_ci vin->compose.left = 0; 24462306a36Sopenharmony_ci vin->compose.width = vin->format.width; 24562306a36Sopenharmony_ci vin->compose.height = vin->format.height; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci return 0; 24862306a36Sopenharmony_ci} 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_cistatic int rvin_try_format(struct rvin_dev *vin, u32 which, 25162306a36Sopenharmony_ci struct v4l2_pix_format *pix, 25262306a36Sopenharmony_ci struct v4l2_rect *src_rect) 25362306a36Sopenharmony_ci{ 25462306a36Sopenharmony_ci struct v4l2_subdev *sd = vin_to_source(vin); 25562306a36Sopenharmony_ci struct v4l2_subdev_state *sd_state; 25662306a36Sopenharmony_ci static struct lock_class_key key; 25762306a36Sopenharmony_ci struct v4l2_subdev_format format = { 25862306a36Sopenharmony_ci .which = which, 25962306a36Sopenharmony_ci .pad = vin->parallel.source_pad, 26062306a36Sopenharmony_ci }; 26162306a36Sopenharmony_ci enum v4l2_field field; 26262306a36Sopenharmony_ci u32 width, height; 26362306a36Sopenharmony_ci int ret; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci /* 26662306a36Sopenharmony_ci * FIXME: Drop this call, drivers are not supposed to use 26762306a36Sopenharmony_ci * __v4l2_subdev_state_alloc(). 26862306a36Sopenharmony_ci */ 26962306a36Sopenharmony_ci sd_state = __v4l2_subdev_state_alloc(sd, "rvin:state->lock", &key); 27062306a36Sopenharmony_ci if (IS_ERR(sd_state)) 27162306a36Sopenharmony_ci return PTR_ERR(sd_state); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci if (!rvin_format_from_pixel(vin, pix->pixelformat)) 27462306a36Sopenharmony_ci pix->pixelformat = RVIN_DEFAULT_FORMAT; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci v4l2_fill_mbus_format(&format.format, pix, vin->mbus_code); 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci /* Allow the video device to override field and to scale */ 27962306a36Sopenharmony_ci field = pix->field; 28062306a36Sopenharmony_ci width = pix->width; 28162306a36Sopenharmony_ci height = pix->height; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci ret = v4l2_subdev_call(sd, pad, set_fmt, sd_state, &format); 28462306a36Sopenharmony_ci if (ret < 0 && ret != -ENOIOCTLCMD) 28562306a36Sopenharmony_ci goto done; 28662306a36Sopenharmony_ci ret = 0; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci v4l2_fill_pix_format(pix, &format.format); 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci if (src_rect) { 29162306a36Sopenharmony_ci src_rect->top = 0; 29262306a36Sopenharmony_ci src_rect->left = 0; 29362306a36Sopenharmony_ci src_rect->width = pix->width; 29462306a36Sopenharmony_ci src_rect->height = pix->height; 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci if (field != V4L2_FIELD_ANY) 29862306a36Sopenharmony_ci pix->field = field; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci pix->width = width; 30162306a36Sopenharmony_ci pix->height = height; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci rvin_format_align(vin, pix); 30462306a36Sopenharmony_cidone: 30562306a36Sopenharmony_ci __v4l2_subdev_state_free(sd_state); 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci return ret; 30862306a36Sopenharmony_ci} 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_cistatic int rvin_querycap(struct file *file, void *priv, 31162306a36Sopenharmony_ci struct v4l2_capability *cap) 31262306a36Sopenharmony_ci{ 31362306a36Sopenharmony_ci strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver)); 31462306a36Sopenharmony_ci strscpy(cap->card, "R_Car_VIN", sizeof(cap->card)); 31562306a36Sopenharmony_ci return 0; 31662306a36Sopenharmony_ci} 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_cistatic int rvin_try_fmt_vid_cap(struct file *file, void *priv, 31962306a36Sopenharmony_ci struct v4l2_format *f) 32062306a36Sopenharmony_ci{ 32162306a36Sopenharmony_ci struct rvin_dev *vin = video_drvdata(file); 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci return rvin_try_format(vin, V4L2_SUBDEV_FORMAT_TRY, &f->fmt.pix, NULL); 32462306a36Sopenharmony_ci} 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_cistatic int rvin_s_fmt_vid_cap(struct file *file, void *priv, 32762306a36Sopenharmony_ci struct v4l2_format *f) 32862306a36Sopenharmony_ci{ 32962306a36Sopenharmony_ci struct rvin_dev *vin = video_drvdata(file); 33062306a36Sopenharmony_ci struct v4l2_rect fmt_rect, src_rect; 33162306a36Sopenharmony_ci int ret; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci if (vb2_is_busy(&vin->queue)) 33462306a36Sopenharmony_ci return -EBUSY; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci ret = rvin_try_format(vin, V4L2_SUBDEV_FORMAT_ACTIVE, &f->fmt.pix, 33762306a36Sopenharmony_ci &src_rect); 33862306a36Sopenharmony_ci if (ret) 33962306a36Sopenharmony_ci return ret; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci vin->format = f->fmt.pix; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci fmt_rect.top = 0; 34462306a36Sopenharmony_ci fmt_rect.left = 0; 34562306a36Sopenharmony_ci fmt_rect.width = vin->format.width; 34662306a36Sopenharmony_ci fmt_rect.height = vin->format.height; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci v4l2_rect_map_inside(&vin->crop, &src_rect); 34962306a36Sopenharmony_ci v4l2_rect_map_inside(&vin->compose, &fmt_rect); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci return 0; 35262306a36Sopenharmony_ci} 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_cistatic int rvin_g_fmt_vid_cap(struct file *file, void *priv, 35562306a36Sopenharmony_ci struct v4l2_format *f) 35662306a36Sopenharmony_ci{ 35762306a36Sopenharmony_ci struct rvin_dev *vin = video_drvdata(file); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci f->fmt.pix = vin->format; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci return 0; 36262306a36Sopenharmony_ci} 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_cistatic int rvin_enum_fmt_vid_cap(struct file *file, void *priv, 36562306a36Sopenharmony_ci struct v4l2_fmtdesc *f) 36662306a36Sopenharmony_ci{ 36762306a36Sopenharmony_ci struct rvin_dev *vin = video_drvdata(file); 36862306a36Sopenharmony_ci unsigned int i; 36962306a36Sopenharmony_ci int matched; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci /* 37262306a36Sopenharmony_ci * If mbus_code is set only enumerate supported pixel formats for that 37362306a36Sopenharmony_ci * bus code. Converting from YCbCr to RGB and RGB to YCbCr is possible 37462306a36Sopenharmony_ci * with VIN, so all supported YCbCr and RGB media bus codes can produce 37562306a36Sopenharmony_ci * all of the related pixel formats. If mbus_code is not set enumerate 37662306a36Sopenharmony_ci * all possible pixelformats. 37762306a36Sopenharmony_ci * 37862306a36Sopenharmony_ci * TODO: Once raw MEDIA_BUS_FMT_SRGGB12_1X12 format is added to the 37962306a36Sopenharmony_ci * driver this needs to be extended so raw media bus code only result in 38062306a36Sopenharmony_ci * raw pixel format. 38162306a36Sopenharmony_ci */ 38262306a36Sopenharmony_ci switch (f->mbus_code) { 38362306a36Sopenharmony_ci case 0: 38462306a36Sopenharmony_ci case MEDIA_BUS_FMT_YUYV8_1X16: 38562306a36Sopenharmony_ci case MEDIA_BUS_FMT_UYVY8_1X16: 38662306a36Sopenharmony_ci case MEDIA_BUS_FMT_UYVY8_2X8: 38762306a36Sopenharmony_ci case MEDIA_BUS_FMT_UYVY10_2X10: 38862306a36Sopenharmony_ci case MEDIA_BUS_FMT_RGB888_1X24: 38962306a36Sopenharmony_ci break; 39062306a36Sopenharmony_ci case MEDIA_BUS_FMT_SBGGR8_1X8: 39162306a36Sopenharmony_ci if (f->index) 39262306a36Sopenharmony_ci return -EINVAL; 39362306a36Sopenharmony_ci f->pixelformat = V4L2_PIX_FMT_SBGGR8; 39462306a36Sopenharmony_ci return 0; 39562306a36Sopenharmony_ci case MEDIA_BUS_FMT_SGBRG8_1X8: 39662306a36Sopenharmony_ci if (f->index) 39762306a36Sopenharmony_ci return -EINVAL; 39862306a36Sopenharmony_ci f->pixelformat = V4L2_PIX_FMT_SGBRG8; 39962306a36Sopenharmony_ci return 0; 40062306a36Sopenharmony_ci case MEDIA_BUS_FMT_SGRBG8_1X8: 40162306a36Sopenharmony_ci if (f->index) 40262306a36Sopenharmony_ci return -EINVAL; 40362306a36Sopenharmony_ci f->pixelformat = V4L2_PIX_FMT_SGRBG8; 40462306a36Sopenharmony_ci return 0; 40562306a36Sopenharmony_ci case MEDIA_BUS_FMT_SRGGB8_1X8: 40662306a36Sopenharmony_ci if (f->index) 40762306a36Sopenharmony_ci return -EINVAL; 40862306a36Sopenharmony_ci f->pixelformat = V4L2_PIX_FMT_SRGGB8; 40962306a36Sopenharmony_ci return 0; 41062306a36Sopenharmony_ci default: 41162306a36Sopenharmony_ci return -EINVAL; 41262306a36Sopenharmony_ci } 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci matched = -1; 41562306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(rvin_formats); i++) { 41662306a36Sopenharmony_ci if (rvin_format_from_pixel(vin, rvin_formats[i].fourcc)) 41762306a36Sopenharmony_ci matched++; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci if (matched == f->index) { 42062306a36Sopenharmony_ci f->pixelformat = rvin_formats[i].fourcc; 42162306a36Sopenharmony_ci return 0; 42262306a36Sopenharmony_ci } 42362306a36Sopenharmony_ci } 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci return -EINVAL; 42662306a36Sopenharmony_ci} 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_cistatic int rvin_remote_rectangle(struct rvin_dev *vin, struct v4l2_rect *rect) 42962306a36Sopenharmony_ci{ 43062306a36Sopenharmony_ci struct v4l2_subdev_format fmt = { 43162306a36Sopenharmony_ci .which = V4L2_SUBDEV_FORMAT_ACTIVE, 43262306a36Sopenharmony_ci }; 43362306a36Sopenharmony_ci struct v4l2_subdev *sd; 43462306a36Sopenharmony_ci unsigned int index; 43562306a36Sopenharmony_ci int ret; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci if (vin->info->use_mc) { 43862306a36Sopenharmony_ci struct media_pad *pad = media_pad_remote_pad_first(&vin->pad); 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci if (!pad) 44162306a36Sopenharmony_ci return -EINVAL; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci sd = media_entity_to_v4l2_subdev(pad->entity); 44462306a36Sopenharmony_ci index = pad->index; 44562306a36Sopenharmony_ci } else { 44662306a36Sopenharmony_ci sd = vin_to_source(vin); 44762306a36Sopenharmony_ci index = vin->parallel.source_pad; 44862306a36Sopenharmony_ci } 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci fmt.pad = index; 45162306a36Sopenharmony_ci ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt); 45262306a36Sopenharmony_ci if (ret) 45362306a36Sopenharmony_ci return ret; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci rect->left = rect->top = 0; 45662306a36Sopenharmony_ci rect->width = fmt.format.width; 45762306a36Sopenharmony_ci rect->height = fmt.format.height; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci if (fmt.format.field == V4L2_FIELD_ALTERNATE) { 46062306a36Sopenharmony_ci switch (vin->format.field) { 46162306a36Sopenharmony_ci case V4L2_FIELD_INTERLACED_TB: 46262306a36Sopenharmony_ci case V4L2_FIELD_INTERLACED_BT: 46362306a36Sopenharmony_ci case V4L2_FIELD_INTERLACED: 46462306a36Sopenharmony_ci case V4L2_FIELD_SEQ_TB: 46562306a36Sopenharmony_ci case V4L2_FIELD_SEQ_BT: 46662306a36Sopenharmony_ci rect->height *= 2; 46762306a36Sopenharmony_ci break; 46862306a36Sopenharmony_ci } 46962306a36Sopenharmony_ci } 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci return 0; 47262306a36Sopenharmony_ci} 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_cistatic int rvin_g_selection(struct file *file, void *fh, 47562306a36Sopenharmony_ci struct v4l2_selection *s) 47662306a36Sopenharmony_ci{ 47762306a36Sopenharmony_ci struct rvin_dev *vin = video_drvdata(file); 47862306a36Sopenharmony_ci int ret; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci if (!vin->scaler) 48162306a36Sopenharmony_ci return -ENOIOCTLCMD; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 48462306a36Sopenharmony_ci return -EINVAL; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci switch (s->target) { 48762306a36Sopenharmony_ci case V4L2_SEL_TGT_CROP_BOUNDS: 48862306a36Sopenharmony_ci case V4L2_SEL_TGT_CROP_DEFAULT: 48962306a36Sopenharmony_ci ret = rvin_remote_rectangle(vin, &s->r); 49062306a36Sopenharmony_ci if (ret) 49162306a36Sopenharmony_ci return ret; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci break; 49462306a36Sopenharmony_ci case V4L2_SEL_TGT_CROP: 49562306a36Sopenharmony_ci s->r = vin->crop; 49662306a36Sopenharmony_ci break; 49762306a36Sopenharmony_ci case V4L2_SEL_TGT_COMPOSE_BOUNDS: 49862306a36Sopenharmony_ci case V4L2_SEL_TGT_COMPOSE_DEFAULT: 49962306a36Sopenharmony_ci s->r.left = s->r.top = 0; 50062306a36Sopenharmony_ci s->r.width = vin->format.width; 50162306a36Sopenharmony_ci s->r.height = vin->format.height; 50262306a36Sopenharmony_ci break; 50362306a36Sopenharmony_ci case V4L2_SEL_TGT_COMPOSE: 50462306a36Sopenharmony_ci s->r = vin->compose; 50562306a36Sopenharmony_ci break; 50662306a36Sopenharmony_ci default: 50762306a36Sopenharmony_ci return -EINVAL; 50862306a36Sopenharmony_ci } 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci return 0; 51162306a36Sopenharmony_ci} 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_cistatic int rvin_s_selection(struct file *file, void *fh, 51462306a36Sopenharmony_ci struct v4l2_selection *s) 51562306a36Sopenharmony_ci{ 51662306a36Sopenharmony_ci struct rvin_dev *vin = video_drvdata(file); 51762306a36Sopenharmony_ci const struct rvin_video_format *fmt; 51862306a36Sopenharmony_ci struct v4l2_rect r = s->r; 51962306a36Sopenharmony_ci struct v4l2_rect max_rect; 52062306a36Sopenharmony_ci struct v4l2_rect min_rect = { 52162306a36Sopenharmony_ci .width = 6, 52262306a36Sopenharmony_ci .height = 2, 52362306a36Sopenharmony_ci }; 52462306a36Sopenharmony_ci int ret; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci if (!vin->scaler) 52762306a36Sopenharmony_ci return -ENOIOCTLCMD; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 53062306a36Sopenharmony_ci return -EINVAL; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci v4l2_rect_set_min_size(&r, &min_rect); 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci switch (s->target) { 53562306a36Sopenharmony_ci case V4L2_SEL_TGT_CROP: 53662306a36Sopenharmony_ci /* Can't crop outside of source input */ 53762306a36Sopenharmony_ci ret = rvin_remote_rectangle(vin, &max_rect); 53862306a36Sopenharmony_ci if (ret) 53962306a36Sopenharmony_ci return ret; 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci v4l2_rect_map_inside(&r, &max_rect); 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci v4l_bound_align_image(&r.width, 6, max_rect.width, 0, 54462306a36Sopenharmony_ci &r.height, 2, max_rect.height, 0, 0); 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci r.top = clamp_t(s32, r.top, 0, max_rect.height - r.height); 54762306a36Sopenharmony_ci r.left = clamp_t(s32, r.left, 0, max_rect.width - r.width); 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci vin->crop = s->r = r; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci vin_dbg(vin, "Cropped %dx%d@%d:%d of %dx%d\n", 55262306a36Sopenharmony_ci r.width, r.height, r.left, r.top, 55362306a36Sopenharmony_ci max_rect.width, max_rect.height); 55462306a36Sopenharmony_ci break; 55562306a36Sopenharmony_ci case V4L2_SEL_TGT_COMPOSE: 55662306a36Sopenharmony_ci /* Make sure compose rect fits inside output format */ 55762306a36Sopenharmony_ci max_rect.top = max_rect.left = 0; 55862306a36Sopenharmony_ci max_rect.width = vin->format.width; 55962306a36Sopenharmony_ci max_rect.height = vin->format.height; 56062306a36Sopenharmony_ci v4l2_rect_map_inside(&r, &max_rect); 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci /* 56362306a36Sopenharmony_ci * Composing is done by adding a offset to the buffer address, 56462306a36Sopenharmony_ci * the HW wants this address to be aligned to HW_BUFFER_MASK. 56562306a36Sopenharmony_ci * Make sure the top and left values meets this requirement. 56662306a36Sopenharmony_ci */ 56762306a36Sopenharmony_ci while ((r.top * vin->format.bytesperline) & HW_BUFFER_MASK) 56862306a36Sopenharmony_ci r.top--; 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci fmt = rvin_format_from_pixel(vin, vin->format.pixelformat); 57162306a36Sopenharmony_ci while ((r.left * fmt->bpp) & HW_BUFFER_MASK) 57262306a36Sopenharmony_ci r.left--; 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci vin->compose = s->r = r; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci vin_dbg(vin, "Compose %dx%d@%d:%d in %dx%d\n", 57762306a36Sopenharmony_ci r.width, r.height, r.left, r.top, 57862306a36Sopenharmony_ci vin->format.width, vin->format.height); 57962306a36Sopenharmony_ci break; 58062306a36Sopenharmony_ci default: 58162306a36Sopenharmony_ci return -EINVAL; 58262306a36Sopenharmony_ci } 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci /* HW supports modifying configuration while running */ 58562306a36Sopenharmony_ci rvin_crop_scale_comp(vin); 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci return 0; 58862306a36Sopenharmony_ci} 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_cistatic int rvin_g_parm(struct file *file, void *priv, 59162306a36Sopenharmony_ci struct v4l2_streamparm *parm) 59262306a36Sopenharmony_ci{ 59362306a36Sopenharmony_ci struct rvin_dev *vin = video_drvdata(file); 59462306a36Sopenharmony_ci struct v4l2_subdev *sd = vin_to_source(vin); 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci return v4l2_g_parm_cap(&vin->vdev, sd, parm); 59762306a36Sopenharmony_ci} 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_cistatic int rvin_s_parm(struct file *file, void *priv, 60062306a36Sopenharmony_ci struct v4l2_streamparm *parm) 60162306a36Sopenharmony_ci{ 60262306a36Sopenharmony_ci struct rvin_dev *vin = video_drvdata(file); 60362306a36Sopenharmony_ci struct v4l2_subdev *sd = vin_to_source(vin); 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci return v4l2_s_parm_cap(&vin->vdev, sd, parm); 60662306a36Sopenharmony_ci} 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_cistatic int rvin_g_pixelaspect(struct file *file, void *priv, 60962306a36Sopenharmony_ci int type, struct v4l2_fract *f) 61062306a36Sopenharmony_ci{ 61162306a36Sopenharmony_ci struct rvin_dev *vin = video_drvdata(file); 61262306a36Sopenharmony_ci struct v4l2_subdev *sd = vin_to_source(vin); 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 61562306a36Sopenharmony_ci return -EINVAL; 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci return v4l2_subdev_call(sd, video, g_pixelaspect, f); 61862306a36Sopenharmony_ci} 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_cistatic int rvin_enum_input(struct file *file, void *priv, 62162306a36Sopenharmony_ci struct v4l2_input *i) 62262306a36Sopenharmony_ci{ 62362306a36Sopenharmony_ci struct rvin_dev *vin = video_drvdata(file); 62462306a36Sopenharmony_ci struct v4l2_subdev *sd = vin_to_source(vin); 62562306a36Sopenharmony_ci int ret; 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci if (i->index != 0) 62862306a36Sopenharmony_ci return -EINVAL; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci ret = v4l2_subdev_call(sd, video, g_input_status, &i->status); 63162306a36Sopenharmony_ci if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) 63262306a36Sopenharmony_ci return ret; 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci i->type = V4L2_INPUT_TYPE_CAMERA; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci if (v4l2_subdev_has_op(sd, pad, dv_timings_cap)) { 63762306a36Sopenharmony_ci i->capabilities = V4L2_IN_CAP_DV_TIMINGS; 63862306a36Sopenharmony_ci i->std = 0; 63962306a36Sopenharmony_ci } else { 64062306a36Sopenharmony_ci i->capabilities = V4L2_IN_CAP_STD; 64162306a36Sopenharmony_ci i->std = vin->vdev.tvnorms; 64262306a36Sopenharmony_ci } 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci strscpy(i->name, "Camera", sizeof(i->name)); 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci return 0; 64762306a36Sopenharmony_ci} 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_cistatic int rvin_g_input(struct file *file, void *priv, unsigned int *i) 65062306a36Sopenharmony_ci{ 65162306a36Sopenharmony_ci *i = 0; 65262306a36Sopenharmony_ci return 0; 65362306a36Sopenharmony_ci} 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_cistatic int rvin_s_input(struct file *file, void *priv, unsigned int i) 65662306a36Sopenharmony_ci{ 65762306a36Sopenharmony_ci if (i > 0) 65862306a36Sopenharmony_ci return -EINVAL; 65962306a36Sopenharmony_ci return 0; 66062306a36Sopenharmony_ci} 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_cistatic int rvin_querystd(struct file *file, void *priv, v4l2_std_id *a) 66362306a36Sopenharmony_ci{ 66462306a36Sopenharmony_ci struct rvin_dev *vin = video_drvdata(file); 66562306a36Sopenharmony_ci struct v4l2_subdev *sd = vin_to_source(vin); 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci return v4l2_subdev_call(sd, video, querystd, a); 66862306a36Sopenharmony_ci} 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_cistatic int rvin_s_std(struct file *file, void *priv, v4l2_std_id a) 67162306a36Sopenharmony_ci{ 67262306a36Sopenharmony_ci struct rvin_dev *vin = video_drvdata(file); 67362306a36Sopenharmony_ci int ret; 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci ret = v4l2_subdev_call(vin_to_source(vin), video, s_std, a); 67662306a36Sopenharmony_ci if (ret < 0) 67762306a36Sopenharmony_ci return ret; 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci vin->std = a; 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci /* Changing the standard will change the width/height */ 68262306a36Sopenharmony_ci return rvin_reset_format(vin); 68362306a36Sopenharmony_ci} 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_cistatic int rvin_g_std(struct file *file, void *priv, v4l2_std_id *a) 68662306a36Sopenharmony_ci{ 68762306a36Sopenharmony_ci struct rvin_dev *vin = video_drvdata(file); 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci if (v4l2_subdev_has_op(vin_to_source(vin), pad, dv_timings_cap)) 69062306a36Sopenharmony_ci return -ENOIOCTLCMD; 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci *a = vin->std; 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci return 0; 69562306a36Sopenharmony_ci} 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_cistatic int rvin_subscribe_event(struct v4l2_fh *fh, 69862306a36Sopenharmony_ci const struct v4l2_event_subscription *sub) 69962306a36Sopenharmony_ci{ 70062306a36Sopenharmony_ci switch (sub->type) { 70162306a36Sopenharmony_ci case V4L2_EVENT_SOURCE_CHANGE: 70262306a36Sopenharmony_ci return v4l2_event_subscribe(fh, sub, 4, NULL); 70362306a36Sopenharmony_ci } 70462306a36Sopenharmony_ci return v4l2_ctrl_subscribe_event(fh, sub); 70562306a36Sopenharmony_ci} 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_cistatic int rvin_enum_dv_timings(struct file *file, void *priv_fh, 70862306a36Sopenharmony_ci struct v4l2_enum_dv_timings *timings) 70962306a36Sopenharmony_ci{ 71062306a36Sopenharmony_ci struct rvin_dev *vin = video_drvdata(file); 71162306a36Sopenharmony_ci struct v4l2_subdev *sd = vin_to_source(vin); 71262306a36Sopenharmony_ci int ret; 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci if (timings->pad) 71562306a36Sopenharmony_ci return -EINVAL; 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci timings->pad = vin->parallel.sink_pad; 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci ret = v4l2_subdev_call(sd, pad, enum_dv_timings, timings); 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci timings->pad = 0; 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci return ret; 72462306a36Sopenharmony_ci} 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_cistatic int rvin_s_dv_timings(struct file *file, void *priv_fh, 72762306a36Sopenharmony_ci struct v4l2_dv_timings *timings) 72862306a36Sopenharmony_ci{ 72962306a36Sopenharmony_ci struct rvin_dev *vin = video_drvdata(file); 73062306a36Sopenharmony_ci struct v4l2_subdev *sd = vin_to_source(vin); 73162306a36Sopenharmony_ci int ret; 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci ret = v4l2_subdev_call(sd, video, s_dv_timings, timings); 73462306a36Sopenharmony_ci if (ret) 73562306a36Sopenharmony_ci return ret; 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci /* Changing the timings will change the width/height */ 73862306a36Sopenharmony_ci return rvin_reset_format(vin); 73962306a36Sopenharmony_ci} 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_cistatic int rvin_g_dv_timings(struct file *file, void *priv_fh, 74262306a36Sopenharmony_ci struct v4l2_dv_timings *timings) 74362306a36Sopenharmony_ci{ 74462306a36Sopenharmony_ci struct rvin_dev *vin = video_drvdata(file); 74562306a36Sopenharmony_ci struct v4l2_subdev *sd = vin_to_source(vin); 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci return v4l2_subdev_call(sd, video, g_dv_timings, timings); 74862306a36Sopenharmony_ci} 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_cistatic int rvin_query_dv_timings(struct file *file, void *priv_fh, 75162306a36Sopenharmony_ci struct v4l2_dv_timings *timings) 75262306a36Sopenharmony_ci{ 75362306a36Sopenharmony_ci struct rvin_dev *vin = video_drvdata(file); 75462306a36Sopenharmony_ci struct v4l2_subdev *sd = vin_to_source(vin); 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci return v4l2_subdev_call(sd, video, query_dv_timings, timings); 75762306a36Sopenharmony_ci} 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_cistatic int rvin_dv_timings_cap(struct file *file, void *priv_fh, 76062306a36Sopenharmony_ci struct v4l2_dv_timings_cap *cap) 76162306a36Sopenharmony_ci{ 76262306a36Sopenharmony_ci struct rvin_dev *vin = video_drvdata(file); 76362306a36Sopenharmony_ci struct v4l2_subdev *sd = vin_to_source(vin); 76462306a36Sopenharmony_ci int ret; 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci if (cap->pad) 76762306a36Sopenharmony_ci return -EINVAL; 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci cap->pad = vin->parallel.sink_pad; 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci ret = v4l2_subdev_call(sd, pad, dv_timings_cap, cap); 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci cap->pad = 0; 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci return ret; 77662306a36Sopenharmony_ci} 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_cistatic int rvin_g_edid(struct file *file, void *fh, struct v4l2_edid *edid) 77962306a36Sopenharmony_ci{ 78062306a36Sopenharmony_ci struct rvin_dev *vin = video_drvdata(file); 78162306a36Sopenharmony_ci struct v4l2_subdev *sd = vin_to_source(vin); 78262306a36Sopenharmony_ci int ret; 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci if (edid->pad) 78562306a36Sopenharmony_ci return -EINVAL; 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci edid->pad = vin->parallel.sink_pad; 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci ret = v4l2_subdev_call(sd, pad, get_edid, edid); 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci edid->pad = 0; 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci return ret; 79462306a36Sopenharmony_ci} 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_cistatic int rvin_s_edid(struct file *file, void *fh, struct v4l2_edid *edid) 79762306a36Sopenharmony_ci{ 79862306a36Sopenharmony_ci struct rvin_dev *vin = video_drvdata(file); 79962306a36Sopenharmony_ci struct v4l2_subdev *sd = vin_to_source(vin); 80062306a36Sopenharmony_ci int ret; 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci if (edid->pad) 80362306a36Sopenharmony_ci return -EINVAL; 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci edid->pad = vin->parallel.sink_pad; 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci ret = v4l2_subdev_call(sd, pad, set_edid, edid); 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci edid->pad = 0; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci return ret; 81262306a36Sopenharmony_ci} 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_cistatic const struct v4l2_ioctl_ops rvin_ioctl_ops = { 81562306a36Sopenharmony_ci .vidioc_querycap = rvin_querycap, 81662306a36Sopenharmony_ci .vidioc_try_fmt_vid_cap = rvin_try_fmt_vid_cap, 81762306a36Sopenharmony_ci .vidioc_g_fmt_vid_cap = rvin_g_fmt_vid_cap, 81862306a36Sopenharmony_ci .vidioc_s_fmt_vid_cap = rvin_s_fmt_vid_cap, 81962306a36Sopenharmony_ci .vidioc_enum_fmt_vid_cap = rvin_enum_fmt_vid_cap, 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci .vidioc_g_selection = rvin_g_selection, 82262306a36Sopenharmony_ci .vidioc_s_selection = rvin_s_selection, 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci .vidioc_g_parm = rvin_g_parm, 82562306a36Sopenharmony_ci .vidioc_s_parm = rvin_s_parm, 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci .vidioc_g_pixelaspect = rvin_g_pixelaspect, 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci .vidioc_enum_input = rvin_enum_input, 83062306a36Sopenharmony_ci .vidioc_g_input = rvin_g_input, 83162306a36Sopenharmony_ci .vidioc_s_input = rvin_s_input, 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci .vidioc_dv_timings_cap = rvin_dv_timings_cap, 83462306a36Sopenharmony_ci .vidioc_enum_dv_timings = rvin_enum_dv_timings, 83562306a36Sopenharmony_ci .vidioc_g_dv_timings = rvin_g_dv_timings, 83662306a36Sopenharmony_ci .vidioc_s_dv_timings = rvin_s_dv_timings, 83762306a36Sopenharmony_ci .vidioc_query_dv_timings = rvin_query_dv_timings, 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci .vidioc_g_edid = rvin_g_edid, 84062306a36Sopenharmony_ci .vidioc_s_edid = rvin_s_edid, 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci .vidioc_querystd = rvin_querystd, 84362306a36Sopenharmony_ci .vidioc_g_std = rvin_g_std, 84462306a36Sopenharmony_ci .vidioc_s_std = rvin_s_std, 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci .vidioc_reqbufs = vb2_ioctl_reqbufs, 84762306a36Sopenharmony_ci .vidioc_create_bufs = vb2_ioctl_create_bufs, 84862306a36Sopenharmony_ci .vidioc_querybuf = vb2_ioctl_querybuf, 84962306a36Sopenharmony_ci .vidioc_qbuf = vb2_ioctl_qbuf, 85062306a36Sopenharmony_ci .vidioc_dqbuf = vb2_ioctl_dqbuf, 85162306a36Sopenharmony_ci .vidioc_expbuf = vb2_ioctl_expbuf, 85262306a36Sopenharmony_ci .vidioc_prepare_buf = vb2_ioctl_prepare_buf, 85362306a36Sopenharmony_ci .vidioc_streamon = vb2_ioctl_streamon, 85462306a36Sopenharmony_ci .vidioc_streamoff = vb2_ioctl_streamoff, 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci .vidioc_log_status = v4l2_ctrl_log_status, 85762306a36Sopenharmony_ci .vidioc_subscribe_event = rvin_subscribe_event, 85862306a36Sopenharmony_ci .vidioc_unsubscribe_event = v4l2_event_unsubscribe, 85962306a36Sopenharmony_ci}; 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci/* ----------------------------------------------------------------------------- 86262306a36Sopenharmony_ci * V4L2 Media Controller 86362306a36Sopenharmony_ci */ 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_cistatic void rvin_mc_try_format(struct rvin_dev *vin, 86662306a36Sopenharmony_ci struct v4l2_pix_format *pix) 86762306a36Sopenharmony_ci{ 86862306a36Sopenharmony_ci /* 86962306a36Sopenharmony_ci * The V4L2 specification clearly documents the colorspace fields 87062306a36Sopenharmony_ci * as being set by drivers for capture devices. Using the values 87162306a36Sopenharmony_ci * supplied by userspace thus wouldn't comply with the API. Until 87262306a36Sopenharmony_ci * the API is updated force fixed values. 87362306a36Sopenharmony_ci */ 87462306a36Sopenharmony_ci pix->colorspace = RVIN_DEFAULT_COLORSPACE; 87562306a36Sopenharmony_ci pix->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(pix->colorspace); 87662306a36Sopenharmony_ci pix->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(pix->colorspace); 87762306a36Sopenharmony_ci pix->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true, pix->colorspace, 87862306a36Sopenharmony_ci pix->ycbcr_enc); 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci rvin_format_align(vin, pix); 88162306a36Sopenharmony_ci} 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_cistatic int rvin_mc_try_fmt_vid_cap(struct file *file, void *priv, 88462306a36Sopenharmony_ci struct v4l2_format *f) 88562306a36Sopenharmony_ci{ 88662306a36Sopenharmony_ci struct rvin_dev *vin = video_drvdata(file); 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci rvin_mc_try_format(vin, &f->fmt.pix); 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci return 0; 89162306a36Sopenharmony_ci} 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_cistatic int rvin_mc_s_fmt_vid_cap(struct file *file, void *priv, 89462306a36Sopenharmony_ci struct v4l2_format *f) 89562306a36Sopenharmony_ci{ 89662306a36Sopenharmony_ci struct rvin_dev *vin = video_drvdata(file); 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci if (vb2_is_busy(&vin->queue)) 89962306a36Sopenharmony_ci return -EBUSY; 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci rvin_mc_try_format(vin, &f->fmt.pix); 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci vin->format = f->fmt.pix; 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci vin->crop.top = 0; 90662306a36Sopenharmony_ci vin->crop.left = 0; 90762306a36Sopenharmony_ci vin->crop.width = vin->format.width; 90862306a36Sopenharmony_ci vin->crop.height = vin->format.height; 90962306a36Sopenharmony_ci vin->compose = vin->crop; 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci return 0; 91262306a36Sopenharmony_ci} 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_cistatic const struct v4l2_ioctl_ops rvin_mc_ioctl_ops = { 91562306a36Sopenharmony_ci .vidioc_querycap = rvin_querycap, 91662306a36Sopenharmony_ci .vidioc_try_fmt_vid_cap = rvin_mc_try_fmt_vid_cap, 91762306a36Sopenharmony_ci .vidioc_g_fmt_vid_cap = rvin_g_fmt_vid_cap, 91862306a36Sopenharmony_ci .vidioc_s_fmt_vid_cap = rvin_mc_s_fmt_vid_cap, 91962306a36Sopenharmony_ci .vidioc_enum_fmt_vid_cap = rvin_enum_fmt_vid_cap, 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci .vidioc_g_selection = rvin_g_selection, 92262306a36Sopenharmony_ci .vidioc_s_selection = rvin_s_selection, 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci .vidioc_reqbufs = vb2_ioctl_reqbufs, 92562306a36Sopenharmony_ci .vidioc_create_bufs = vb2_ioctl_create_bufs, 92662306a36Sopenharmony_ci .vidioc_querybuf = vb2_ioctl_querybuf, 92762306a36Sopenharmony_ci .vidioc_qbuf = vb2_ioctl_qbuf, 92862306a36Sopenharmony_ci .vidioc_dqbuf = vb2_ioctl_dqbuf, 92962306a36Sopenharmony_ci .vidioc_expbuf = vb2_ioctl_expbuf, 93062306a36Sopenharmony_ci .vidioc_prepare_buf = vb2_ioctl_prepare_buf, 93162306a36Sopenharmony_ci .vidioc_streamon = vb2_ioctl_streamon, 93262306a36Sopenharmony_ci .vidioc_streamoff = vb2_ioctl_streamoff, 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci .vidioc_log_status = v4l2_ctrl_log_status, 93562306a36Sopenharmony_ci .vidioc_subscribe_event = rvin_subscribe_event, 93662306a36Sopenharmony_ci .vidioc_unsubscribe_event = v4l2_event_unsubscribe, 93762306a36Sopenharmony_ci}; 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci/* ----------------------------------------------------------------------------- 94062306a36Sopenharmony_ci * File Operations 94162306a36Sopenharmony_ci */ 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_cistatic int rvin_power_parallel(struct rvin_dev *vin, bool on) 94462306a36Sopenharmony_ci{ 94562306a36Sopenharmony_ci struct v4l2_subdev *sd = vin_to_source(vin); 94662306a36Sopenharmony_ci int power = on ? 1 : 0; 94762306a36Sopenharmony_ci int ret; 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci ret = v4l2_subdev_call(sd, core, s_power, power); 95062306a36Sopenharmony_ci if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) 95162306a36Sopenharmony_ci return ret; 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci return 0; 95462306a36Sopenharmony_ci} 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_cistatic int rvin_open(struct file *file) 95762306a36Sopenharmony_ci{ 95862306a36Sopenharmony_ci struct rvin_dev *vin = video_drvdata(file); 95962306a36Sopenharmony_ci int ret; 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci ret = pm_runtime_resume_and_get(vin->dev); 96262306a36Sopenharmony_ci if (ret < 0) 96362306a36Sopenharmony_ci return ret; 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci ret = mutex_lock_interruptible(&vin->lock); 96662306a36Sopenharmony_ci if (ret) 96762306a36Sopenharmony_ci goto err_pm; 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci file->private_data = vin; 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci ret = v4l2_fh_open(file); 97262306a36Sopenharmony_ci if (ret) 97362306a36Sopenharmony_ci goto err_unlock; 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci if (vin->info->use_mc) 97662306a36Sopenharmony_ci ret = v4l2_pipeline_pm_get(&vin->vdev.entity); 97762306a36Sopenharmony_ci else if (v4l2_fh_is_singular_file(file)) 97862306a36Sopenharmony_ci ret = rvin_power_parallel(vin, true); 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci if (ret < 0) 98162306a36Sopenharmony_ci goto err_open; 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci ret = v4l2_ctrl_handler_setup(&vin->ctrl_handler); 98462306a36Sopenharmony_ci if (ret) 98562306a36Sopenharmony_ci goto err_power; 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci mutex_unlock(&vin->lock); 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci return 0; 99062306a36Sopenharmony_cierr_power: 99162306a36Sopenharmony_ci if (vin->info->use_mc) 99262306a36Sopenharmony_ci v4l2_pipeline_pm_put(&vin->vdev.entity); 99362306a36Sopenharmony_ci else if (v4l2_fh_is_singular_file(file)) 99462306a36Sopenharmony_ci rvin_power_parallel(vin, false); 99562306a36Sopenharmony_cierr_open: 99662306a36Sopenharmony_ci v4l2_fh_release(file); 99762306a36Sopenharmony_cierr_unlock: 99862306a36Sopenharmony_ci mutex_unlock(&vin->lock); 99962306a36Sopenharmony_cierr_pm: 100062306a36Sopenharmony_ci pm_runtime_put(vin->dev); 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci return ret; 100362306a36Sopenharmony_ci} 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_cistatic int rvin_release(struct file *file) 100662306a36Sopenharmony_ci{ 100762306a36Sopenharmony_ci struct rvin_dev *vin = video_drvdata(file); 100862306a36Sopenharmony_ci bool fh_singular; 100962306a36Sopenharmony_ci int ret; 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci mutex_lock(&vin->lock); 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci /* Save the singular status before we call the clean-up helper */ 101462306a36Sopenharmony_ci fh_singular = v4l2_fh_is_singular_file(file); 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci /* the release helper will cleanup any on-going streaming */ 101762306a36Sopenharmony_ci ret = _vb2_fop_release(file, NULL); 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci if (vin->info->use_mc) { 102062306a36Sopenharmony_ci v4l2_pipeline_pm_put(&vin->vdev.entity); 102162306a36Sopenharmony_ci } else { 102262306a36Sopenharmony_ci if (fh_singular) 102362306a36Sopenharmony_ci rvin_power_parallel(vin, false); 102462306a36Sopenharmony_ci } 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci mutex_unlock(&vin->lock); 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci pm_runtime_put(vin->dev); 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci return ret; 103162306a36Sopenharmony_ci} 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_cistatic const struct v4l2_file_operations rvin_fops = { 103462306a36Sopenharmony_ci .owner = THIS_MODULE, 103562306a36Sopenharmony_ci .unlocked_ioctl = video_ioctl2, 103662306a36Sopenharmony_ci .open = rvin_open, 103762306a36Sopenharmony_ci .release = rvin_release, 103862306a36Sopenharmony_ci .poll = vb2_fop_poll, 103962306a36Sopenharmony_ci .mmap = vb2_fop_mmap, 104062306a36Sopenharmony_ci .read = vb2_fop_read, 104162306a36Sopenharmony_ci}; 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_civoid rvin_v4l2_unregister(struct rvin_dev *vin) 104462306a36Sopenharmony_ci{ 104562306a36Sopenharmony_ci if (!video_is_registered(&vin->vdev)) 104662306a36Sopenharmony_ci return; 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci v4l2_info(&vin->v4l2_dev, "Removing %s\n", 104962306a36Sopenharmony_ci video_device_node_name(&vin->vdev)); 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci /* Checks internally if vdev have been init or not */ 105262306a36Sopenharmony_ci video_unregister_device(&vin->vdev); 105362306a36Sopenharmony_ci} 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_cistatic void rvin_notify_video_device(struct rvin_dev *vin, 105662306a36Sopenharmony_ci unsigned int notification, void *arg) 105762306a36Sopenharmony_ci{ 105862306a36Sopenharmony_ci switch (notification) { 105962306a36Sopenharmony_ci case V4L2_DEVICE_NOTIFY_EVENT: 106062306a36Sopenharmony_ci v4l2_event_queue(&vin->vdev, arg); 106162306a36Sopenharmony_ci break; 106262306a36Sopenharmony_ci default: 106362306a36Sopenharmony_ci break; 106462306a36Sopenharmony_ci } 106562306a36Sopenharmony_ci} 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_cistatic void rvin_notify(struct v4l2_subdev *sd, 106862306a36Sopenharmony_ci unsigned int notification, void *arg) 106962306a36Sopenharmony_ci{ 107062306a36Sopenharmony_ci struct v4l2_subdev *remote; 107162306a36Sopenharmony_ci struct rvin_group *group; 107262306a36Sopenharmony_ci struct media_pad *pad; 107362306a36Sopenharmony_ci struct rvin_dev *vin = 107462306a36Sopenharmony_ci container_of(sd->v4l2_dev, struct rvin_dev, v4l2_dev); 107562306a36Sopenharmony_ci unsigned int i; 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci /* If no media controller, no need to route the event. */ 107862306a36Sopenharmony_ci if (!vin->info->use_mc) { 107962306a36Sopenharmony_ci rvin_notify_video_device(vin, notification, arg); 108062306a36Sopenharmony_ci return; 108162306a36Sopenharmony_ci } 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci group = vin->group; 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci for (i = 0; i < RCAR_VIN_NUM; i++) { 108662306a36Sopenharmony_ci vin = group->vin[i]; 108762306a36Sopenharmony_ci if (!vin) 108862306a36Sopenharmony_ci continue; 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci pad = media_pad_remote_pad_first(&vin->pad); 109162306a36Sopenharmony_ci if (!pad) 109262306a36Sopenharmony_ci continue; 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci remote = media_entity_to_v4l2_subdev(pad->entity); 109562306a36Sopenharmony_ci if (remote != sd) 109662306a36Sopenharmony_ci continue; 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci rvin_notify_video_device(vin, notification, arg); 109962306a36Sopenharmony_ci } 110062306a36Sopenharmony_ci} 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ciint rvin_v4l2_register(struct rvin_dev *vin) 110362306a36Sopenharmony_ci{ 110462306a36Sopenharmony_ci struct video_device *vdev = &vin->vdev; 110562306a36Sopenharmony_ci int ret; 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci vin->v4l2_dev.notify = rvin_notify; 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci /* video node */ 111062306a36Sopenharmony_ci vdev->v4l2_dev = &vin->v4l2_dev; 111162306a36Sopenharmony_ci vdev->queue = &vin->queue; 111262306a36Sopenharmony_ci snprintf(vdev->name, sizeof(vdev->name), "VIN%u output", vin->id); 111362306a36Sopenharmony_ci vdev->release = video_device_release_empty; 111462306a36Sopenharmony_ci vdev->lock = &vin->lock; 111562306a36Sopenharmony_ci vdev->fops = &rvin_fops; 111662306a36Sopenharmony_ci vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | 111762306a36Sopenharmony_ci V4L2_CAP_READWRITE; 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_ci /* Set a default format */ 112062306a36Sopenharmony_ci vin->format.pixelformat = RVIN_DEFAULT_FORMAT; 112162306a36Sopenharmony_ci vin->format.width = RVIN_DEFAULT_WIDTH; 112262306a36Sopenharmony_ci vin->format.height = RVIN_DEFAULT_HEIGHT; 112362306a36Sopenharmony_ci vin->format.field = RVIN_DEFAULT_FIELD; 112462306a36Sopenharmony_ci vin->format.colorspace = RVIN_DEFAULT_COLORSPACE; 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_ci if (vin->info->use_mc) { 112762306a36Sopenharmony_ci vdev->device_caps |= V4L2_CAP_IO_MC; 112862306a36Sopenharmony_ci vdev->ioctl_ops = &rvin_mc_ioctl_ops; 112962306a36Sopenharmony_ci } else { 113062306a36Sopenharmony_ci vdev->ioctl_ops = &rvin_ioctl_ops; 113162306a36Sopenharmony_ci rvin_reset_format(vin); 113262306a36Sopenharmony_ci } 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci rvin_format_align(vin, &vin->format); 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci ret = video_register_device(&vin->vdev, VFL_TYPE_VIDEO, -1); 113762306a36Sopenharmony_ci if (ret) { 113862306a36Sopenharmony_ci vin_err(vin, "Failed to register video device\n"); 113962306a36Sopenharmony_ci return ret; 114062306a36Sopenharmony_ci } 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci video_set_drvdata(&vin->vdev, vin); 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci v4l2_info(&vin->v4l2_dev, "Device registered as %s\n", 114562306a36Sopenharmony_ci video_device_node_name(&vin->vdev)); 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci return ret; 114862306a36Sopenharmony_ci} 1149