1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (C) 2013 - 2020 Intel Corporation
4 #include <linux/types.h>
5 #include <linux/videodev2.h>
7 #include <media/media-entity.h>
9 #include <uapi/linux/media-bus-format.h>
12 #include "ipu-isys-video.h"
13 #include "ipu-isys-subdev.h"
15 unsigned int ipu_isys_mbus_code_to_bpp(u32 code
)
18 case MEDIA_BUS_FMT_RGB888_1X24
:
20 case MEDIA_BUS_FMT_YUYV10_1X20
:
22 case MEDIA_BUS_FMT_Y10_1X10
:
23 case MEDIA_BUS_FMT_RGB565_1X16
:
24 case MEDIA_BUS_FMT_UYVY8_1X16
:
25 case MEDIA_BUS_FMT_YUYV8_1X16
:
27 case MEDIA_BUS_FMT_SBGGR12_1X12
:
28 case MEDIA_BUS_FMT_SGBRG12_1X12
:
29 case MEDIA_BUS_FMT_SGRBG12_1X12
:
30 case MEDIA_BUS_FMT_SRGGB12_1X12
:
32 case MEDIA_BUS_FMT_SBGGR10_1X10
:
33 case MEDIA_BUS_FMT_SGBRG10_1X10
:
34 case MEDIA_BUS_FMT_SGRBG10_1X10
:
35 case MEDIA_BUS_FMT_SRGGB10_1X10
:
37 case MEDIA_BUS_FMT_SBGGR8_1X8
:
38 case MEDIA_BUS_FMT_SGBRG8_1X8
:
39 case MEDIA_BUS_FMT_SGRBG8_1X8
:
40 case MEDIA_BUS_FMT_SRGGB8_1X8
:
41 case MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8
:
42 case MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8
:
43 case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8
:
44 case MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8
:
52 unsigned int ipu_isys_mbus_code_to_mipi(u32 code
)
55 case MEDIA_BUS_FMT_RGB565_1X16
:
56 return IPU_ISYS_MIPI_CSI2_TYPE_RGB565
;
57 case MEDIA_BUS_FMT_RGB888_1X24
:
58 return IPU_ISYS_MIPI_CSI2_TYPE_RGB888
;
59 case MEDIA_BUS_FMT_YUYV10_1X20
:
60 return IPU_ISYS_MIPI_CSI2_TYPE_YUV422_10
;
61 case MEDIA_BUS_FMT_UYVY8_1X16
:
62 case MEDIA_BUS_FMT_YUYV8_1X16
:
63 return IPU_ISYS_MIPI_CSI2_TYPE_YUV422_8
;
64 case MEDIA_BUS_FMT_SBGGR12_1X12
:
65 case MEDIA_BUS_FMT_SGBRG12_1X12
:
66 case MEDIA_BUS_FMT_SGRBG12_1X12
:
67 case MEDIA_BUS_FMT_SRGGB12_1X12
:
68 return IPU_ISYS_MIPI_CSI2_TYPE_RAW12
;
69 case MEDIA_BUS_FMT_Y10_1X10
:
70 case MEDIA_BUS_FMT_SBGGR10_1X10
:
71 case MEDIA_BUS_FMT_SGBRG10_1X10
:
72 case MEDIA_BUS_FMT_SGRBG10_1X10
:
73 case MEDIA_BUS_FMT_SRGGB10_1X10
:
74 return IPU_ISYS_MIPI_CSI2_TYPE_RAW10
;
75 case MEDIA_BUS_FMT_SBGGR8_1X8
:
76 case MEDIA_BUS_FMT_SGBRG8_1X8
:
77 case MEDIA_BUS_FMT_SGRBG8_1X8
:
78 case MEDIA_BUS_FMT_SRGGB8_1X8
:
79 return IPU_ISYS_MIPI_CSI2_TYPE_RAW8
;
80 case MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8
:
81 case MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8
:
82 case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8
:
83 case MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8
:
84 return IPU_ISYS_MIPI_CSI2_TYPE_USER_DEF(1);
91 enum ipu_isys_subdev_pixelorder
ipu_isys_subdev_get_pixelorder(u32 code
)
94 case MEDIA_BUS_FMT_SBGGR12_1X12
:
95 case MEDIA_BUS_FMT_SBGGR10_1X10
:
96 case MEDIA_BUS_FMT_SBGGR8_1X8
:
97 case MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8
:
98 return IPU_ISYS_SUBDEV_PIXELORDER_BGGR
;
99 case MEDIA_BUS_FMT_SGBRG12_1X12
:
100 case MEDIA_BUS_FMT_SGBRG10_1X10
:
101 case MEDIA_BUS_FMT_SGBRG8_1X8
:
102 case MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8
:
103 return IPU_ISYS_SUBDEV_PIXELORDER_GBRG
;
104 case MEDIA_BUS_FMT_SGRBG12_1X12
:
105 case MEDIA_BUS_FMT_SGRBG10_1X10
:
106 case MEDIA_BUS_FMT_SGRBG8_1X8
:
107 case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8
:
108 return IPU_ISYS_SUBDEV_PIXELORDER_GRBG
;
109 case MEDIA_BUS_FMT_SRGGB12_1X12
:
110 case MEDIA_BUS_FMT_SRGGB10_1X10
:
111 case MEDIA_BUS_FMT_SRGGB8_1X8
:
112 case MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8
:
113 return IPU_ISYS_SUBDEV_PIXELORDER_RGGB
;
120 u32
ipu_isys_subdev_code_to_uncompressed(u32 sink_code
)
123 case MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8
:
124 return MEDIA_BUS_FMT_SBGGR10_1X10
;
125 case MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8
:
126 return MEDIA_BUS_FMT_SGBRG10_1X10
;
127 case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8
:
128 return MEDIA_BUS_FMT_SGRBG10_1X10
;
129 case MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8
:
130 return MEDIA_BUS_FMT_SRGGB10_1X10
;
136 struct v4l2_mbus_framefmt
*__ipu_isys_get_ffmt(struct v4l2_subdev
*sd
,
137 struct v4l2_subdev_state
*sd_state
,
141 struct ipu_isys_subdev
*asd
= to_ipu_isys_subdev(sd
);
143 if (which
== V4L2_SUBDEV_FORMAT_ACTIVE
)
144 return &asd
->ffmt
[pad
];
146 return v4l2_subdev_get_try_format(sd
, sd_state
, pad
);
149 struct v4l2_rect
*__ipu_isys_get_selection(struct v4l2_subdev
*sd
,
150 struct v4l2_subdev_state
*sd_state
,
152 unsigned int pad
, unsigned int which
)
154 struct ipu_isys_subdev
*asd
= to_ipu_isys_subdev(sd
);
156 if (which
== V4L2_SUBDEV_FORMAT_ACTIVE
) {
158 case V4L2_SEL_TGT_CROP
:
159 return &asd
->crop
[pad
];
160 case V4L2_SEL_TGT_COMPOSE
:
161 return &asd
->compose
[pad
];
165 case V4L2_SEL_TGT_CROP
:
166 return v4l2_subdev_get_try_crop(sd
, sd_state
, pad
);
167 case V4L2_SEL_TGT_COMPOSE
:
168 return v4l2_subdev_get_try_compose(sd
, sd_state
, pad
);
175 static int target_valid(struct v4l2_subdev
*sd
, unsigned int target
,
178 struct ipu_isys_subdev
*asd
= to_ipu_isys_subdev(sd
);
181 case V4L2_SEL_TGT_CROP
:
182 return asd
->valid_tgts
[pad
].crop
;
183 case V4L2_SEL_TGT_COMPOSE
:
184 return asd
->valid_tgts
[pad
].compose
;
190 int ipu_isys_subdev_fmt_propagate(struct v4l2_subdev
*sd
,
191 struct v4l2_subdev_state
*sd_state
,
192 struct v4l2_mbus_framefmt
*ffmt
,
194 enum isys_subdev_prop_tgt tgt
,
195 unsigned int pad
, unsigned int which
)
197 struct ipu_isys_subdev
*asd
= to_ipu_isys_subdev(sd
);
198 struct v4l2_mbus_framefmt
**ffmts
= NULL
;
199 struct v4l2_rect
**crops
= NULL
;
200 struct v4l2_rect
**compose
= NULL
;
204 if (tgt
== IPU_ISYS_SUBDEV_PROP_TGT_NR_OF
)
207 if (WARN_ON(pad
>= sd
->entity
.num_pads
))
210 ffmts
= kcalloc(sd
->entity
.num_pads
,
211 sizeof(*ffmts
), GFP_KERNEL
);
214 goto out_subdev_fmt_propagate
;
216 crops
= kcalloc(sd
->entity
.num_pads
,
217 sizeof(*crops
), GFP_KERNEL
);
220 goto out_subdev_fmt_propagate
;
222 compose
= kcalloc(sd
->entity
.num_pads
,
223 sizeof(*compose
), GFP_KERNEL
);
226 goto out_subdev_fmt_propagate
;
229 for (i
= 0; i
< sd
->entity
.num_pads
; i
++) {
230 ffmts
[i
] = __ipu_isys_get_ffmt(sd
, sd_state
, i
, which
);
231 crops
[i
] = __ipu_isys_get_selection(sd
, sd_state
,
232 V4L2_SEL_TGT_CROP
, i
, which
);
233 compose
[i
] = __ipu_isys_get_selection(sd
, sd_state
,
234 V4L2_SEL_TGT_COMPOSE
, i
, which
);
238 case IPU_ISYS_SUBDEV_PROP_TGT_SINK_FMT
:
239 crops
[pad
]->left
= 0;
241 crops
[pad
]->width
= ffmt
->width
;
242 crops
[pad
]->height
= ffmt
->height
;
243 rval
= ipu_isys_subdev_fmt_propagate(sd
, sd_state
, ffmt
,
244 crops
[pad
], tgt
+ 1, pad
, which
);
245 goto out_subdev_fmt_propagate
;
246 case IPU_ISYS_SUBDEV_PROP_TGT_SINK_CROP
:
247 if (WARN_ON(sd
->entity
.pads
[pad
].flags
& MEDIA_PAD_FL_SOURCE
))
248 goto out_subdev_fmt_propagate
;
250 compose
[pad
]->left
= 0;
251 compose
[pad
]->top
= 0;
252 compose
[pad
]->width
= r
->width
;
253 compose
[pad
]->height
= r
->height
;
254 rval
= ipu_isys_subdev_fmt_propagate(sd
, sd_state
, ffmt
,
255 compose
[pad
], tgt
+ 1, pad
, which
);
256 goto out_subdev_fmt_propagate
;
257 case IPU_ISYS_SUBDEV_PROP_TGT_SINK_COMPOSE
:
258 if (WARN_ON(sd
->entity
.pads
[pad
].flags
& MEDIA_PAD_FL_SOURCE
)) {
260 goto out_subdev_fmt_propagate
;
263 for (i
= 1; i
< sd
->entity
.num_pads
; i
++) {
264 if (!(sd
->entity
.pads
[i
].flags
&
265 MEDIA_PAD_FL_SOURCE
))
268 compose
[i
]->left
= 0;
270 compose
[i
]->width
= r
->width
;
271 compose
[i
]->height
= r
->height
;
272 rval
= ipu_isys_subdev_fmt_propagate(sd
, sd_state
,
273 ffmt
, compose
[i
], tgt
+ 1, i
, which
);
275 goto out_subdev_fmt_propagate
;
277 goto out_subdev_fmt_propagate
;
278 case IPU_ISYS_SUBDEV_PROP_TGT_SOURCE_COMPOSE
:
279 if (WARN_ON(sd
->entity
.pads
[pad
].flags
& MEDIA_PAD_FL_SINK
)) {
281 goto out_subdev_fmt_propagate
;
284 crops
[pad
]->left
= 0;
286 crops
[pad
]->width
= r
->width
;
287 crops
[pad
]->height
= r
->height
;
288 rval
= ipu_isys_subdev_fmt_propagate(sd
, sd_state
, ffmt
,
289 crops
[pad
], tgt
+ 1, pad
, which
);
290 goto out_subdev_fmt_propagate
;
291 case IPU_ISYS_SUBDEV_PROP_TGT_SOURCE_CROP
:{
292 struct v4l2_subdev_format fmt
= {
299 * Either use the code from sink pad
300 * or the current one.
302 .code
= ffmt
? ffmt
->code
:
304 .field
= ffmt
? ffmt
->field
:
309 asd
->set_ffmt(sd
, sd_state
, &fmt
);
310 goto out_subdev_fmt_propagate
;
314 out_subdev_fmt_propagate
:
321 int ipu_isys_subdev_set_ffmt_default(struct v4l2_subdev
*sd
,
322 struct v4l2_subdev_state
*sd_state
,
323 struct v4l2_subdev_format
*fmt
)
325 struct v4l2_mbus_framefmt
*ffmt
=
326 __ipu_isys_get_ffmt(sd
, sd_state
, fmt
->pad
, fmt
->which
);
328 /* No propagation for non-zero pads. */
330 struct v4l2_mbus_framefmt
*sink_ffmt
=
331 __ipu_isys_get_ffmt(sd
, sd_state
, 0, fmt
->which
);
333 ffmt
->width
= sink_ffmt
->width
;
334 ffmt
->height
= sink_ffmt
->height
;
335 ffmt
->code
= sink_ffmt
->code
;
336 ffmt
->field
= sink_ffmt
->field
;
341 ffmt
->width
= fmt
->format
.width
;
342 ffmt
->height
= fmt
->format
.height
;
343 ffmt
->code
= fmt
->format
.code
;
344 ffmt
->field
= fmt
->format
.field
;
346 return ipu_isys_subdev_fmt_propagate(sd
, sd_state
, &fmt
->format
, NULL
,
347 IPU_ISYS_SUBDEV_PROP_TGT_SINK_FMT
,
348 fmt
->pad
, fmt
->which
);
351 int __ipu_isys_subdev_set_ffmt(struct v4l2_subdev
*sd
,
352 struct v4l2_subdev_state
*sd_state
,
353 struct v4l2_subdev_format
*fmt
)
355 struct ipu_isys_subdev
*asd
= to_ipu_isys_subdev(sd
);
356 struct v4l2_mbus_framefmt
*ffmt
=
357 __ipu_isys_get_ffmt(sd
, sd_state
, fmt
->pad
, fmt
->which
);
358 u32 code
= asd
->supported_codes
[fmt
->pad
][0];
361 WARN_ON(!mutex_is_locked(&asd
->mutex
));
363 fmt
->format
.width
= clamp(fmt
->format
.width
, IPU_ISYS_MIN_WIDTH
,
365 fmt
->format
.height
= clamp(fmt
->format
.height
,
366 IPU_ISYS_MIN_HEIGHT
, IPU_ISYS_MAX_HEIGHT
);
368 for (i
= 0; asd
->supported_codes
[fmt
->pad
][i
]; i
++) {
369 if (asd
->supported_codes
[fmt
->pad
][i
] == fmt
->format
.code
) {
370 code
= asd
->supported_codes
[fmt
->pad
][i
];
375 fmt
->format
.code
= code
;
377 asd
->set_ffmt(sd
, sd_state
, fmt
);
384 int ipu_isys_subdev_set_ffmt(struct v4l2_subdev
*sd
,
385 struct v4l2_subdev_state
*sd_state
,
386 struct v4l2_subdev_format
*fmt
)
388 struct ipu_isys_subdev
*asd
= to_ipu_isys_subdev(sd
);
391 mutex_lock(&asd
->mutex
);
392 rval
= __ipu_isys_subdev_set_ffmt(sd
, sd_state
, fmt
);
393 mutex_unlock(&asd
->mutex
);
398 int ipu_isys_subdev_get_ffmt(struct v4l2_subdev
*sd
,
399 struct v4l2_subdev_state
*sd_state
,
400 struct v4l2_subdev_format
*fmt
)
402 struct ipu_isys_subdev
*asd
= to_ipu_isys_subdev(sd
);
404 mutex_lock(&asd
->mutex
);
405 fmt
->format
= *__ipu_isys_get_ffmt(sd
, sd_state
, fmt
->pad
,
407 mutex_unlock(&asd
->mutex
);
412 int ipu_isys_subdev_set_sel(struct v4l2_subdev
*sd
,
413 struct v4l2_subdev_state
*sd_state
,
414 struct v4l2_subdev_selection
*sel
)
416 struct ipu_isys_subdev
*asd
= to_ipu_isys_subdev(sd
);
417 struct media_pad
*pad
= &asd
->sd
.entity
.pads
[sel
->pad
];
418 struct v4l2_rect
*r
, __r
= { 0 };
421 if (!target_valid(sd
, sel
->target
, sel
->pad
))
424 switch (sel
->target
) {
425 case V4L2_SEL_TGT_CROP
:
426 if (pad
->flags
& MEDIA_PAD_FL_SINK
) {
427 struct v4l2_mbus_framefmt
*ffmt
=
428 __ipu_isys_get_ffmt(sd
, sd_state
, sel
->pad
,
431 __r
.width
= ffmt
->width
;
432 __r
.height
= ffmt
->height
;
434 tgt
= IPU_ISYS_SUBDEV_PROP_TGT_SINK_CROP
;
436 /* 0 is the sink pad. */
437 r
= __ipu_isys_get_selection(sd
, sd_state
, sel
->target
, 0,
439 tgt
= IPU_ISYS_SUBDEV_PROP_TGT_SOURCE_CROP
;
443 case V4L2_SEL_TGT_COMPOSE
:
444 if (pad
->flags
& MEDIA_PAD_FL_SINK
) {
445 r
= __ipu_isys_get_selection(sd
, sd_state
, V4L2_SEL_TGT_CROP
,
446 sel
->pad
, sel
->which
);
447 tgt
= IPU_ISYS_SUBDEV_PROP_TGT_SINK_COMPOSE
;
449 r
= __ipu_isys_get_selection(sd
, sd_state
,
450 V4L2_SEL_TGT_COMPOSE
, 0,
452 tgt
= IPU_ISYS_SUBDEV_PROP_TGT_SOURCE_COMPOSE
;
459 sel
->r
.width
= clamp(sel
->r
.width
, IPU_ISYS_MIN_WIDTH
, r
->width
);
460 sel
->r
.height
= clamp(sel
->r
.height
, IPU_ISYS_MIN_HEIGHT
, r
->height
);
461 *__ipu_isys_get_selection(sd
, sd_state
, sel
->target
, sel
->pad
,
462 sel
->which
) = sel
->r
;
463 return ipu_isys_subdev_fmt_propagate(sd
, sd_state
, NULL
, &sel
->r
, tgt
,
464 sel
->pad
, sel
->which
);
467 int ipu_isys_subdev_get_sel(struct v4l2_subdev
*sd
,
468 struct v4l2_subdev_state
*sd_state
,
469 struct v4l2_subdev_selection
*sel
)
471 if (!target_valid(sd
, sel
->target
, sel
->pad
))
474 sel
->r
= *__ipu_isys_get_selection(sd
, sd_state
, sel
->target
,
475 sel
->pad
, sel
->which
);
480 int ipu_isys_subdev_enum_mbus_code(struct v4l2_subdev
*sd
,
481 struct v4l2_subdev_state
*sd_state
,
482 struct v4l2_subdev_mbus_code_enum
*code
)
484 struct ipu_isys_subdev
*asd
= to_ipu_isys_subdev(sd
);
485 const u32
*supported_codes
= asd
->supported_codes
[code
->pad
];
488 for (index
= 0; supported_codes
[index
]; index
++) {
489 if (index
== code
->index
) {
490 code
->code
= supported_codes
[index
];
499 * Besides validating the link, figure out the external pad and the
500 * ISYS FW ABI source.
502 int ipu_isys_subdev_link_validate(struct v4l2_subdev
*sd
,
503 struct media_link
*link
,
504 struct v4l2_subdev_format
*source_fmt
,
505 struct v4l2_subdev_format
*sink_fmt
)
507 struct v4l2_subdev
*source_sd
=
508 media_entity_to_v4l2_subdev(link
->source
->entity
);
509 struct ipu_isys_pipeline
*ip
= container_of(sd
->entity
.pipe
,
510 struct ipu_isys_pipeline
,
512 struct ipu_isys_subdev
*asd
= to_ipu_isys_subdev(sd
);
516 if (strncmp(source_sd
->name
, IPU_ISYS_ENTITY_PREFIX
,
517 strlen(IPU_ISYS_ENTITY_PREFIX
)) != 0) {
519 * source_sd isn't ours --- sd must be the external
522 ip
->external
= link
->source
;
523 ip
->source
= to_ipu_isys_subdev(sd
)->source
;
524 dev_dbg(&asd
->isys
->adev
->dev
, "%s: using source %d\n",
525 sd
->entity
.name
, ip
->source
);
526 } else if (source_sd
->entity
.num_pads
== 1) {
527 /* All internal sources have a single pad. */
528 ip
->external
= link
->source
;
529 ip
->source
= to_ipu_isys_subdev(source_sd
)->source
;
531 dev_dbg(&asd
->isys
->adev
->dev
, "%s: using source %d\n",
532 sd
->entity
.name
, ip
->source
);
535 if (asd
->isl_mode
!= IPU_ISL_OFF
)
536 ip
->isl_mode
= asd
->isl_mode
;
538 return v4l2_subdev_link_validate_default(sd
, link
, source_fmt
,
542 int ipu_isys_subdev_open(struct v4l2_subdev
*sd
, struct v4l2_subdev_fh
*fh
)
544 struct ipu_isys_subdev
*asd
= to_ipu_isys_subdev(sd
);
547 mutex_lock(&asd
->mutex
);
549 for (i
= 0; i
< asd
->sd
.entity
.num_pads
; i
++) {
550 struct v4l2_mbus_framefmt
*try_fmt
=
551 v4l2_subdev_get_try_format(sd
, fh
->state
, i
);
552 struct v4l2_rect
*try_crop
=
553 v4l2_subdev_get_try_crop(sd
, fh
->state
, i
);
554 struct v4l2_rect
*try_compose
=
555 v4l2_subdev_get_try_compose(sd
, fh
->state
, i
);
557 *try_fmt
= asd
->ffmt
[i
];
558 *try_crop
= asd
->crop
[i
];
559 *try_compose
= asd
->compose
[i
];
562 mutex_unlock(&asd
->mutex
);
567 int ipu_isys_subdev_close(struct v4l2_subdev
*sd
, struct v4l2_subdev_fh
*fh
)
572 int ipu_isys_subdev_init(struct ipu_isys_subdev
*asd
,
573 struct v4l2_subdev_ops
*ops
,
574 unsigned int nr_ctrls
,
575 unsigned int num_pads
,
576 unsigned int num_source
,
577 unsigned int num_sink
,
578 unsigned int sd_flags
)
582 mutex_init(&asd
->mutex
);
584 v4l2_subdev_init(&asd
->sd
, ops
);
586 asd
->sd
.flags
|= V4L2_SUBDEV_FL_HAS_DEVNODE
| sd_flags
;
587 asd
->sd
.owner
= THIS_MODULE
;
588 asd
->sd
.entity
.function
= MEDIA_ENT_F_VID_IF_BRIDGE
;
590 asd
->nsources
= num_source
;
591 asd
->nsinks
= num_sink
;
593 asd
->pad
= devm_kcalloc(&asd
->isys
->adev
->dev
, num_pads
,
594 sizeof(*asd
->pad
), GFP_KERNEL
);
596 asd
->ffmt
= devm_kcalloc(&asd
->isys
->adev
->dev
, num_pads
,
597 sizeof(*asd
->ffmt
), GFP_KERNEL
);
599 asd
->crop
= devm_kcalloc(&asd
->isys
->adev
->dev
, num_pads
,
600 sizeof(*asd
->crop
), GFP_KERNEL
);
602 asd
->compose
= devm_kcalloc(&asd
->isys
->adev
->dev
, num_pads
,
603 sizeof(*asd
->compose
), GFP_KERNEL
);
605 asd
->valid_tgts
= devm_kcalloc(&asd
->isys
->adev
->dev
, num_pads
,
606 sizeof(*asd
->valid_tgts
), GFP_KERNEL
);
607 if (!asd
->pad
|| !asd
->ffmt
|| !asd
->crop
|| !asd
->compose
||
611 rval
= media_entity_pads_init(&asd
->sd
.entity
, num_pads
, asd
->pad
);
613 goto out_mutex_destroy
;
615 if (asd
->ctrl_init
) {
616 rval
= v4l2_ctrl_handler_init(&asd
->ctrl_handler
, nr_ctrls
);
618 goto out_media_entity_cleanup
;
620 asd
->ctrl_init(&asd
->sd
);
621 if (asd
->ctrl_handler
.error
) {
622 rval
= asd
->ctrl_handler
.error
;
623 goto out_v4l2_ctrl_handler_free
;
626 asd
->sd
.ctrl_handler
= &asd
->ctrl_handler
;
633 out_v4l2_ctrl_handler_free
:
634 v4l2_ctrl_handler_free(&asd
->ctrl_handler
);
636 out_media_entity_cleanup
:
637 media_entity_cleanup(&asd
->sd
.entity
);
640 mutex_destroy(&asd
->mutex
);
645 void ipu_isys_subdev_cleanup(struct ipu_isys_subdev
*asd
)
647 media_entity_cleanup(&asd
->sd
.entity
);
648 v4l2_ctrl_handler_free(&asd
->ctrl_handler
);
649 mutex_destroy(&asd
->mutex
);