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