162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * vimc-common.c Virtual Media Controller Driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2015-2017 Helen Koike <helen.fornazier@gmail.com>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/init.h>
962306a36Sopenharmony_ci#include <linux/module.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include "vimc-common.h"
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci/*
1462306a36Sopenharmony_ci * NOTE: non-bayer formats need to come first (necessary for enum_mbus_code
1562306a36Sopenharmony_ci * in the scaler)
1662306a36Sopenharmony_ci */
1762306a36Sopenharmony_cistatic const struct vimc_pix_map vimc_pix_map_list[] = {
1862306a36Sopenharmony_ci	/* TODO: add all missing formats */
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci	/* RGB formats */
2162306a36Sopenharmony_ci	{
2262306a36Sopenharmony_ci		.code = {
2362306a36Sopenharmony_ci			MEDIA_BUS_FMT_BGR888_1X24,
2462306a36Sopenharmony_ci			MEDIA_BUS_FMT_BGR888_3X8
2562306a36Sopenharmony_ci		},
2662306a36Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_BGR24,
2762306a36Sopenharmony_ci		.bpp = 3,
2862306a36Sopenharmony_ci		.bayer = false,
2962306a36Sopenharmony_ci	},
3062306a36Sopenharmony_ci	{
3162306a36Sopenharmony_ci		.code = {
3262306a36Sopenharmony_ci			MEDIA_BUS_FMT_RGB888_1X24,
3362306a36Sopenharmony_ci			MEDIA_BUS_FMT_RGB888_2X12_BE,
3462306a36Sopenharmony_ci			MEDIA_BUS_FMT_RGB888_2X12_LE,
3562306a36Sopenharmony_ci			MEDIA_BUS_FMT_RGB888_3X8,
3662306a36Sopenharmony_ci			MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
3762306a36Sopenharmony_ci			MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA,
3862306a36Sopenharmony_ci			MEDIA_BUS_FMT_RGB888_1X32_PADHI,
3962306a36Sopenharmony_ci			MEDIA_BUS_FMT_GBR888_1X24
4062306a36Sopenharmony_ci		},
4162306a36Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_RGB24,
4262306a36Sopenharmony_ci		.bpp = 3,
4362306a36Sopenharmony_ci		.bayer = false,
4462306a36Sopenharmony_ci	},
4562306a36Sopenharmony_ci	{
4662306a36Sopenharmony_ci		.code = { MEDIA_BUS_FMT_ARGB8888_1X32 },
4762306a36Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_ARGB32,
4862306a36Sopenharmony_ci		.bpp = 4,
4962306a36Sopenharmony_ci		.bayer = false,
5062306a36Sopenharmony_ci	},
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	/* Bayer formats */
5362306a36Sopenharmony_ci	{
5462306a36Sopenharmony_ci		.code = { MEDIA_BUS_FMT_SBGGR8_1X8 },
5562306a36Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_SBGGR8,
5662306a36Sopenharmony_ci		.bpp = 1,
5762306a36Sopenharmony_ci		.bayer = true,
5862306a36Sopenharmony_ci	},
5962306a36Sopenharmony_ci	{
6062306a36Sopenharmony_ci		.code = { MEDIA_BUS_FMT_SGBRG8_1X8 },
6162306a36Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_SGBRG8,
6262306a36Sopenharmony_ci		.bpp = 1,
6362306a36Sopenharmony_ci		.bayer = true,
6462306a36Sopenharmony_ci	},
6562306a36Sopenharmony_ci	{
6662306a36Sopenharmony_ci		.code = { MEDIA_BUS_FMT_SGRBG8_1X8 },
6762306a36Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_SGRBG8,
6862306a36Sopenharmony_ci		.bpp = 1,
6962306a36Sopenharmony_ci		.bayer = true,
7062306a36Sopenharmony_ci	},
7162306a36Sopenharmony_ci	{
7262306a36Sopenharmony_ci		.code = { MEDIA_BUS_FMT_SRGGB8_1X8 },
7362306a36Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_SRGGB8,
7462306a36Sopenharmony_ci		.bpp = 1,
7562306a36Sopenharmony_ci		.bayer = true,
7662306a36Sopenharmony_ci	},
7762306a36Sopenharmony_ci	{
7862306a36Sopenharmony_ci		.code = { MEDIA_BUS_FMT_SBGGR10_1X10 },
7962306a36Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_SBGGR10,
8062306a36Sopenharmony_ci		.bpp = 2,
8162306a36Sopenharmony_ci		.bayer = true,
8262306a36Sopenharmony_ci	},
8362306a36Sopenharmony_ci	{
8462306a36Sopenharmony_ci		.code = { MEDIA_BUS_FMT_SGBRG10_1X10 },
8562306a36Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_SGBRG10,
8662306a36Sopenharmony_ci		.bpp = 2,
8762306a36Sopenharmony_ci		.bayer = true,
8862306a36Sopenharmony_ci	},
8962306a36Sopenharmony_ci	{
9062306a36Sopenharmony_ci		.code = { MEDIA_BUS_FMT_SGRBG10_1X10 },
9162306a36Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_SGRBG10,
9262306a36Sopenharmony_ci		.bpp = 2,
9362306a36Sopenharmony_ci		.bayer = true,
9462306a36Sopenharmony_ci	},
9562306a36Sopenharmony_ci	{
9662306a36Sopenharmony_ci		.code = { MEDIA_BUS_FMT_SRGGB10_1X10 },
9762306a36Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_SRGGB10,
9862306a36Sopenharmony_ci		.bpp = 2,
9962306a36Sopenharmony_ci		.bayer = true,
10062306a36Sopenharmony_ci	},
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	/* 10bit raw bayer a-law compressed to 8 bits */
10362306a36Sopenharmony_ci	{
10462306a36Sopenharmony_ci		.code = { MEDIA_BUS_FMT_SBGGR10_ALAW8_1X8 },
10562306a36Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_SBGGR10ALAW8,
10662306a36Sopenharmony_ci		.bpp = 1,
10762306a36Sopenharmony_ci		.bayer = true,
10862306a36Sopenharmony_ci	},
10962306a36Sopenharmony_ci	{
11062306a36Sopenharmony_ci		.code = { MEDIA_BUS_FMT_SGBRG10_ALAW8_1X8 },
11162306a36Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_SGBRG10ALAW8,
11262306a36Sopenharmony_ci		.bpp = 1,
11362306a36Sopenharmony_ci		.bayer = true,
11462306a36Sopenharmony_ci	},
11562306a36Sopenharmony_ci	{
11662306a36Sopenharmony_ci		.code = { MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8 },
11762306a36Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_SGRBG10ALAW8,
11862306a36Sopenharmony_ci		.bpp = 1,
11962306a36Sopenharmony_ci		.bayer = true,
12062306a36Sopenharmony_ci	},
12162306a36Sopenharmony_ci	{
12262306a36Sopenharmony_ci		.code = { MEDIA_BUS_FMT_SRGGB10_ALAW8_1X8 },
12362306a36Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_SRGGB10ALAW8,
12462306a36Sopenharmony_ci		.bpp = 1,
12562306a36Sopenharmony_ci		.bayer = true,
12662306a36Sopenharmony_ci	},
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	/* 10bit raw bayer DPCM compressed to 8 bits */
12962306a36Sopenharmony_ci	{
13062306a36Sopenharmony_ci		.code = { MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8 },
13162306a36Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_SBGGR10DPCM8,
13262306a36Sopenharmony_ci		.bpp = 1,
13362306a36Sopenharmony_ci		.bayer = true,
13462306a36Sopenharmony_ci	},
13562306a36Sopenharmony_ci	{
13662306a36Sopenharmony_ci		.code = { MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8 },
13762306a36Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_SGBRG10DPCM8,
13862306a36Sopenharmony_ci		.bpp = 1,
13962306a36Sopenharmony_ci		.bayer = true,
14062306a36Sopenharmony_ci	},
14162306a36Sopenharmony_ci	{
14262306a36Sopenharmony_ci		.code = { MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8 },
14362306a36Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_SGRBG10DPCM8,
14462306a36Sopenharmony_ci		.bpp = 1,
14562306a36Sopenharmony_ci		.bayer = true,
14662306a36Sopenharmony_ci	},
14762306a36Sopenharmony_ci	{
14862306a36Sopenharmony_ci		.code = { MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8 },
14962306a36Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_SRGGB10DPCM8,
15062306a36Sopenharmony_ci		.bpp = 1,
15162306a36Sopenharmony_ci		.bayer = true,
15262306a36Sopenharmony_ci	},
15362306a36Sopenharmony_ci	{
15462306a36Sopenharmony_ci		.code = { MEDIA_BUS_FMT_SBGGR12_1X12 },
15562306a36Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_SBGGR12,
15662306a36Sopenharmony_ci		.bpp = 2,
15762306a36Sopenharmony_ci		.bayer = true,
15862306a36Sopenharmony_ci	},
15962306a36Sopenharmony_ci	{
16062306a36Sopenharmony_ci		.code = { MEDIA_BUS_FMT_SGBRG12_1X12 },
16162306a36Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_SGBRG12,
16262306a36Sopenharmony_ci		.bpp = 2,
16362306a36Sopenharmony_ci		.bayer = true,
16462306a36Sopenharmony_ci	},
16562306a36Sopenharmony_ci	{
16662306a36Sopenharmony_ci		.code = { MEDIA_BUS_FMT_SGRBG12_1X12 },
16762306a36Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_SGRBG12,
16862306a36Sopenharmony_ci		.bpp = 2,
16962306a36Sopenharmony_ci		.bayer = true,
17062306a36Sopenharmony_ci	},
17162306a36Sopenharmony_ci	{
17262306a36Sopenharmony_ci		.code = { MEDIA_BUS_FMT_SRGGB12_1X12 },
17362306a36Sopenharmony_ci		.pixelformat = V4L2_PIX_FMT_SRGGB12,
17462306a36Sopenharmony_ci		.bpp = 2,
17562306a36Sopenharmony_ci		.bayer = true,
17662306a36Sopenharmony_ci	},
17762306a36Sopenharmony_ci};
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_cibool vimc_is_source(struct media_entity *ent)
18062306a36Sopenharmony_ci{
18162306a36Sopenharmony_ci	unsigned int i;
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	for (i = 0; i < ent->num_pads; i++)
18462306a36Sopenharmony_ci		if (ent->pads[i].flags & MEDIA_PAD_FL_SINK)
18562306a36Sopenharmony_ci			return false;
18662306a36Sopenharmony_ci	return true;
18762306a36Sopenharmony_ci}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ciconst struct vimc_pix_map *vimc_pix_map_by_index(unsigned int i)
19062306a36Sopenharmony_ci{
19162306a36Sopenharmony_ci	if (i >= ARRAY_SIZE(vimc_pix_map_list))
19262306a36Sopenharmony_ci		return NULL;
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	return &vimc_pix_map_list[i];
19562306a36Sopenharmony_ci}
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ciu32 vimc_mbus_code_by_index(unsigned int index)
19862306a36Sopenharmony_ci{
19962306a36Sopenharmony_ci	unsigned int i, j;
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(vimc_pix_map_list); i++) {
20262306a36Sopenharmony_ci		for (j = 0; j < ARRAY_SIZE(vimc_pix_map_list[i].code); j++) {
20362306a36Sopenharmony_ci			if (!vimc_pix_map_list[i].code[j])
20462306a36Sopenharmony_ci				break;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci			if (!index)
20762306a36Sopenharmony_ci				return vimc_pix_map_list[i].code[j];
20862306a36Sopenharmony_ci			index--;
20962306a36Sopenharmony_ci		}
21062306a36Sopenharmony_ci	}
21162306a36Sopenharmony_ci	return 0;
21262306a36Sopenharmony_ci}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ciconst struct vimc_pix_map *vimc_pix_map_by_code(u32 code)
21562306a36Sopenharmony_ci{
21662306a36Sopenharmony_ci	unsigned int i, j;
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(vimc_pix_map_list); i++) {
21962306a36Sopenharmony_ci		for (j = 0; j < ARRAY_SIZE(vimc_pix_map_list[i].code); j++) {
22062306a36Sopenharmony_ci			if (vimc_pix_map_list[i].code[j] == code)
22162306a36Sopenharmony_ci				return &vimc_pix_map_list[i];
22262306a36Sopenharmony_ci		}
22362306a36Sopenharmony_ci	}
22462306a36Sopenharmony_ci	return NULL;
22562306a36Sopenharmony_ci}
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ciconst struct vimc_pix_map *vimc_pix_map_by_pixelformat(u32 pixelformat)
22862306a36Sopenharmony_ci{
22962306a36Sopenharmony_ci	unsigned int i;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(vimc_pix_map_list); i++) {
23262306a36Sopenharmony_ci		if (vimc_pix_map_list[i].pixelformat == pixelformat)
23362306a36Sopenharmony_ci			return &vimc_pix_map_list[i];
23462306a36Sopenharmony_ci	}
23562306a36Sopenharmony_ci	return NULL;
23662306a36Sopenharmony_ci}
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_cistatic int vimc_get_pix_format(struct media_pad *pad,
23962306a36Sopenharmony_ci			       struct v4l2_pix_format *fmt)
24062306a36Sopenharmony_ci{
24162306a36Sopenharmony_ci	if (is_media_entity_v4l2_subdev(pad->entity)) {
24262306a36Sopenharmony_ci		struct v4l2_subdev *sd =
24362306a36Sopenharmony_ci			media_entity_to_v4l2_subdev(pad->entity);
24462306a36Sopenharmony_ci		struct v4l2_subdev_format sd_fmt = {
24562306a36Sopenharmony_ci			.which = V4L2_SUBDEV_FORMAT_ACTIVE,
24662306a36Sopenharmony_ci			.pad = pad->index,
24762306a36Sopenharmony_ci		};
24862306a36Sopenharmony_ci		const struct vimc_pix_map *pix_map;
24962306a36Sopenharmony_ci		int ret;
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci		ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &sd_fmt);
25262306a36Sopenharmony_ci		if (ret)
25362306a36Sopenharmony_ci			return ret;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci		v4l2_fill_pix_format(fmt, &sd_fmt.format);
25662306a36Sopenharmony_ci		pix_map = vimc_pix_map_by_code(sd_fmt.format.code);
25762306a36Sopenharmony_ci		fmt->pixelformat = pix_map->pixelformat;
25862306a36Sopenharmony_ci	} else if (is_media_entity_v4l2_video_device(pad->entity)) {
25962306a36Sopenharmony_ci		struct video_device *vdev = container_of(pad->entity,
26062306a36Sopenharmony_ci							 struct video_device,
26162306a36Sopenharmony_ci							 entity);
26262306a36Sopenharmony_ci		struct vimc_ent_device *ved = video_get_drvdata(vdev);
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci		if (!ved->vdev_get_format)
26562306a36Sopenharmony_ci			return -ENOIOCTLCMD;
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci		ved->vdev_get_format(ved, fmt);
26862306a36Sopenharmony_ci	} else {
26962306a36Sopenharmony_ci		return -EINVAL;
27062306a36Sopenharmony_ci	}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	return 0;
27362306a36Sopenharmony_ci}
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ciint vimc_vdev_link_validate(struct media_link *link)
27662306a36Sopenharmony_ci{
27762306a36Sopenharmony_ci	struct v4l2_pix_format source_fmt, sink_fmt;
27862306a36Sopenharmony_ci	int ret;
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	ret = vimc_get_pix_format(link->source, &source_fmt);
28162306a36Sopenharmony_ci	if (ret)
28262306a36Sopenharmony_ci		return ret;
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	ret = vimc_get_pix_format(link->sink, &sink_fmt);
28562306a36Sopenharmony_ci	if (ret)
28662306a36Sopenharmony_ci		return ret;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	pr_info("vimc link validate: "
28962306a36Sopenharmony_ci		"%s:src:%dx%d (0x%x, %d, %d, %d, %d) "
29062306a36Sopenharmony_ci		"%s:snk:%dx%d (0x%x, %d, %d, %d, %d)\n",
29162306a36Sopenharmony_ci		/* src */
29262306a36Sopenharmony_ci		link->source->entity->name,
29362306a36Sopenharmony_ci		source_fmt.width, source_fmt.height,
29462306a36Sopenharmony_ci		source_fmt.pixelformat, source_fmt.colorspace,
29562306a36Sopenharmony_ci		source_fmt.quantization, source_fmt.xfer_func,
29662306a36Sopenharmony_ci		source_fmt.ycbcr_enc,
29762306a36Sopenharmony_ci		/* sink */
29862306a36Sopenharmony_ci		link->sink->entity->name,
29962306a36Sopenharmony_ci		sink_fmt.width, sink_fmt.height,
30062306a36Sopenharmony_ci		sink_fmt.pixelformat, sink_fmt.colorspace,
30162306a36Sopenharmony_ci		sink_fmt.quantization, sink_fmt.xfer_func,
30262306a36Sopenharmony_ci		sink_fmt.ycbcr_enc);
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	/* The width, height and pixelformat must match. */
30562306a36Sopenharmony_ci	if (source_fmt.width != sink_fmt.width ||
30662306a36Sopenharmony_ci	    source_fmt.height != sink_fmt.height ||
30762306a36Sopenharmony_ci	    source_fmt.pixelformat != sink_fmt.pixelformat)
30862306a36Sopenharmony_ci		return -EPIPE;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	/*
31162306a36Sopenharmony_ci	 * The field order must match, or the sink field order must be NONE
31262306a36Sopenharmony_ci	 * to support interlaced hardware connected to bridges that support
31362306a36Sopenharmony_ci	 * progressive formats only.
31462306a36Sopenharmony_ci	 */
31562306a36Sopenharmony_ci	if (source_fmt.field != sink_fmt.field &&
31662306a36Sopenharmony_ci	    sink_fmt.field != V4L2_FIELD_NONE)
31762306a36Sopenharmony_ci		return -EPIPE;
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	/*
32062306a36Sopenharmony_ci	 * If colorspace is DEFAULT, then assume all the colorimetry is also
32162306a36Sopenharmony_ci	 * DEFAULT, return 0 to skip comparing the other colorimetry parameters
32262306a36Sopenharmony_ci	 */
32362306a36Sopenharmony_ci	if (source_fmt.colorspace == V4L2_COLORSPACE_DEFAULT ||
32462306a36Sopenharmony_ci	    sink_fmt.colorspace == V4L2_COLORSPACE_DEFAULT)
32562306a36Sopenharmony_ci		return 0;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	/* Colorspace must match. */
32862306a36Sopenharmony_ci	if (source_fmt.colorspace != sink_fmt.colorspace)
32962306a36Sopenharmony_ci		return -EPIPE;
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	/* Colorimetry must match if they are not set to DEFAULT */
33262306a36Sopenharmony_ci	if (source_fmt.ycbcr_enc != V4L2_YCBCR_ENC_DEFAULT &&
33362306a36Sopenharmony_ci	    sink_fmt.ycbcr_enc != V4L2_YCBCR_ENC_DEFAULT &&
33462306a36Sopenharmony_ci	    source_fmt.ycbcr_enc != sink_fmt.ycbcr_enc)
33562306a36Sopenharmony_ci		return -EPIPE;
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	if (source_fmt.quantization != V4L2_QUANTIZATION_DEFAULT &&
33862306a36Sopenharmony_ci	    sink_fmt.quantization != V4L2_QUANTIZATION_DEFAULT &&
33962306a36Sopenharmony_ci	    source_fmt.quantization != sink_fmt.quantization)
34062306a36Sopenharmony_ci		return -EPIPE;
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	if (source_fmt.xfer_func != V4L2_XFER_FUNC_DEFAULT &&
34362306a36Sopenharmony_ci	    sink_fmt.xfer_func != V4L2_XFER_FUNC_DEFAULT &&
34462306a36Sopenharmony_ci	    source_fmt.xfer_func != sink_fmt.xfer_func)
34562306a36Sopenharmony_ci		return -EPIPE;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	return 0;
34862306a36Sopenharmony_ci}
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_cistatic const struct media_entity_operations vimc_ent_sd_mops = {
35162306a36Sopenharmony_ci	.link_validate = v4l2_subdev_link_validate,
35262306a36Sopenharmony_ci};
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ciint vimc_ent_sd_register(struct vimc_ent_device *ved,
35562306a36Sopenharmony_ci			 struct v4l2_subdev *sd,
35662306a36Sopenharmony_ci			 struct v4l2_device *v4l2_dev,
35762306a36Sopenharmony_ci			 const char *const name,
35862306a36Sopenharmony_ci			 u32 function,
35962306a36Sopenharmony_ci			 u16 num_pads,
36062306a36Sopenharmony_ci			 struct media_pad *pads,
36162306a36Sopenharmony_ci			 const struct v4l2_subdev_ops *sd_ops)
36262306a36Sopenharmony_ci{
36362306a36Sopenharmony_ci	int ret;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	/* Fill the vimc_ent_device struct */
36662306a36Sopenharmony_ci	ved->ent = &sd->entity;
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	/* Initialize the subdev */
36962306a36Sopenharmony_ci	v4l2_subdev_init(sd, sd_ops);
37062306a36Sopenharmony_ci	sd->entity.function = function;
37162306a36Sopenharmony_ci	sd->entity.ops = &vimc_ent_sd_mops;
37262306a36Sopenharmony_ci	sd->owner = THIS_MODULE;
37362306a36Sopenharmony_ci	strscpy(sd->name, name, sizeof(sd->name));
37462306a36Sopenharmony_ci	v4l2_set_subdevdata(sd, ved);
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	/* Expose this subdev to user space */
37762306a36Sopenharmony_ci	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
37862306a36Sopenharmony_ci	if (sd->ctrl_handler)
37962306a36Sopenharmony_ci		sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS;
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	/* Initialize the media entity */
38262306a36Sopenharmony_ci	ret = media_entity_pads_init(&sd->entity, num_pads, pads);
38362306a36Sopenharmony_ci	if (ret)
38462306a36Sopenharmony_ci		return ret;
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	/* Register the subdev with the v4l2 and the media framework */
38762306a36Sopenharmony_ci	ret = v4l2_device_register_subdev(v4l2_dev, sd);
38862306a36Sopenharmony_ci	if (ret) {
38962306a36Sopenharmony_ci		dev_err(v4l2_dev->dev,
39062306a36Sopenharmony_ci			"%s: subdev register failed (err=%d)\n",
39162306a36Sopenharmony_ci			name, ret);
39262306a36Sopenharmony_ci		goto err_clean_m_ent;
39362306a36Sopenharmony_ci	}
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	return 0;
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_cierr_clean_m_ent:
39862306a36Sopenharmony_ci	media_entity_cleanup(&sd->entity);
39962306a36Sopenharmony_ci	return ret;
40062306a36Sopenharmony_ci}
401