1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * vimc-common.c Virtual Media Controller Driver
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 2015-2017 Helen Koike <helen.fornazier@gmail.com>
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #include <linux/init.h>
9*4882a593Smuzhiyun #include <linux/module.h>
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun #include "vimc-common.h"
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun /*
14*4882a593Smuzhiyun * NOTE: non-bayer formats need to come first (necessary for enum_mbus_code
15*4882a593Smuzhiyun * in the scaler)
16*4882a593Smuzhiyun */
17*4882a593Smuzhiyun static const struct vimc_pix_map vimc_pix_map_list[] = {
18*4882a593Smuzhiyun /* TODO: add all missing formats */
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun /* RGB formats */
21*4882a593Smuzhiyun {
22*4882a593Smuzhiyun .code = {
23*4882a593Smuzhiyun MEDIA_BUS_FMT_BGR888_1X24,
24*4882a593Smuzhiyun MEDIA_BUS_FMT_BGR888_3X8
25*4882a593Smuzhiyun },
26*4882a593Smuzhiyun .pixelformat = V4L2_PIX_FMT_BGR24,
27*4882a593Smuzhiyun .bpp = 3,
28*4882a593Smuzhiyun .bayer = false,
29*4882a593Smuzhiyun },
30*4882a593Smuzhiyun {
31*4882a593Smuzhiyun .code = {
32*4882a593Smuzhiyun MEDIA_BUS_FMT_RGB888_1X24,
33*4882a593Smuzhiyun MEDIA_BUS_FMT_RGB888_2X12_BE,
34*4882a593Smuzhiyun MEDIA_BUS_FMT_RGB888_2X12_LE,
35*4882a593Smuzhiyun MEDIA_BUS_FMT_RGB888_3X8,
36*4882a593Smuzhiyun MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
37*4882a593Smuzhiyun MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA,
38*4882a593Smuzhiyun MEDIA_BUS_FMT_RGB888_1X32_PADHI,
39*4882a593Smuzhiyun MEDIA_BUS_FMT_GBR888_1X24
40*4882a593Smuzhiyun },
41*4882a593Smuzhiyun .pixelformat = V4L2_PIX_FMT_RGB24,
42*4882a593Smuzhiyun .bpp = 3,
43*4882a593Smuzhiyun .bayer = false,
44*4882a593Smuzhiyun },
45*4882a593Smuzhiyun {
46*4882a593Smuzhiyun .code = { MEDIA_BUS_FMT_ARGB8888_1X32 },
47*4882a593Smuzhiyun .pixelformat = V4L2_PIX_FMT_ARGB32,
48*4882a593Smuzhiyun .bpp = 4,
49*4882a593Smuzhiyun .bayer = false,
50*4882a593Smuzhiyun },
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun /* Bayer formats */
53*4882a593Smuzhiyun {
54*4882a593Smuzhiyun .code = { MEDIA_BUS_FMT_SBGGR8_1X8 },
55*4882a593Smuzhiyun .pixelformat = V4L2_PIX_FMT_SBGGR8,
56*4882a593Smuzhiyun .bpp = 1,
57*4882a593Smuzhiyun .bayer = true,
58*4882a593Smuzhiyun },
59*4882a593Smuzhiyun {
60*4882a593Smuzhiyun .code = { MEDIA_BUS_FMT_SGBRG8_1X8 },
61*4882a593Smuzhiyun .pixelformat = V4L2_PIX_FMT_SGBRG8,
62*4882a593Smuzhiyun .bpp = 1,
63*4882a593Smuzhiyun .bayer = true,
64*4882a593Smuzhiyun },
65*4882a593Smuzhiyun {
66*4882a593Smuzhiyun .code = { MEDIA_BUS_FMT_SGRBG8_1X8 },
67*4882a593Smuzhiyun .pixelformat = V4L2_PIX_FMT_SGRBG8,
68*4882a593Smuzhiyun .bpp = 1,
69*4882a593Smuzhiyun .bayer = true,
70*4882a593Smuzhiyun },
71*4882a593Smuzhiyun {
72*4882a593Smuzhiyun .code = { MEDIA_BUS_FMT_SRGGB8_1X8 },
73*4882a593Smuzhiyun .pixelformat = V4L2_PIX_FMT_SRGGB8,
74*4882a593Smuzhiyun .bpp = 1,
75*4882a593Smuzhiyun .bayer = true,
76*4882a593Smuzhiyun },
77*4882a593Smuzhiyun {
78*4882a593Smuzhiyun .code = { MEDIA_BUS_FMT_SBGGR10_1X10 },
79*4882a593Smuzhiyun .pixelformat = V4L2_PIX_FMT_SBGGR10,
80*4882a593Smuzhiyun .bpp = 2,
81*4882a593Smuzhiyun .bayer = true,
82*4882a593Smuzhiyun },
83*4882a593Smuzhiyun {
84*4882a593Smuzhiyun .code = { MEDIA_BUS_FMT_SGBRG10_1X10 },
85*4882a593Smuzhiyun .pixelformat = V4L2_PIX_FMT_SGBRG10,
86*4882a593Smuzhiyun .bpp = 2,
87*4882a593Smuzhiyun .bayer = true,
88*4882a593Smuzhiyun },
89*4882a593Smuzhiyun {
90*4882a593Smuzhiyun .code = { MEDIA_BUS_FMT_SGRBG10_1X10 },
91*4882a593Smuzhiyun .pixelformat = V4L2_PIX_FMT_SGRBG10,
92*4882a593Smuzhiyun .bpp = 2,
93*4882a593Smuzhiyun .bayer = true,
94*4882a593Smuzhiyun },
95*4882a593Smuzhiyun {
96*4882a593Smuzhiyun .code = { MEDIA_BUS_FMT_SRGGB10_1X10 },
97*4882a593Smuzhiyun .pixelformat = V4L2_PIX_FMT_SRGGB10,
98*4882a593Smuzhiyun .bpp = 2,
99*4882a593Smuzhiyun .bayer = true,
100*4882a593Smuzhiyun },
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun /* 10bit raw bayer a-law compressed to 8 bits */
103*4882a593Smuzhiyun {
104*4882a593Smuzhiyun .code = { MEDIA_BUS_FMT_SBGGR10_ALAW8_1X8 },
105*4882a593Smuzhiyun .pixelformat = V4L2_PIX_FMT_SBGGR10ALAW8,
106*4882a593Smuzhiyun .bpp = 1,
107*4882a593Smuzhiyun .bayer = true,
108*4882a593Smuzhiyun },
109*4882a593Smuzhiyun {
110*4882a593Smuzhiyun .code = { MEDIA_BUS_FMT_SGBRG10_ALAW8_1X8 },
111*4882a593Smuzhiyun .pixelformat = V4L2_PIX_FMT_SGBRG10ALAW8,
112*4882a593Smuzhiyun .bpp = 1,
113*4882a593Smuzhiyun .bayer = true,
114*4882a593Smuzhiyun },
115*4882a593Smuzhiyun {
116*4882a593Smuzhiyun .code = { MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8 },
117*4882a593Smuzhiyun .pixelformat = V4L2_PIX_FMT_SGRBG10ALAW8,
118*4882a593Smuzhiyun .bpp = 1,
119*4882a593Smuzhiyun .bayer = true,
120*4882a593Smuzhiyun },
121*4882a593Smuzhiyun {
122*4882a593Smuzhiyun .code = { MEDIA_BUS_FMT_SRGGB10_ALAW8_1X8 },
123*4882a593Smuzhiyun .pixelformat = V4L2_PIX_FMT_SRGGB10ALAW8,
124*4882a593Smuzhiyun .bpp = 1,
125*4882a593Smuzhiyun .bayer = true,
126*4882a593Smuzhiyun },
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun /* 10bit raw bayer DPCM compressed to 8 bits */
129*4882a593Smuzhiyun {
130*4882a593Smuzhiyun .code = { MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8 },
131*4882a593Smuzhiyun .pixelformat = V4L2_PIX_FMT_SBGGR10DPCM8,
132*4882a593Smuzhiyun .bpp = 1,
133*4882a593Smuzhiyun .bayer = true,
134*4882a593Smuzhiyun },
135*4882a593Smuzhiyun {
136*4882a593Smuzhiyun .code = { MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8 },
137*4882a593Smuzhiyun .pixelformat = V4L2_PIX_FMT_SGBRG10DPCM8,
138*4882a593Smuzhiyun .bpp = 1,
139*4882a593Smuzhiyun .bayer = true,
140*4882a593Smuzhiyun },
141*4882a593Smuzhiyun {
142*4882a593Smuzhiyun .code = { MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8 },
143*4882a593Smuzhiyun .pixelformat = V4L2_PIX_FMT_SGRBG10DPCM8,
144*4882a593Smuzhiyun .bpp = 1,
145*4882a593Smuzhiyun .bayer = true,
146*4882a593Smuzhiyun },
147*4882a593Smuzhiyun {
148*4882a593Smuzhiyun .code = { MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8 },
149*4882a593Smuzhiyun .pixelformat = V4L2_PIX_FMT_SRGGB10DPCM8,
150*4882a593Smuzhiyun .bpp = 1,
151*4882a593Smuzhiyun .bayer = true,
152*4882a593Smuzhiyun },
153*4882a593Smuzhiyun {
154*4882a593Smuzhiyun .code = { MEDIA_BUS_FMT_SBGGR12_1X12 },
155*4882a593Smuzhiyun .pixelformat = V4L2_PIX_FMT_SBGGR12,
156*4882a593Smuzhiyun .bpp = 2,
157*4882a593Smuzhiyun .bayer = true,
158*4882a593Smuzhiyun },
159*4882a593Smuzhiyun {
160*4882a593Smuzhiyun .code = { MEDIA_BUS_FMT_SGBRG12_1X12 },
161*4882a593Smuzhiyun .pixelformat = V4L2_PIX_FMT_SGBRG12,
162*4882a593Smuzhiyun .bpp = 2,
163*4882a593Smuzhiyun .bayer = true,
164*4882a593Smuzhiyun },
165*4882a593Smuzhiyun {
166*4882a593Smuzhiyun .code = { MEDIA_BUS_FMT_SGRBG12_1X12 },
167*4882a593Smuzhiyun .pixelformat = V4L2_PIX_FMT_SGRBG12,
168*4882a593Smuzhiyun .bpp = 2,
169*4882a593Smuzhiyun .bayer = true,
170*4882a593Smuzhiyun },
171*4882a593Smuzhiyun {
172*4882a593Smuzhiyun .code = { MEDIA_BUS_FMT_SRGGB12_1X12 },
173*4882a593Smuzhiyun .pixelformat = V4L2_PIX_FMT_SRGGB12,
174*4882a593Smuzhiyun .bpp = 2,
175*4882a593Smuzhiyun .bayer = true,
176*4882a593Smuzhiyun },
177*4882a593Smuzhiyun };
178*4882a593Smuzhiyun
vimc_is_source(struct media_entity * ent)179*4882a593Smuzhiyun bool vimc_is_source(struct media_entity *ent)
180*4882a593Smuzhiyun {
181*4882a593Smuzhiyun unsigned int i;
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun for (i = 0; i < ent->num_pads; i++)
184*4882a593Smuzhiyun if (ent->pads[i].flags & MEDIA_PAD_FL_SINK)
185*4882a593Smuzhiyun return false;
186*4882a593Smuzhiyun return true;
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun
vimc_pix_map_by_index(unsigned int i)189*4882a593Smuzhiyun const struct vimc_pix_map *vimc_pix_map_by_index(unsigned int i)
190*4882a593Smuzhiyun {
191*4882a593Smuzhiyun if (i >= ARRAY_SIZE(vimc_pix_map_list))
192*4882a593Smuzhiyun return NULL;
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun return &vimc_pix_map_list[i];
195*4882a593Smuzhiyun }
196*4882a593Smuzhiyun
vimc_mbus_code_by_index(unsigned int index)197*4882a593Smuzhiyun u32 vimc_mbus_code_by_index(unsigned int index)
198*4882a593Smuzhiyun {
199*4882a593Smuzhiyun unsigned int i, j;
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(vimc_pix_map_list); i++) {
202*4882a593Smuzhiyun for (j = 0; j < ARRAY_SIZE(vimc_pix_map_list[i].code); j++) {
203*4882a593Smuzhiyun if (!vimc_pix_map_list[i].code[j])
204*4882a593Smuzhiyun break;
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun if (!index)
207*4882a593Smuzhiyun return vimc_pix_map_list[i].code[j];
208*4882a593Smuzhiyun index--;
209*4882a593Smuzhiyun }
210*4882a593Smuzhiyun }
211*4882a593Smuzhiyun return 0;
212*4882a593Smuzhiyun }
213*4882a593Smuzhiyun
vimc_pix_map_by_code(u32 code)214*4882a593Smuzhiyun const struct vimc_pix_map *vimc_pix_map_by_code(u32 code)
215*4882a593Smuzhiyun {
216*4882a593Smuzhiyun unsigned int i, j;
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(vimc_pix_map_list); i++) {
219*4882a593Smuzhiyun for (j = 0; j < ARRAY_SIZE(vimc_pix_map_list[i].code); j++) {
220*4882a593Smuzhiyun if (vimc_pix_map_list[i].code[j] == code)
221*4882a593Smuzhiyun return &vimc_pix_map_list[i];
222*4882a593Smuzhiyun }
223*4882a593Smuzhiyun }
224*4882a593Smuzhiyun return NULL;
225*4882a593Smuzhiyun }
226*4882a593Smuzhiyun
vimc_pix_map_by_pixelformat(u32 pixelformat)227*4882a593Smuzhiyun const struct vimc_pix_map *vimc_pix_map_by_pixelformat(u32 pixelformat)
228*4882a593Smuzhiyun {
229*4882a593Smuzhiyun unsigned int i;
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(vimc_pix_map_list); i++) {
232*4882a593Smuzhiyun if (vimc_pix_map_list[i].pixelformat == pixelformat)
233*4882a593Smuzhiyun return &vimc_pix_map_list[i];
234*4882a593Smuzhiyun }
235*4882a593Smuzhiyun return NULL;
236*4882a593Smuzhiyun }
237*4882a593Smuzhiyun
vimc_get_pix_format(struct media_pad * pad,struct v4l2_pix_format * fmt)238*4882a593Smuzhiyun static int vimc_get_pix_format(struct media_pad *pad,
239*4882a593Smuzhiyun struct v4l2_pix_format *fmt)
240*4882a593Smuzhiyun {
241*4882a593Smuzhiyun if (is_media_entity_v4l2_subdev(pad->entity)) {
242*4882a593Smuzhiyun struct v4l2_subdev *sd =
243*4882a593Smuzhiyun media_entity_to_v4l2_subdev(pad->entity);
244*4882a593Smuzhiyun struct v4l2_subdev_format sd_fmt;
245*4882a593Smuzhiyun const struct vimc_pix_map *pix_map;
246*4882a593Smuzhiyun int ret;
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
249*4882a593Smuzhiyun sd_fmt.pad = pad->index;
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &sd_fmt);
252*4882a593Smuzhiyun if (ret)
253*4882a593Smuzhiyun return ret;
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun v4l2_fill_pix_format(fmt, &sd_fmt.format);
256*4882a593Smuzhiyun pix_map = vimc_pix_map_by_code(sd_fmt.format.code);
257*4882a593Smuzhiyun fmt->pixelformat = pix_map->pixelformat;
258*4882a593Smuzhiyun } else if (is_media_entity_v4l2_video_device(pad->entity)) {
259*4882a593Smuzhiyun struct video_device *vdev = container_of(pad->entity,
260*4882a593Smuzhiyun struct video_device,
261*4882a593Smuzhiyun entity);
262*4882a593Smuzhiyun struct vimc_ent_device *ved = video_get_drvdata(vdev);
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun if (!ved->vdev_get_format)
265*4882a593Smuzhiyun return -ENOIOCTLCMD;
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun ved->vdev_get_format(ved, fmt);
268*4882a593Smuzhiyun } else {
269*4882a593Smuzhiyun return -EINVAL;
270*4882a593Smuzhiyun }
271*4882a593Smuzhiyun
272*4882a593Smuzhiyun return 0;
273*4882a593Smuzhiyun }
274*4882a593Smuzhiyun
vimc_vdev_link_validate(struct media_link * link)275*4882a593Smuzhiyun int vimc_vdev_link_validate(struct media_link *link)
276*4882a593Smuzhiyun {
277*4882a593Smuzhiyun struct v4l2_pix_format source_fmt, sink_fmt;
278*4882a593Smuzhiyun int ret;
279*4882a593Smuzhiyun
280*4882a593Smuzhiyun ret = vimc_get_pix_format(link->source, &source_fmt);
281*4882a593Smuzhiyun if (ret)
282*4882a593Smuzhiyun return ret;
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun ret = vimc_get_pix_format(link->sink, &sink_fmt);
285*4882a593Smuzhiyun if (ret)
286*4882a593Smuzhiyun return ret;
287*4882a593Smuzhiyun
288*4882a593Smuzhiyun pr_info("vimc link validate: "
289*4882a593Smuzhiyun "%s:src:%dx%d (0x%x, %d, %d, %d, %d) "
290*4882a593Smuzhiyun "%s:snk:%dx%d (0x%x, %d, %d, %d, %d)\n",
291*4882a593Smuzhiyun /* src */
292*4882a593Smuzhiyun link->source->entity->name,
293*4882a593Smuzhiyun source_fmt.width, source_fmt.height,
294*4882a593Smuzhiyun source_fmt.pixelformat, source_fmt.colorspace,
295*4882a593Smuzhiyun source_fmt.quantization, source_fmt.xfer_func,
296*4882a593Smuzhiyun source_fmt.ycbcr_enc,
297*4882a593Smuzhiyun /* sink */
298*4882a593Smuzhiyun link->sink->entity->name,
299*4882a593Smuzhiyun sink_fmt.width, sink_fmt.height,
300*4882a593Smuzhiyun sink_fmt.pixelformat, sink_fmt.colorspace,
301*4882a593Smuzhiyun sink_fmt.quantization, sink_fmt.xfer_func,
302*4882a593Smuzhiyun sink_fmt.ycbcr_enc);
303*4882a593Smuzhiyun
304*4882a593Smuzhiyun /* The width, height and pixelformat must match. */
305*4882a593Smuzhiyun if (source_fmt.width != sink_fmt.width ||
306*4882a593Smuzhiyun source_fmt.height != sink_fmt.height ||
307*4882a593Smuzhiyun source_fmt.pixelformat != sink_fmt.pixelformat)
308*4882a593Smuzhiyun return -EPIPE;
309*4882a593Smuzhiyun
310*4882a593Smuzhiyun /*
311*4882a593Smuzhiyun * The field order must match, or the sink field order must be NONE
312*4882a593Smuzhiyun * to support interlaced hardware connected to bridges that support
313*4882a593Smuzhiyun * progressive formats only.
314*4882a593Smuzhiyun */
315*4882a593Smuzhiyun if (source_fmt.field != sink_fmt.field &&
316*4882a593Smuzhiyun sink_fmt.field != V4L2_FIELD_NONE)
317*4882a593Smuzhiyun return -EPIPE;
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun /*
320*4882a593Smuzhiyun * If colorspace is DEFAULT, then assume all the colorimetry is also
321*4882a593Smuzhiyun * DEFAULT, return 0 to skip comparing the other colorimetry parameters
322*4882a593Smuzhiyun */
323*4882a593Smuzhiyun if (source_fmt.colorspace == V4L2_COLORSPACE_DEFAULT ||
324*4882a593Smuzhiyun sink_fmt.colorspace == V4L2_COLORSPACE_DEFAULT)
325*4882a593Smuzhiyun return 0;
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun /* Colorspace must match. */
328*4882a593Smuzhiyun if (source_fmt.colorspace != sink_fmt.colorspace)
329*4882a593Smuzhiyun return -EPIPE;
330*4882a593Smuzhiyun
331*4882a593Smuzhiyun /* Colorimetry must match if they are not set to DEFAULT */
332*4882a593Smuzhiyun if (source_fmt.ycbcr_enc != V4L2_YCBCR_ENC_DEFAULT &&
333*4882a593Smuzhiyun sink_fmt.ycbcr_enc != V4L2_YCBCR_ENC_DEFAULT &&
334*4882a593Smuzhiyun source_fmt.ycbcr_enc != sink_fmt.ycbcr_enc)
335*4882a593Smuzhiyun return -EPIPE;
336*4882a593Smuzhiyun
337*4882a593Smuzhiyun if (source_fmt.quantization != V4L2_QUANTIZATION_DEFAULT &&
338*4882a593Smuzhiyun sink_fmt.quantization != V4L2_QUANTIZATION_DEFAULT &&
339*4882a593Smuzhiyun source_fmt.quantization != sink_fmt.quantization)
340*4882a593Smuzhiyun return -EPIPE;
341*4882a593Smuzhiyun
342*4882a593Smuzhiyun if (source_fmt.xfer_func != V4L2_XFER_FUNC_DEFAULT &&
343*4882a593Smuzhiyun sink_fmt.xfer_func != V4L2_XFER_FUNC_DEFAULT &&
344*4882a593Smuzhiyun source_fmt.xfer_func != sink_fmt.xfer_func)
345*4882a593Smuzhiyun return -EPIPE;
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun return 0;
348*4882a593Smuzhiyun }
349*4882a593Smuzhiyun
350*4882a593Smuzhiyun static const struct media_entity_operations vimc_ent_sd_mops = {
351*4882a593Smuzhiyun .link_validate = v4l2_subdev_link_validate,
352*4882a593Smuzhiyun };
353*4882a593Smuzhiyun
vimc_ent_sd_register(struct vimc_ent_device * ved,struct v4l2_subdev * sd,struct v4l2_device * v4l2_dev,const char * const name,u32 function,u16 num_pads,struct media_pad * pads,const struct v4l2_subdev_ops * sd_ops)354*4882a593Smuzhiyun int vimc_ent_sd_register(struct vimc_ent_device *ved,
355*4882a593Smuzhiyun struct v4l2_subdev *sd,
356*4882a593Smuzhiyun struct v4l2_device *v4l2_dev,
357*4882a593Smuzhiyun const char *const name,
358*4882a593Smuzhiyun u32 function,
359*4882a593Smuzhiyun u16 num_pads,
360*4882a593Smuzhiyun struct media_pad *pads,
361*4882a593Smuzhiyun const struct v4l2_subdev_ops *sd_ops)
362*4882a593Smuzhiyun {
363*4882a593Smuzhiyun int ret;
364*4882a593Smuzhiyun
365*4882a593Smuzhiyun /* Fill the vimc_ent_device struct */
366*4882a593Smuzhiyun ved->ent = &sd->entity;
367*4882a593Smuzhiyun
368*4882a593Smuzhiyun /* Initialize the subdev */
369*4882a593Smuzhiyun v4l2_subdev_init(sd, sd_ops);
370*4882a593Smuzhiyun sd->entity.function = function;
371*4882a593Smuzhiyun sd->entity.ops = &vimc_ent_sd_mops;
372*4882a593Smuzhiyun sd->owner = THIS_MODULE;
373*4882a593Smuzhiyun strscpy(sd->name, name, sizeof(sd->name));
374*4882a593Smuzhiyun v4l2_set_subdevdata(sd, ved);
375*4882a593Smuzhiyun
376*4882a593Smuzhiyun /* Expose this subdev to user space */
377*4882a593Smuzhiyun sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
378*4882a593Smuzhiyun if (sd->ctrl_handler)
379*4882a593Smuzhiyun sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS;
380*4882a593Smuzhiyun
381*4882a593Smuzhiyun /* Initialize the media entity */
382*4882a593Smuzhiyun ret = media_entity_pads_init(&sd->entity, num_pads, pads);
383*4882a593Smuzhiyun if (ret)
384*4882a593Smuzhiyun return ret;
385*4882a593Smuzhiyun
386*4882a593Smuzhiyun /* Register the subdev with the v4l2 and the media framework */
387*4882a593Smuzhiyun ret = v4l2_device_register_subdev(v4l2_dev, sd);
388*4882a593Smuzhiyun if (ret) {
389*4882a593Smuzhiyun dev_err(v4l2_dev->dev,
390*4882a593Smuzhiyun "%s: subdev register failed (err=%d)\n",
391*4882a593Smuzhiyun name, ret);
392*4882a593Smuzhiyun goto err_clean_m_ent;
393*4882a593Smuzhiyun }
394*4882a593Smuzhiyun
395*4882a593Smuzhiyun return 0;
396*4882a593Smuzhiyun
397*4882a593Smuzhiyun err_clean_m_ent:
398*4882a593Smuzhiyun media_entity_cleanup(&sd->entity);
399*4882a593Smuzhiyun return ret;
400*4882a593Smuzhiyun }
401