18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Driver for Renesas R-Car VIN
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2016 Renesas Electronics Corp.
68c2ecf20Sopenharmony_ci * Copyright (C) 2011-2013 Renesas Solutions Corp.
78c2ecf20Sopenharmony_ci * Copyright (C) 2013 Cogent Embedded, Inc., <source@cogentembedded.com>
88c2ecf20Sopenharmony_ci * Copyright (C) 2008 Magnus Damm
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * Based on the soc-camera rcar_vin driver
118c2ecf20Sopenharmony_ci */
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include <media/v4l2-event.h>
168c2ecf20Sopenharmony_ci#include <media/v4l2-ioctl.h>
178c2ecf20Sopenharmony_ci#include <media/v4l2-mc.h>
188c2ecf20Sopenharmony_ci#include <media/v4l2-rect.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#include "rcar-vin.h"
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#define RVIN_DEFAULT_FORMAT	V4L2_PIX_FMT_YUYV
238c2ecf20Sopenharmony_ci#define RVIN_DEFAULT_WIDTH	800
248c2ecf20Sopenharmony_ci#define RVIN_DEFAULT_HEIGHT	600
258c2ecf20Sopenharmony_ci#define RVIN_DEFAULT_FIELD	V4L2_FIELD_NONE
268c2ecf20Sopenharmony_ci#define RVIN_DEFAULT_COLORSPACE	V4L2_COLORSPACE_SRGB
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci/* -----------------------------------------------------------------------------
298c2ecf20Sopenharmony_ci * Format Conversions
308c2ecf20Sopenharmony_ci */
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_cistatic const struct rvin_video_format rvin_formats[] = {
338c2ecf20Sopenharmony_ci	{
348c2ecf20Sopenharmony_ci		.fourcc			= V4L2_PIX_FMT_NV12,
358c2ecf20Sopenharmony_ci		.bpp			= 1,
368c2ecf20Sopenharmony_ci	},
378c2ecf20Sopenharmony_ci	{
388c2ecf20Sopenharmony_ci		.fourcc			= V4L2_PIX_FMT_NV16,
398c2ecf20Sopenharmony_ci		.bpp			= 1,
408c2ecf20Sopenharmony_ci	},
418c2ecf20Sopenharmony_ci	{
428c2ecf20Sopenharmony_ci		.fourcc			= V4L2_PIX_FMT_YUYV,
438c2ecf20Sopenharmony_ci		.bpp			= 2,
448c2ecf20Sopenharmony_ci	},
458c2ecf20Sopenharmony_ci	{
468c2ecf20Sopenharmony_ci		.fourcc			= V4L2_PIX_FMT_UYVY,
478c2ecf20Sopenharmony_ci		.bpp			= 2,
488c2ecf20Sopenharmony_ci	},
498c2ecf20Sopenharmony_ci	{
508c2ecf20Sopenharmony_ci		.fourcc			= V4L2_PIX_FMT_RGB565,
518c2ecf20Sopenharmony_ci		.bpp			= 2,
528c2ecf20Sopenharmony_ci	},
538c2ecf20Sopenharmony_ci	{
548c2ecf20Sopenharmony_ci		.fourcc			= V4L2_PIX_FMT_XRGB555,
558c2ecf20Sopenharmony_ci		.bpp			= 2,
568c2ecf20Sopenharmony_ci	},
578c2ecf20Sopenharmony_ci	{
588c2ecf20Sopenharmony_ci		.fourcc			= V4L2_PIX_FMT_XBGR32,
598c2ecf20Sopenharmony_ci		.bpp			= 4,
608c2ecf20Sopenharmony_ci	},
618c2ecf20Sopenharmony_ci	{
628c2ecf20Sopenharmony_ci		.fourcc			= V4L2_PIX_FMT_ARGB555,
638c2ecf20Sopenharmony_ci		.bpp			= 2,
648c2ecf20Sopenharmony_ci	},
658c2ecf20Sopenharmony_ci	{
668c2ecf20Sopenharmony_ci		.fourcc			= V4L2_PIX_FMT_ABGR32,
678c2ecf20Sopenharmony_ci		.bpp			= 4,
688c2ecf20Sopenharmony_ci	},
698c2ecf20Sopenharmony_ci	{
708c2ecf20Sopenharmony_ci		.fourcc			= V4L2_PIX_FMT_SBGGR8,
718c2ecf20Sopenharmony_ci		.bpp			= 1,
728c2ecf20Sopenharmony_ci	},
738c2ecf20Sopenharmony_ci	{
748c2ecf20Sopenharmony_ci		.fourcc			= V4L2_PIX_FMT_SGBRG8,
758c2ecf20Sopenharmony_ci		.bpp			= 1,
768c2ecf20Sopenharmony_ci	},
778c2ecf20Sopenharmony_ci	{
788c2ecf20Sopenharmony_ci		.fourcc			= V4L2_PIX_FMT_SGRBG8,
798c2ecf20Sopenharmony_ci		.bpp			= 1,
808c2ecf20Sopenharmony_ci	},
818c2ecf20Sopenharmony_ci	{
828c2ecf20Sopenharmony_ci		.fourcc			= V4L2_PIX_FMT_SRGGB8,
838c2ecf20Sopenharmony_ci		.bpp			= 1,
848c2ecf20Sopenharmony_ci	},
858c2ecf20Sopenharmony_ci};
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ciconst struct rvin_video_format *rvin_format_from_pixel(struct rvin_dev *vin,
888c2ecf20Sopenharmony_ci						       u32 pixelformat)
898c2ecf20Sopenharmony_ci{
908c2ecf20Sopenharmony_ci	int i;
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	switch (pixelformat) {
938c2ecf20Sopenharmony_ci	case V4L2_PIX_FMT_XBGR32:
948c2ecf20Sopenharmony_ci		if (vin->info->model == RCAR_M1)
958c2ecf20Sopenharmony_ci			return NULL;
968c2ecf20Sopenharmony_ci		break;
978c2ecf20Sopenharmony_ci	case V4L2_PIX_FMT_NV12:
988c2ecf20Sopenharmony_ci		/*
998c2ecf20Sopenharmony_ci		 * If NV12 is supported it's only supported on channels 0, 1, 4,
1008c2ecf20Sopenharmony_ci		 * 5, 8, 9, 12 and 13.
1018c2ecf20Sopenharmony_ci		 */
1028c2ecf20Sopenharmony_ci		if (!vin->info->nv12 || !(BIT(vin->id) & 0x3333))
1038c2ecf20Sopenharmony_ci			return NULL;
1048c2ecf20Sopenharmony_ci		break;
1058c2ecf20Sopenharmony_ci	default:
1068c2ecf20Sopenharmony_ci		break;
1078c2ecf20Sopenharmony_ci	}
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(rvin_formats); i++)
1108c2ecf20Sopenharmony_ci		if (rvin_formats[i].fourcc == pixelformat)
1118c2ecf20Sopenharmony_ci			return rvin_formats + i;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	return NULL;
1148c2ecf20Sopenharmony_ci}
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_cistatic u32 rvin_format_bytesperline(struct rvin_dev *vin,
1178c2ecf20Sopenharmony_ci				    struct v4l2_pix_format *pix)
1188c2ecf20Sopenharmony_ci{
1198c2ecf20Sopenharmony_ci	const struct rvin_video_format *fmt;
1208c2ecf20Sopenharmony_ci	u32 align;
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	fmt = rvin_format_from_pixel(vin, pix->pixelformat);
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	if (WARN_ON(!fmt))
1258c2ecf20Sopenharmony_ci		return -EINVAL;
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	switch (pix->pixelformat) {
1288c2ecf20Sopenharmony_ci	case V4L2_PIX_FMT_NV12:
1298c2ecf20Sopenharmony_ci	case V4L2_PIX_FMT_NV16:
1308c2ecf20Sopenharmony_ci		align = 0x20;
1318c2ecf20Sopenharmony_ci		break;
1328c2ecf20Sopenharmony_ci	default:
1338c2ecf20Sopenharmony_ci		align = 0x10;
1348c2ecf20Sopenharmony_ci		break;
1358c2ecf20Sopenharmony_ci	}
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	if (V4L2_FIELD_IS_SEQUENTIAL(pix->field))
1388c2ecf20Sopenharmony_ci		align = 0x80;
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	return ALIGN(pix->width, align) * fmt->bpp;
1418c2ecf20Sopenharmony_ci}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_cistatic u32 rvin_format_sizeimage(struct v4l2_pix_format *pix)
1448c2ecf20Sopenharmony_ci{
1458c2ecf20Sopenharmony_ci	switch (pix->pixelformat) {
1468c2ecf20Sopenharmony_ci	case V4L2_PIX_FMT_NV12:
1478c2ecf20Sopenharmony_ci		return pix->bytesperline * pix->height * 3 / 2;
1488c2ecf20Sopenharmony_ci	case V4L2_PIX_FMT_NV16:
1498c2ecf20Sopenharmony_ci		return pix->bytesperline * pix->height * 2;
1508c2ecf20Sopenharmony_ci	default:
1518c2ecf20Sopenharmony_ci		return pix->bytesperline * pix->height;
1528c2ecf20Sopenharmony_ci	}
1538c2ecf20Sopenharmony_ci}
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_cistatic void rvin_format_align(struct rvin_dev *vin, struct v4l2_pix_format *pix)
1568c2ecf20Sopenharmony_ci{
1578c2ecf20Sopenharmony_ci	u32 walign;
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	if (!rvin_format_from_pixel(vin, pix->pixelformat))
1608c2ecf20Sopenharmony_ci		pix->pixelformat = RVIN_DEFAULT_FORMAT;
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	switch (pix->field) {
1638c2ecf20Sopenharmony_ci	case V4L2_FIELD_TOP:
1648c2ecf20Sopenharmony_ci	case V4L2_FIELD_BOTTOM:
1658c2ecf20Sopenharmony_ci	case V4L2_FIELD_NONE:
1668c2ecf20Sopenharmony_ci	case V4L2_FIELD_INTERLACED_TB:
1678c2ecf20Sopenharmony_ci	case V4L2_FIELD_INTERLACED_BT:
1688c2ecf20Sopenharmony_ci	case V4L2_FIELD_INTERLACED:
1698c2ecf20Sopenharmony_ci	case V4L2_FIELD_ALTERNATE:
1708c2ecf20Sopenharmony_ci	case V4L2_FIELD_SEQ_TB:
1718c2ecf20Sopenharmony_ci	case V4L2_FIELD_SEQ_BT:
1728c2ecf20Sopenharmony_ci		break;
1738c2ecf20Sopenharmony_ci	default:
1748c2ecf20Sopenharmony_ci		pix->field = RVIN_DEFAULT_FIELD;
1758c2ecf20Sopenharmony_ci		break;
1768c2ecf20Sopenharmony_ci	}
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	/* Hardware limits width alignment based on format. */
1798c2ecf20Sopenharmony_ci	switch (pix->pixelformat) {
1808c2ecf20Sopenharmony_ci	/* Multiple of 32 (2^5) for NV12/16. */
1818c2ecf20Sopenharmony_ci	case V4L2_PIX_FMT_NV12:
1828c2ecf20Sopenharmony_ci	case V4L2_PIX_FMT_NV16:
1838c2ecf20Sopenharmony_ci		walign = 5;
1848c2ecf20Sopenharmony_ci		break;
1858c2ecf20Sopenharmony_ci	/* Multiple of 2 (2^1) for YUV. */
1868c2ecf20Sopenharmony_ci	case V4L2_PIX_FMT_YUYV:
1878c2ecf20Sopenharmony_ci	case V4L2_PIX_FMT_UYVY:
1888c2ecf20Sopenharmony_ci		walign = 1;
1898c2ecf20Sopenharmony_ci		break;
1908c2ecf20Sopenharmony_ci	/* No multiple for RGB. */
1918c2ecf20Sopenharmony_ci	default:
1928c2ecf20Sopenharmony_ci		walign = 0;
1938c2ecf20Sopenharmony_ci		break;
1948c2ecf20Sopenharmony_ci	}
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	/* Limit to VIN capabilities */
1978c2ecf20Sopenharmony_ci	v4l_bound_align_image(&pix->width, 5, vin->info->max_width, walign,
1988c2ecf20Sopenharmony_ci			      &pix->height, 2, vin->info->max_height, 0, 0);
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	pix->bytesperline = rvin_format_bytesperline(vin, pix);
2018c2ecf20Sopenharmony_ci	pix->sizeimage = rvin_format_sizeimage(pix);
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	vin_dbg(vin, "Format %ux%u bpl: %u size: %u\n",
2048c2ecf20Sopenharmony_ci		pix->width, pix->height, pix->bytesperline, pix->sizeimage);
2058c2ecf20Sopenharmony_ci}
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci/* -----------------------------------------------------------------------------
2088c2ecf20Sopenharmony_ci * V4L2
2098c2ecf20Sopenharmony_ci */
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_cistatic int rvin_reset_format(struct rvin_dev *vin)
2128c2ecf20Sopenharmony_ci{
2138c2ecf20Sopenharmony_ci	struct v4l2_subdev_format fmt = {
2148c2ecf20Sopenharmony_ci		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
2158c2ecf20Sopenharmony_ci		.pad = vin->parallel->source_pad,
2168c2ecf20Sopenharmony_ci	};
2178c2ecf20Sopenharmony_ci	int ret;
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	ret = v4l2_subdev_call(vin_to_source(vin), pad, get_fmt, NULL, &fmt);
2208c2ecf20Sopenharmony_ci	if (ret)
2218c2ecf20Sopenharmony_ci		return ret;
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	v4l2_fill_pix_format(&vin->format, &fmt.format);
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	vin->src_rect.top = 0;
2268c2ecf20Sopenharmony_ci	vin->src_rect.left = 0;
2278c2ecf20Sopenharmony_ci	vin->src_rect.width = vin->format.width;
2288c2ecf20Sopenharmony_ci	vin->src_rect.height = vin->format.height;
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	/*  Make use of the hardware interlacer by default. */
2318c2ecf20Sopenharmony_ci	if (vin->format.field == V4L2_FIELD_ALTERNATE) {
2328c2ecf20Sopenharmony_ci		vin->format.field = V4L2_FIELD_INTERLACED;
2338c2ecf20Sopenharmony_ci		vin->format.height *= 2;
2348c2ecf20Sopenharmony_ci	}
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	rvin_format_align(vin, &vin->format);
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	vin->crop = vin->src_rect;
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	vin->compose.top = 0;
2418c2ecf20Sopenharmony_ci	vin->compose.left = 0;
2428c2ecf20Sopenharmony_ci	vin->compose.width = vin->format.width;
2438c2ecf20Sopenharmony_ci	vin->compose.height = vin->format.height;
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	return 0;
2468c2ecf20Sopenharmony_ci}
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_cistatic int rvin_try_format(struct rvin_dev *vin, u32 which,
2498c2ecf20Sopenharmony_ci			   struct v4l2_pix_format *pix,
2508c2ecf20Sopenharmony_ci			   struct v4l2_rect *src_rect)
2518c2ecf20Sopenharmony_ci{
2528c2ecf20Sopenharmony_ci	struct v4l2_subdev *sd = vin_to_source(vin);
2538c2ecf20Sopenharmony_ci	struct v4l2_subdev_pad_config *pad_cfg;
2548c2ecf20Sopenharmony_ci	struct v4l2_subdev_format format = {
2558c2ecf20Sopenharmony_ci		.which = which,
2568c2ecf20Sopenharmony_ci		.pad = vin->parallel->source_pad,
2578c2ecf20Sopenharmony_ci	};
2588c2ecf20Sopenharmony_ci	enum v4l2_field field;
2598c2ecf20Sopenharmony_ci	u32 width, height;
2608c2ecf20Sopenharmony_ci	int ret;
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	pad_cfg = v4l2_subdev_alloc_pad_config(sd);
2638c2ecf20Sopenharmony_ci	if (pad_cfg == NULL)
2648c2ecf20Sopenharmony_ci		return -ENOMEM;
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	if (!rvin_format_from_pixel(vin, pix->pixelformat))
2678c2ecf20Sopenharmony_ci		pix->pixelformat = RVIN_DEFAULT_FORMAT;
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	v4l2_fill_mbus_format(&format.format, pix, vin->mbus_code);
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	/* Allow the video device to override field and to scale */
2728c2ecf20Sopenharmony_ci	field = pix->field;
2738c2ecf20Sopenharmony_ci	width = pix->width;
2748c2ecf20Sopenharmony_ci	height = pix->height;
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	ret = v4l2_subdev_call(sd, pad, set_fmt, pad_cfg, &format);
2778c2ecf20Sopenharmony_ci	if (ret < 0 && ret != -ENOIOCTLCMD)
2788c2ecf20Sopenharmony_ci		goto done;
2798c2ecf20Sopenharmony_ci	ret = 0;
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	v4l2_fill_pix_format(pix, &format.format);
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	if (src_rect) {
2848c2ecf20Sopenharmony_ci		src_rect->top = 0;
2858c2ecf20Sopenharmony_ci		src_rect->left = 0;
2868c2ecf20Sopenharmony_ci		src_rect->width = pix->width;
2878c2ecf20Sopenharmony_ci		src_rect->height = pix->height;
2888c2ecf20Sopenharmony_ci	}
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	if (field != V4L2_FIELD_ANY)
2918c2ecf20Sopenharmony_ci		pix->field = field;
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	pix->width = width;
2948c2ecf20Sopenharmony_ci	pix->height = height;
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	rvin_format_align(vin, pix);
2978c2ecf20Sopenharmony_cidone:
2988c2ecf20Sopenharmony_ci	v4l2_subdev_free_pad_config(pad_cfg);
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	return ret;
3018c2ecf20Sopenharmony_ci}
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_cistatic int rvin_querycap(struct file *file, void *priv,
3048c2ecf20Sopenharmony_ci			 struct v4l2_capability *cap)
3058c2ecf20Sopenharmony_ci{
3068c2ecf20Sopenharmony_ci	struct rvin_dev *vin = video_drvdata(file);
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
3098c2ecf20Sopenharmony_ci	strscpy(cap->card, "R_Car_VIN", sizeof(cap->card));
3108c2ecf20Sopenharmony_ci	snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
3118c2ecf20Sopenharmony_ci		 dev_name(vin->dev));
3128c2ecf20Sopenharmony_ci	return 0;
3138c2ecf20Sopenharmony_ci}
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_cistatic int rvin_try_fmt_vid_cap(struct file *file, void *priv,
3168c2ecf20Sopenharmony_ci				struct v4l2_format *f)
3178c2ecf20Sopenharmony_ci{
3188c2ecf20Sopenharmony_ci	struct rvin_dev *vin = video_drvdata(file);
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	return rvin_try_format(vin, V4L2_SUBDEV_FORMAT_TRY, &f->fmt.pix, NULL);
3218c2ecf20Sopenharmony_ci}
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_cistatic int rvin_s_fmt_vid_cap(struct file *file, void *priv,
3248c2ecf20Sopenharmony_ci			      struct v4l2_format *f)
3258c2ecf20Sopenharmony_ci{
3268c2ecf20Sopenharmony_ci	struct rvin_dev *vin = video_drvdata(file);
3278c2ecf20Sopenharmony_ci	struct v4l2_rect fmt_rect, src_rect;
3288c2ecf20Sopenharmony_ci	int ret;
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	if (vb2_is_busy(&vin->queue))
3318c2ecf20Sopenharmony_ci		return -EBUSY;
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	ret = rvin_try_format(vin, V4L2_SUBDEV_FORMAT_ACTIVE, &f->fmt.pix,
3348c2ecf20Sopenharmony_ci			      &src_rect);
3358c2ecf20Sopenharmony_ci	if (ret)
3368c2ecf20Sopenharmony_ci		return ret;
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	vin->format = f->fmt.pix;
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	fmt_rect.top = 0;
3418c2ecf20Sopenharmony_ci	fmt_rect.left = 0;
3428c2ecf20Sopenharmony_ci	fmt_rect.width = vin->format.width;
3438c2ecf20Sopenharmony_ci	fmt_rect.height = vin->format.height;
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	v4l2_rect_map_inside(&vin->crop, &src_rect);
3468c2ecf20Sopenharmony_ci	v4l2_rect_map_inside(&vin->compose, &fmt_rect);
3478c2ecf20Sopenharmony_ci	vin->src_rect = src_rect;
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	return 0;
3508c2ecf20Sopenharmony_ci}
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_cistatic int rvin_g_fmt_vid_cap(struct file *file, void *priv,
3538c2ecf20Sopenharmony_ci			      struct v4l2_format *f)
3548c2ecf20Sopenharmony_ci{
3558c2ecf20Sopenharmony_ci	struct rvin_dev *vin = video_drvdata(file);
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	f->fmt.pix = vin->format;
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	return 0;
3608c2ecf20Sopenharmony_ci}
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_cistatic int rvin_enum_fmt_vid_cap(struct file *file, void *priv,
3638c2ecf20Sopenharmony_ci				 struct v4l2_fmtdesc *f)
3648c2ecf20Sopenharmony_ci{
3658c2ecf20Sopenharmony_ci	struct rvin_dev *vin = video_drvdata(file);
3668c2ecf20Sopenharmony_ci	unsigned int i;
3678c2ecf20Sopenharmony_ci	int matched;
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	/*
3708c2ecf20Sopenharmony_ci	 * If mbus_code is set only enumerate supported pixel formats for that
3718c2ecf20Sopenharmony_ci	 * bus code. Converting from YCbCr to RGB and RGB to YCbCr is possible
3728c2ecf20Sopenharmony_ci	 * with VIN, so all supported YCbCr and RGB media bus codes can produce
3738c2ecf20Sopenharmony_ci	 * all of the related pixel formats. If mbus_code is not set enumerate
3748c2ecf20Sopenharmony_ci	 * all possible pixelformats.
3758c2ecf20Sopenharmony_ci	 *
3768c2ecf20Sopenharmony_ci	 * TODO: Once raw MEDIA_BUS_FMT_SRGGB12_1X12 format is added to the
3778c2ecf20Sopenharmony_ci	 * driver this needs to be extended so raw media bus code only result in
3788c2ecf20Sopenharmony_ci	 * raw pixel format.
3798c2ecf20Sopenharmony_ci	 */
3808c2ecf20Sopenharmony_ci	switch (f->mbus_code) {
3818c2ecf20Sopenharmony_ci	case 0:
3828c2ecf20Sopenharmony_ci	case MEDIA_BUS_FMT_YUYV8_1X16:
3838c2ecf20Sopenharmony_ci	case MEDIA_BUS_FMT_UYVY8_1X16:
3848c2ecf20Sopenharmony_ci	case MEDIA_BUS_FMT_UYVY8_2X8:
3858c2ecf20Sopenharmony_ci	case MEDIA_BUS_FMT_UYVY10_2X10:
3868c2ecf20Sopenharmony_ci	case MEDIA_BUS_FMT_RGB888_1X24:
3878c2ecf20Sopenharmony_ci		break;
3888c2ecf20Sopenharmony_ci	case MEDIA_BUS_FMT_SBGGR8_1X8:
3898c2ecf20Sopenharmony_ci		if (f->index)
3908c2ecf20Sopenharmony_ci			return -EINVAL;
3918c2ecf20Sopenharmony_ci		f->pixelformat = V4L2_PIX_FMT_SBGGR8;
3928c2ecf20Sopenharmony_ci		return 0;
3938c2ecf20Sopenharmony_ci	case MEDIA_BUS_FMT_SGBRG8_1X8:
3948c2ecf20Sopenharmony_ci		if (f->index)
3958c2ecf20Sopenharmony_ci			return -EINVAL;
3968c2ecf20Sopenharmony_ci		f->pixelformat = V4L2_PIX_FMT_SGBRG8;
3978c2ecf20Sopenharmony_ci		return 0;
3988c2ecf20Sopenharmony_ci	case MEDIA_BUS_FMT_SGRBG8_1X8:
3998c2ecf20Sopenharmony_ci		if (f->index)
4008c2ecf20Sopenharmony_ci			return -EINVAL;
4018c2ecf20Sopenharmony_ci		f->pixelformat = V4L2_PIX_FMT_SGRBG8;
4028c2ecf20Sopenharmony_ci		return 0;
4038c2ecf20Sopenharmony_ci	case MEDIA_BUS_FMT_SRGGB8_1X8:
4048c2ecf20Sopenharmony_ci		if (f->index)
4058c2ecf20Sopenharmony_ci			return -EINVAL;
4068c2ecf20Sopenharmony_ci		f->pixelformat = V4L2_PIX_FMT_SRGGB8;
4078c2ecf20Sopenharmony_ci		return 0;
4088c2ecf20Sopenharmony_ci	default:
4098c2ecf20Sopenharmony_ci		return -EINVAL;
4108c2ecf20Sopenharmony_ci	}
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	matched = -1;
4138c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(rvin_formats); i++) {
4148c2ecf20Sopenharmony_ci		if (rvin_format_from_pixel(vin, rvin_formats[i].fourcc))
4158c2ecf20Sopenharmony_ci			matched++;
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci		if (matched == f->index) {
4188c2ecf20Sopenharmony_ci			f->pixelformat = rvin_formats[i].fourcc;
4198c2ecf20Sopenharmony_ci			return 0;
4208c2ecf20Sopenharmony_ci		}
4218c2ecf20Sopenharmony_ci	}
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	return -EINVAL;
4248c2ecf20Sopenharmony_ci}
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_cistatic int rvin_g_selection(struct file *file, void *fh,
4278c2ecf20Sopenharmony_ci			    struct v4l2_selection *s)
4288c2ecf20Sopenharmony_ci{
4298c2ecf20Sopenharmony_ci	struct rvin_dev *vin = video_drvdata(file);
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
4328c2ecf20Sopenharmony_ci		return -EINVAL;
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	switch (s->target) {
4358c2ecf20Sopenharmony_ci	case V4L2_SEL_TGT_CROP_BOUNDS:
4368c2ecf20Sopenharmony_ci	case V4L2_SEL_TGT_CROP_DEFAULT:
4378c2ecf20Sopenharmony_ci		s->r.left = s->r.top = 0;
4388c2ecf20Sopenharmony_ci		s->r.width = vin->src_rect.width;
4398c2ecf20Sopenharmony_ci		s->r.height = vin->src_rect.height;
4408c2ecf20Sopenharmony_ci		break;
4418c2ecf20Sopenharmony_ci	case V4L2_SEL_TGT_CROP:
4428c2ecf20Sopenharmony_ci		s->r = vin->crop;
4438c2ecf20Sopenharmony_ci		break;
4448c2ecf20Sopenharmony_ci	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
4458c2ecf20Sopenharmony_ci	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
4468c2ecf20Sopenharmony_ci		s->r.left = s->r.top = 0;
4478c2ecf20Sopenharmony_ci		s->r.width = vin->format.width;
4488c2ecf20Sopenharmony_ci		s->r.height = vin->format.height;
4498c2ecf20Sopenharmony_ci		break;
4508c2ecf20Sopenharmony_ci	case V4L2_SEL_TGT_COMPOSE:
4518c2ecf20Sopenharmony_ci		s->r = vin->compose;
4528c2ecf20Sopenharmony_ci		break;
4538c2ecf20Sopenharmony_ci	default:
4548c2ecf20Sopenharmony_ci		return -EINVAL;
4558c2ecf20Sopenharmony_ci	}
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	return 0;
4588c2ecf20Sopenharmony_ci}
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_cistatic int rvin_s_selection(struct file *file, void *fh,
4618c2ecf20Sopenharmony_ci			    struct v4l2_selection *s)
4628c2ecf20Sopenharmony_ci{
4638c2ecf20Sopenharmony_ci	struct rvin_dev *vin = video_drvdata(file);
4648c2ecf20Sopenharmony_ci	const struct rvin_video_format *fmt;
4658c2ecf20Sopenharmony_ci	struct v4l2_rect r = s->r;
4668c2ecf20Sopenharmony_ci	struct v4l2_rect max_rect;
4678c2ecf20Sopenharmony_ci	struct v4l2_rect min_rect = {
4688c2ecf20Sopenharmony_ci		.width = 6,
4698c2ecf20Sopenharmony_ci		.height = 2,
4708c2ecf20Sopenharmony_ci	};
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
4738c2ecf20Sopenharmony_ci		return -EINVAL;
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	v4l2_rect_set_min_size(&r, &min_rect);
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	switch (s->target) {
4788c2ecf20Sopenharmony_ci	case V4L2_SEL_TGT_CROP:
4798c2ecf20Sopenharmony_ci		/* Can't crop outside of source input */
4808c2ecf20Sopenharmony_ci		max_rect.top = max_rect.left = 0;
4818c2ecf20Sopenharmony_ci		max_rect.width = vin->src_rect.width;
4828c2ecf20Sopenharmony_ci		max_rect.height = vin->src_rect.height;
4838c2ecf20Sopenharmony_ci		v4l2_rect_map_inside(&r, &max_rect);
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci		v4l_bound_align_image(&r.width, 6, vin->src_rect.width, 0,
4868c2ecf20Sopenharmony_ci				      &r.height, 2, vin->src_rect.height, 0, 0);
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci		r.top  = clamp_t(s32, r.top, 0,
4898c2ecf20Sopenharmony_ci				 vin->src_rect.height - r.height);
4908c2ecf20Sopenharmony_ci		r.left = clamp_t(s32, r.left, 0, vin->src_rect.width - r.width);
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci		vin->crop = s->r = r;
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci		vin_dbg(vin, "Cropped %dx%d@%d:%d of %dx%d\n",
4958c2ecf20Sopenharmony_ci			r.width, r.height, r.left, r.top,
4968c2ecf20Sopenharmony_ci			vin->src_rect.width, vin->src_rect.height);
4978c2ecf20Sopenharmony_ci		break;
4988c2ecf20Sopenharmony_ci	case V4L2_SEL_TGT_COMPOSE:
4998c2ecf20Sopenharmony_ci		/* Make sure compose rect fits inside output format */
5008c2ecf20Sopenharmony_ci		max_rect.top = max_rect.left = 0;
5018c2ecf20Sopenharmony_ci		max_rect.width = vin->format.width;
5028c2ecf20Sopenharmony_ci		max_rect.height = vin->format.height;
5038c2ecf20Sopenharmony_ci		v4l2_rect_map_inside(&r, &max_rect);
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci		/*
5068c2ecf20Sopenharmony_ci		 * Composing is done by adding a offset to the buffer address,
5078c2ecf20Sopenharmony_ci		 * the HW wants this address to be aligned to HW_BUFFER_MASK.
5088c2ecf20Sopenharmony_ci		 * Make sure the top and left values meets this requirement.
5098c2ecf20Sopenharmony_ci		 */
5108c2ecf20Sopenharmony_ci		while ((r.top * vin->format.bytesperline) & HW_BUFFER_MASK)
5118c2ecf20Sopenharmony_ci			r.top--;
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci		fmt = rvin_format_from_pixel(vin, vin->format.pixelformat);
5148c2ecf20Sopenharmony_ci		while ((r.left * fmt->bpp) & HW_BUFFER_MASK)
5158c2ecf20Sopenharmony_ci			r.left--;
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci		vin->compose = s->r = r;
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci		vin_dbg(vin, "Compose %dx%d@%d:%d in %dx%d\n",
5208c2ecf20Sopenharmony_ci			r.width, r.height, r.left, r.top,
5218c2ecf20Sopenharmony_ci			vin->format.width, vin->format.height);
5228c2ecf20Sopenharmony_ci		break;
5238c2ecf20Sopenharmony_ci	default:
5248c2ecf20Sopenharmony_ci		return -EINVAL;
5258c2ecf20Sopenharmony_ci	}
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci	/* HW supports modifying configuration while running */
5288c2ecf20Sopenharmony_ci	rvin_crop_scale_comp(vin);
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci	return 0;
5318c2ecf20Sopenharmony_ci}
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_cistatic int rvin_g_pixelaspect(struct file *file, void *priv,
5348c2ecf20Sopenharmony_ci			      int type, struct v4l2_fract *f)
5358c2ecf20Sopenharmony_ci{
5368c2ecf20Sopenharmony_ci	struct rvin_dev *vin = video_drvdata(file);
5378c2ecf20Sopenharmony_ci	struct v4l2_subdev *sd = vin_to_source(vin);
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci	if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
5408c2ecf20Sopenharmony_ci		return -EINVAL;
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ci	return v4l2_subdev_call(sd, video, g_pixelaspect, f);
5438c2ecf20Sopenharmony_ci}
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_cistatic int rvin_enum_input(struct file *file, void *priv,
5468c2ecf20Sopenharmony_ci			   struct v4l2_input *i)
5478c2ecf20Sopenharmony_ci{
5488c2ecf20Sopenharmony_ci	struct rvin_dev *vin = video_drvdata(file);
5498c2ecf20Sopenharmony_ci	struct v4l2_subdev *sd = vin_to_source(vin);
5508c2ecf20Sopenharmony_ci	int ret;
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	if (i->index != 0)
5538c2ecf20Sopenharmony_ci		return -EINVAL;
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci	ret = v4l2_subdev_call(sd, video, g_input_status, &i->status);
5568c2ecf20Sopenharmony_ci	if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV)
5578c2ecf20Sopenharmony_ci		return ret;
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	i->type = V4L2_INPUT_TYPE_CAMERA;
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci	if (v4l2_subdev_has_op(sd, pad, dv_timings_cap)) {
5628c2ecf20Sopenharmony_ci		i->capabilities = V4L2_IN_CAP_DV_TIMINGS;
5638c2ecf20Sopenharmony_ci		i->std = 0;
5648c2ecf20Sopenharmony_ci	} else {
5658c2ecf20Sopenharmony_ci		i->capabilities = V4L2_IN_CAP_STD;
5668c2ecf20Sopenharmony_ci		i->std = vin->vdev.tvnorms;
5678c2ecf20Sopenharmony_ci	}
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci	strscpy(i->name, "Camera", sizeof(i->name));
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci	return 0;
5728c2ecf20Sopenharmony_ci}
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_cistatic int rvin_g_input(struct file *file, void *priv, unsigned int *i)
5758c2ecf20Sopenharmony_ci{
5768c2ecf20Sopenharmony_ci	*i = 0;
5778c2ecf20Sopenharmony_ci	return 0;
5788c2ecf20Sopenharmony_ci}
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_cistatic int rvin_s_input(struct file *file, void *priv, unsigned int i)
5818c2ecf20Sopenharmony_ci{
5828c2ecf20Sopenharmony_ci	if (i > 0)
5838c2ecf20Sopenharmony_ci		return -EINVAL;
5848c2ecf20Sopenharmony_ci	return 0;
5858c2ecf20Sopenharmony_ci}
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_cistatic int rvin_querystd(struct file *file, void *priv, v4l2_std_id *a)
5888c2ecf20Sopenharmony_ci{
5898c2ecf20Sopenharmony_ci	struct rvin_dev *vin = video_drvdata(file);
5908c2ecf20Sopenharmony_ci	struct v4l2_subdev *sd = vin_to_source(vin);
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	return v4l2_subdev_call(sd, video, querystd, a);
5938c2ecf20Sopenharmony_ci}
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_cistatic int rvin_s_std(struct file *file, void *priv, v4l2_std_id a)
5968c2ecf20Sopenharmony_ci{
5978c2ecf20Sopenharmony_ci	struct rvin_dev *vin = video_drvdata(file);
5988c2ecf20Sopenharmony_ci	int ret;
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci	ret = v4l2_subdev_call(vin_to_source(vin), video, s_std, a);
6018c2ecf20Sopenharmony_ci	if (ret < 0)
6028c2ecf20Sopenharmony_ci		return ret;
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_ci	vin->std = a;
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	/* Changing the standard will change the width/height */
6078c2ecf20Sopenharmony_ci	return rvin_reset_format(vin);
6088c2ecf20Sopenharmony_ci}
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_cistatic int rvin_g_std(struct file *file, void *priv, v4l2_std_id *a)
6118c2ecf20Sopenharmony_ci{
6128c2ecf20Sopenharmony_ci	struct rvin_dev *vin = video_drvdata(file);
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci	if (v4l2_subdev_has_op(vin_to_source(vin), pad, dv_timings_cap))
6158c2ecf20Sopenharmony_ci		return -ENOIOCTLCMD;
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ci	*a = vin->std;
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci	return 0;
6208c2ecf20Sopenharmony_ci}
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_cistatic int rvin_subscribe_event(struct v4l2_fh *fh,
6238c2ecf20Sopenharmony_ci				const struct v4l2_event_subscription *sub)
6248c2ecf20Sopenharmony_ci{
6258c2ecf20Sopenharmony_ci	switch (sub->type) {
6268c2ecf20Sopenharmony_ci	case V4L2_EVENT_SOURCE_CHANGE:
6278c2ecf20Sopenharmony_ci		return v4l2_event_subscribe(fh, sub, 4, NULL);
6288c2ecf20Sopenharmony_ci	}
6298c2ecf20Sopenharmony_ci	return v4l2_ctrl_subscribe_event(fh, sub);
6308c2ecf20Sopenharmony_ci}
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_cistatic int rvin_enum_dv_timings(struct file *file, void *priv_fh,
6338c2ecf20Sopenharmony_ci				struct v4l2_enum_dv_timings *timings)
6348c2ecf20Sopenharmony_ci{
6358c2ecf20Sopenharmony_ci	struct rvin_dev *vin = video_drvdata(file);
6368c2ecf20Sopenharmony_ci	struct v4l2_subdev *sd = vin_to_source(vin);
6378c2ecf20Sopenharmony_ci	int ret;
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_ci	if (timings->pad)
6408c2ecf20Sopenharmony_ci		return -EINVAL;
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci	timings->pad = vin->parallel->sink_pad;
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_ci	ret = v4l2_subdev_call(sd, pad, enum_dv_timings, timings);
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_ci	timings->pad = 0;
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci	return ret;
6498c2ecf20Sopenharmony_ci}
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_cistatic int rvin_s_dv_timings(struct file *file, void *priv_fh,
6528c2ecf20Sopenharmony_ci			     struct v4l2_dv_timings *timings)
6538c2ecf20Sopenharmony_ci{
6548c2ecf20Sopenharmony_ci	struct rvin_dev *vin = video_drvdata(file);
6558c2ecf20Sopenharmony_ci	struct v4l2_subdev *sd = vin_to_source(vin);
6568c2ecf20Sopenharmony_ci	int ret;
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_ci	ret = v4l2_subdev_call(sd, video, s_dv_timings, timings);
6598c2ecf20Sopenharmony_ci	if (ret)
6608c2ecf20Sopenharmony_ci		return ret;
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_ci	/* Changing the timings will change the width/height */
6638c2ecf20Sopenharmony_ci	return rvin_reset_format(vin);
6648c2ecf20Sopenharmony_ci}
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_cistatic int rvin_g_dv_timings(struct file *file, void *priv_fh,
6678c2ecf20Sopenharmony_ci			     struct v4l2_dv_timings *timings)
6688c2ecf20Sopenharmony_ci{
6698c2ecf20Sopenharmony_ci	struct rvin_dev *vin = video_drvdata(file);
6708c2ecf20Sopenharmony_ci	struct v4l2_subdev *sd = vin_to_source(vin);
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	return v4l2_subdev_call(sd, video, g_dv_timings, timings);
6738c2ecf20Sopenharmony_ci}
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_cistatic int rvin_query_dv_timings(struct file *file, void *priv_fh,
6768c2ecf20Sopenharmony_ci				 struct v4l2_dv_timings *timings)
6778c2ecf20Sopenharmony_ci{
6788c2ecf20Sopenharmony_ci	struct rvin_dev *vin = video_drvdata(file);
6798c2ecf20Sopenharmony_ci	struct v4l2_subdev *sd = vin_to_source(vin);
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_ci	return v4l2_subdev_call(sd, video, query_dv_timings, timings);
6828c2ecf20Sopenharmony_ci}
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_cistatic int rvin_dv_timings_cap(struct file *file, void *priv_fh,
6858c2ecf20Sopenharmony_ci			       struct v4l2_dv_timings_cap *cap)
6868c2ecf20Sopenharmony_ci{
6878c2ecf20Sopenharmony_ci	struct rvin_dev *vin = video_drvdata(file);
6888c2ecf20Sopenharmony_ci	struct v4l2_subdev *sd = vin_to_source(vin);
6898c2ecf20Sopenharmony_ci	int ret;
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci	if (cap->pad)
6928c2ecf20Sopenharmony_ci		return -EINVAL;
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_ci	cap->pad = vin->parallel->sink_pad;
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci	ret = v4l2_subdev_call(sd, pad, dv_timings_cap, cap);
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci	cap->pad = 0;
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci	return ret;
7018c2ecf20Sopenharmony_ci}
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_cistatic int rvin_g_edid(struct file *file, void *fh, struct v4l2_edid *edid)
7048c2ecf20Sopenharmony_ci{
7058c2ecf20Sopenharmony_ci	struct rvin_dev *vin = video_drvdata(file);
7068c2ecf20Sopenharmony_ci	struct v4l2_subdev *sd = vin_to_source(vin);
7078c2ecf20Sopenharmony_ci	int ret;
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci	if (edid->pad)
7108c2ecf20Sopenharmony_ci		return -EINVAL;
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci	edid->pad = vin->parallel->sink_pad;
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci	ret = v4l2_subdev_call(sd, pad, get_edid, edid);
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_ci	edid->pad = 0;
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci	return ret;
7198c2ecf20Sopenharmony_ci}
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_cistatic int rvin_s_edid(struct file *file, void *fh, struct v4l2_edid *edid)
7228c2ecf20Sopenharmony_ci{
7238c2ecf20Sopenharmony_ci	struct rvin_dev *vin = video_drvdata(file);
7248c2ecf20Sopenharmony_ci	struct v4l2_subdev *sd = vin_to_source(vin);
7258c2ecf20Sopenharmony_ci	int ret;
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci	if (edid->pad)
7288c2ecf20Sopenharmony_ci		return -EINVAL;
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_ci	edid->pad = vin->parallel->sink_pad;
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci	ret = v4l2_subdev_call(sd, pad, set_edid, edid);
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ci	edid->pad = 0;
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci	return ret;
7378c2ecf20Sopenharmony_ci}
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_cistatic const struct v4l2_ioctl_ops rvin_ioctl_ops = {
7408c2ecf20Sopenharmony_ci	.vidioc_querycap		= rvin_querycap,
7418c2ecf20Sopenharmony_ci	.vidioc_try_fmt_vid_cap		= rvin_try_fmt_vid_cap,
7428c2ecf20Sopenharmony_ci	.vidioc_g_fmt_vid_cap		= rvin_g_fmt_vid_cap,
7438c2ecf20Sopenharmony_ci	.vidioc_s_fmt_vid_cap		= rvin_s_fmt_vid_cap,
7448c2ecf20Sopenharmony_ci	.vidioc_enum_fmt_vid_cap	= rvin_enum_fmt_vid_cap,
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci	.vidioc_g_selection		= rvin_g_selection,
7478c2ecf20Sopenharmony_ci	.vidioc_s_selection		= rvin_s_selection,
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ci	.vidioc_g_pixelaspect		= rvin_g_pixelaspect,
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci	.vidioc_enum_input		= rvin_enum_input,
7528c2ecf20Sopenharmony_ci	.vidioc_g_input			= rvin_g_input,
7538c2ecf20Sopenharmony_ci	.vidioc_s_input			= rvin_s_input,
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_ci	.vidioc_dv_timings_cap		= rvin_dv_timings_cap,
7568c2ecf20Sopenharmony_ci	.vidioc_enum_dv_timings		= rvin_enum_dv_timings,
7578c2ecf20Sopenharmony_ci	.vidioc_g_dv_timings		= rvin_g_dv_timings,
7588c2ecf20Sopenharmony_ci	.vidioc_s_dv_timings		= rvin_s_dv_timings,
7598c2ecf20Sopenharmony_ci	.vidioc_query_dv_timings	= rvin_query_dv_timings,
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci	.vidioc_g_edid			= rvin_g_edid,
7628c2ecf20Sopenharmony_ci	.vidioc_s_edid			= rvin_s_edid,
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_ci	.vidioc_querystd		= rvin_querystd,
7658c2ecf20Sopenharmony_ci	.vidioc_g_std			= rvin_g_std,
7668c2ecf20Sopenharmony_ci	.vidioc_s_std			= rvin_s_std,
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_ci	.vidioc_reqbufs			= vb2_ioctl_reqbufs,
7698c2ecf20Sopenharmony_ci	.vidioc_create_bufs		= vb2_ioctl_create_bufs,
7708c2ecf20Sopenharmony_ci	.vidioc_querybuf		= vb2_ioctl_querybuf,
7718c2ecf20Sopenharmony_ci	.vidioc_qbuf			= vb2_ioctl_qbuf,
7728c2ecf20Sopenharmony_ci	.vidioc_dqbuf			= vb2_ioctl_dqbuf,
7738c2ecf20Sopenharmony_ci	.vidioc_expbuf			= vb2_ioctl_expbuf,
7748c2ecf20Sopenharmony_ci	.vidioc_prepare_buf		= vb2_ioctl_prepare_buf,
7758c2ecf20Sopenharmony_ci	.vidioc_streamon		= vb2_ioctl_streamon,
7768c2ecf20Sopenharmony_ci	.vidioc_streamoff		= vb2_ioctl_streamoff,
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci	.vidioc_log_status		= v4l2_ctrl_log_status,
7798c2ecf20Sopenharmony_ci	.vidioc_subscribe_event		= rvin_subscribe_event,
7808c2ecf20Sopenharmony_ci	.vidioc_unsubscribe_event	= v4l2_event_unsubscribe,
7818c2ecf20Sopenharmony_ci};
7828c2ecf20Sopenharmony_ci
7838c2ecf20Sopenharmony_ci/* -----------------------------------------------------------------------------
7848c2ecf20Sopenharmony_ci * V4L2 Media Controller
7858c2ecf20Sopenharmony_ci */
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_cistatic void rvin_mc_try_format(struct rvin_dev *vin,
7888c2ecf20Sopenharmony_ci			       struct v4l2_pix_format *pix)
7898c2ecf20Sopenharmony_ci{
7908c2ecf20Sopenharmony_ci	/*
7918c2ecf20Sopenharmony_ci	 * The V4L2 specification clearly documents the colorspace fields
7928c2ecf20Sopenharmony_ci	 * as being set by drivers for capture devices. Using the values
7938c2ecf20Sopenharmony_ci	 * supplied by userspace thus wouldn't comply with the API. Until
7948c2ecf20Sopenharmony_ci	 * the API is updated force fixed values.
7958c2ecf20Sopenharmony_ci	 */
7968c2ecf20Sopenharmony_ci	pix->colorspace = RVIN_DEFAULT_COLORSPACE;
7978c2ecf20Sopenharmony_ci	pix->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(pix->colorspace);
7988c2ecf20Sopenharmony_ci	pix->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(pix->colorspace);
7998c2ecf20Sopenharmony_ci	pix->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true, pix->colorspace,
8008c2ecf20Sopenharmony_ci							  pix->ycbcr_enc);
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_ci	rvin_format_align(vin, pix);
8038c2ecf20Sopenharmony_ci}
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_cistatic int rvin_mc_try_fmt_vid_cap(struct file *file, void *priv,
8068c2ecf20Sopenharmony_ci				   struct v4l2_format *f)
8078c2ecf20Sopenharmony_ci{
8088c2ecf20Sopenharmony_ci	struct rvin_dev *vin = video_drvdata(file);
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_ci	rvin_mc_try_format(vin, &f->fmt.pix);
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_ci	return 0;
8138c2ecf20Sopenharmony_ci}
8148c2ecf20Sopenharmony_ci
8158c2ecf20Sopenharmony_cistatic int rvin_mc_s_fmt_vid_cap(struct file *file, void *priv,
8168c2ecf20Sopenharmony_ci				 struct v4l2_format *f)
8178c2ecf20Sopenharmony_ci{
8188c2ecf20Sopenharmony_ci	struct rvin_dev *vin = video_drvdata(file);
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_ci	if (vb2_is_busy(&vin->queue))
8218c2ecf20Sopenharmony_ci		return -EBUSY;
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci	rvin_mc_try_format(vin, &f->fmt.pix);
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci	vin->format = f->fmt.pix;
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_ci	vin->crop.top = 0;
8288c2ecf20Sopenharmony_ci	vin->crop.left = 0;
8298c2ecf20Sopenharmony_ci	vin->crop.width = vin->format.width;
8308c2ecf20Sopenharmony_ci	vin->crop.height = vin->format.height;
8318c2ecf20Sopenharmony_ci	vin->compose = vin->crop;
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_ci	return 0;
8348c2ecf20Sopenharmony_ci}
8358c2ecf20Sopenharmony_ci
8368c2ecf20Sopenharmony_cistatic const struct v4l2_ioctl_ops rvin_mc_ioctl_ops = {
8378c2ecf20Sopenharmony_ci	.vidioc_querycap		= rvin_querycap,
8388c2ecf20Sopenharmony_ci	.vidioc_try_fmt_vid_cap		= rvin_mc_try_fmt_vid_cap,
8398c2ecf20Sopenharmony_ci	.vidioc_g_fmt_vid_cap		= rvin_g_fmt_vid_cap,
8408c2ecf20Sopenharmony_ci	.vidioc_s_fmt_vid_cap		= rvin_mc_s_fmt_vid_cap,
8418c2ecf20Sopenharmony_ci	.vidioc_enum_fmt_vid_cap	= rvin_enum_fmt_vid_cap,
8428c2ecf20Sopenharmony_ci
8438c2ecf20Sopenharmony_ci	.vidioc_reqbufs			= vb2_ioctl_reqbufs,
8448c2ecf20Sopenharmony_ci	.vidioc_create_bufs		= vb2_ioctl_create_bufs,
8458c2ecf20Sopenharmony_ci	.vidioc_querybuf		= vb2_ioctl_querybuf,
8468c2ecf20Sopenharmony_ci	.vidioc_qbuf			= vb2_ioctl_qbuf,
8478c2ecf20Sopenharmony_ci	.vidioc_dqbuf			= vb2_ioctl_dqbuf,
8488c2ecf20Sopenharmony_ci	.vidioc_expbuf			= vb2_ioctl_expbuf,
8498c2ecf20Sopenharmony_ci	.vidioc_prepare_buf		= vb2_ioctl_prepare_buf,
8508c2ecf20Sopenharmony_ci	.vidioc_streamon		= vb2_ioctl_streamon,
8518c2ecf20Sopenharmony_ci	.vidioc_streamoff		= vb2_ioctl_streamoff,
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_ci	.vidioc_log_status		= v4l2_ctrl_log_status,
8548c2ecf20Sopenharmony_ci	.vidioc_subscribe_event		= rvin_subscribe_event,
8558c2ecf20Sopenharmony_ci	.vidioc_unsubscribe_event	= v4l2_event_unsubscribe,
8568c2ecf20Sopenharmony_ci};
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_ci/* -----------------------------------------------------------------------------
8598c2ecf20Sopenharmony_ci * File Operations
8608c2ecf20Sopenharmony_ci */
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_cistatic int rvin_power_parallel(struct rvin_dev *vin, bool on)
8638c2ecf20Sopenharmony_ci{
8648c2ecf20Sopenharmony_ci	struct v4l2_subdev *sd = vin_to_source(vin);
8658c2ecf20Sopenharmony_ci	int power = on ? 1 : 0;
8668c2ecf20Sopenharmony_ci	int ret;
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_ci	ret = v4l2_subdev_call(sd, core, s_power, power);
8698c2ecf20Sopenharmony_ci	if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV)
8708c2ecf20Sopenharmony_ci		return ret;
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_ci	return 0;
8738c2ecf20Sopenharmony_ci}
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_cistatic int rvin_open(struct file *file)
8768c2ecf20Sopenharmony_ci{
8778c2ecf20Sopenharmony_ci	struct rvin_dev *vin = video_drvdata(file);
8788c2ecf20Sopenharmony_ci	int ret;
8798c2ecf20Sopenharmony_ci
8808c2ecf20Sopenharmony_ci	ret = pm_runtime_get_sync(vin->dev);
8818c2ecf20Sopenharmony_ci	if (ret < 0) {
8828c2ecf20Sopenharmony_ci		pm_runtime_put_noidle(vin->dev);
8838c2ecf20Sopenharmony_ci		return ret;
8848c2ecf20Sopenharmony_ci	}
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_ci	ret = mutex_lock_interruptible(&vin->lock);
8878c2ecf20Sopenharmony_ci	if (ret)
8888c2ecf20Sopenharmony_ci		goto err_pm;
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_ci	file->private_data = vin;
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ci	ret = v4l2_fh_open(file);
8938c2ecf20Sopenharmony_ci	if (ret)
8948c2ecf20Sopenharmony_ci		goto err_unlock;
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_ci	if (vin->info->use_mc)
8978c2ecf20Sopenharmony_ci		ret = v4l2_pipeline_pm_get(&vin->vdev.entity);
8988c2ecf20Sopenharmony_ci	else if (v4l2_fh_is_singular_file(file))
8998c2ecf20Sopenharmony_ci		ret = rvin_power_parallel(vin, true);
9008c2ecf20Sopenharmony_ci
9018c2ecf20Sopenharmony_ci	if (ret < 0)
9028c2ecf20Sopenharmony_ci		goto err_open;
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_ci	ret = v4l2_ctrl_handler_setup(&vin->ctrl_handler);
9058c2ecf20Sopenharmony_ci	if (ret)
9068c2ecf20Sopenharmony_ci		goto err_power;
9078c2ecf20Sopenharmony_ci
9088c2ecf20Sopenharmony_ci	mutex_unlock(&vin->lock);
9098c2ecf20Sopenharmony_ci
9108c2ecf20Sopenharmony_ci	return 0;
9118c2ecf20Sopenharmony_cierr_power:
9128c2ecf20Sopenharmony_ci	if (vin->info->use_mc)
9138c2ecf20Sopenharmony_ci		v4l2_pipeline_pm_put(&vin->vdev.entity);
9148c2ecf20Sopenharmony_ci	else if (v4l2_fh_is_singular_file(file))
9158c2ecf20Sopenharmony_ci		rvin_power_parallel(vin, false);
9168c2ecf20Sopenharmony_cierr_open:
9178c2ecf20Sopenharmony_ci	v4l2_fh_release(file);
9188c2ecf20Sopenharmony_cierr_unlock:
9198c2ecf20Sopenharmony_ci	mutex_unlock(&vin->lock);
9208c2ecf20Sopenharmony_cierr_pm:
9218c2ecf20Sopenharmony_ci	pm_runtime_put(vin->dev);
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_ci	return ret;
9248c2ecf20Sopenharmony_ci}
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_cistatic int rvin_release(struct file *file)
9278c2ecf20Sopenharmony_ci{
9288c2ecf20Sopenharmony_ci	struct rvin_dev *vin = video_drvdata(file);
9298c2ecf20Sopenharmony_ci	bool fh_singular;
9308c2ecf20Sopenharmony_ci	int ret;
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_ci	mutex_lock(&vin->lock);
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_ci	/* Save the singular status before we call the clean-up helper */
9358c2ecf20Sopenharmony_ci	fh_singular = v4l2_fh_is_singular_file(file);
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_ci	/* the release helper will cleanup any on-going streaming */
9388c2ecf20Sopenharmony_ci	ret = _vb2_fop_release(file, NULL);
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_ci	if (vin->info->use_mc) {
9418c2ecf20Sopenharmony_ci		v4l2_pipeline_pm_put(&vin->vdev.entity);
9428c2ecf20Sopenharmony_ci	} else {
9438c2ecf20Sopenharmony_ci		if (fh_singular)
9448c2ecf20Sopenharmony_ci			rvin_power_parallel(vin, false);
9458c2ecf20Sopenharmony_ci	}
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ci	mutex_unlock(&vin->lock);
9488c2ecf20Sopenharmony_ci
9498c2ecf20Sopenharmony_ci	pm_runtime_put(vin->dev);
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ci	return ret;
9528c2ecf20Sopenharmony_ci}
9538c2ecf20Sopenharmony_ci
9548c2ecf20Sopenharmony_cistatic const struct v4l2_file_operations rvin_fops = {
9558c2ecf20Sopenharmony_ci	.owner		= THIS_MODULE,
9568c2ecf20Sopenharmony_ci	.unlocked_ioctl	= video_ioctl2,
9578c2ecf20Sopenharmony_ci	.open		= rvin_open,
9588c2ecf20Sopenharmony_ci	.release	= rvin_release,
9598c2ecf20Sopenharmony_ci	.poll		= vb2_fop_poll,
9608c2ecf20Sopenharmony_ci	.mmap		= vb2_fop_mmap,
9618c2ecf20Sopenharmony_ci	.read		= vb2_fop_read,
9628c2ecf20Sopenharmony_ci};
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_civoid rvin_v4l2_unregister(struct rvin_dev *vin)
9658c2ecf20Sopenharmony_ci{
9668c2ecf20Sopenharmony_ci	if (!video_is_registered(&vin->vdev))
9678c2ecf20Sopenharmony_ci		return;
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_ci	v4l2_info(&vin->v4l2_dev, "Removing %s\n",
9708c2ecf20Sopenharmony_ci		  video_device_node_name(&vin->vdev));
9718c2ecf20Sopenharmony_ci
9728c2ecf20Sopenharmony_ci	/* Checks internally if vdev have been init or not */
9738c2ecf20Sopenharmony_ci	video_unregister_device(&vin->vdev);
9748c2ecf20Sopenharmony_ci}
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_cistatic void rvin_notify(struct v4l2_subdev *sd,
9778c2ecf20Sopenharmony_ci			unsigned int notification, void *arg)
9788c2ecf20Sopenharmony_ci{
9798c2ecf20Sopenharmony_ci	struct rvin_dev *vin =
9808c2ecf20Sopenharmony_ci		container_of(sd->v4l2_dev, struct rvin_dev, v4l2_dev);
9818c2ecf20Sopenharmony_ci
9828c2ecf20Sopenharmony_ci	switch (notification) {
9838c2ecf20Sopenharmony_ci	case V4L2_DEVICE_NOTIFY_EVENT:
9848c2ecf20Sopenharmony_ci		v4l2_event_queue(&vin->vdev, arg);
9858c2ecf20Sopenharmony_ci		break;
9868c2ecf20Sopenharmony_ci	default:
9878c2ecf20Sopenharmony_ci		break;
9888c2ecf20Sopenharmony_ci	}
9898c2ecf20Sopenharmony_ci}
9908c2ecf20Sopenharmony_ci
9918c2ecf20Sopenharmony_ciint rvin_v4l2_register(struct rvin_dev *vin)
9928c2ecf20Sopenharmony_ci{
9938c2ecf20Sopenharmony_ci	struct video_device *vdev = &vin->vdev;
9948c2ecf20Sopenharmony_ci	int ret;
9958c2ecf20Sopenharmony_ci
9968c2ecf20Sopenharmony_ci	vin->v4l2_dev.notify = rvin_notify;
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_ci	/* video node */
9998c2ecf20Sopenharmony_ci	vdev->v4l2_dev = &vin->v4l2_dev;
10008c2ecf20Sopenharmony_ci	vdev->queue = &vin->queue;
10018c2ecf20Sopenharmony_ci	snprintf(vdev->name, sizeof(vdev->name), "VIN%u output", vin->id);
10028c2ecf20Sopenharmony_ci	vdev->release = video_device_release_empty;
10038c2ecf20Sopenharmony_ci	vdev->lock = &vin->lock;
10048c2ecf20Sopenharmony_ci	vdev->fops = &rvin_fops;
10058c2ecf20Sopenharmony_ci	vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
10068c2ecf20Sopenharmony_ci		V4L2_CAP_READWRITE;
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_ci	/* Set a default format */
10098c2ecf20Sopenharmony_ci	vin->format.pixelformat	= RVIN_DEFAULT_FORMAT;
10108c2ecf20Sopenharmony_ci	vin->format.width = RVIN_DEFAULT_WIDTH;
10118c2ecf20Sopenharmony_ci	vin->format.height = RVIN_DEFAULT_HEIGHT;
10128c2ecf20Sopenharmony_ci	vin->format.field = RVIN_DEFAULT_FIELD;
10138c2ecf20Sopenharmony_ci	vin->format.colorspace = RVIN_DEFAULT_COLORSPACE;
10148c2ecf20Sopenharmony_ci
10158c2ecf20Sopenharmony_ci	if (vin->info->use_mc) {
10168c2ecf20Sopenharmony_ci		vdev->device_caps |= V4L2_CAP_IO_MC;
10178c2ecf20Sopenharmony_ci		vdev->ioctl_ops = &rvin_mc_ioctl_ops;
10188c2ecf20Sopenharmony_ci	} else {
10198c2ecf20Sopenharmony_ci		vdev->ioctl_ops = &rvin_ioctl_ops;
10208c2ecf20Sopenharmony_ci		rvin_reset_format(vin);
10218c2ecf20Sopenharmony_ci	}
10228c2ecf20Sopenharmony_ci
10238c2ecf20Sopenharmony_ci	rvin_format_align(vin, &vin->format);
10248c2ecf20Sopenharmony_ci
10258c2ecf20Sopenharmony_ci	ret = video_register_device(&vin->vdev, VFL_TYPE_VIDEO, -1);
10268c2ecf20Sopenharmony_ci	if (ret) {
10278c2ecf20Sopenharmony_ci		vin_err(vin, "Failed to register video device\n");
10288c2ecf20Sopenharmony_ci		return ret;
10298c2ecf20Sopenharmony_ci	}
10308c2ecf20Sopenharmony_ci
10318c2ecf20Sopenharmony_ci	video_set_drvdata(&vin->vdev, vin);
10328c2ecf20Sopenharmony_ci
10338c2ecf20Sopenharmony_ci	v4l2_info(&vin->v4l2_dev, "Device registered as %s\n",
10348c2ecf20Sopenharmony_ci		  video_device_node_name(&vin->vdev));
10358c2ecf20Sopenharmony_ci
10368c2ecf20Sopenharmony_ci	return ret;
10378c2ecf20Sopenharmony_ci}
1038