File Index
Files and directories
Sign in
FILE

dcmipp-byteproc.c

File preview with syntax highlighting.

linux-6.19.14/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-byteproc.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Driver for STM32 Digital Camera Memory Interface Pixel Processor
  4 *
  5 * Copyright (C) STMicroelectronics SA 2023
  6 * Authors: Hugues Fruchet <hugues.fruchet@foss.st.com>
  7 *          Alain Volmat <alain.volmat@foss.st.com>
  8 *          for STMicroelectronics.
  9 */
 10
 11#include <linux/vmalloc.h>
 12#include <linux/v4l2-mediabus.h>
 13#include <media/v4l2-rect.h>
 14#include <media/v4l2-subdev.h>
 15
 16#include "dcmipp-common.h"
 17
 18#define DCMIPP_P0FCTCR	0x500
 19#define DCMIPP_P0FCTCR_FRATE_MASK	GENMASK(1, 0)
 20#define DCMIPP_P0SCSTR	0x504
 21#define DCMIPP_P0SCSTR_HSTART_SHIFT	0
 22#define DCMIPP_P0SCSTR_VSTART_SHIFT	16
 23#define DCMIPP_P0SCSZR	0x508
 24#define DCMIPP_P0SCSZR_ENABLE		BIT(31)
 25#define DCMIPP_P0SCSZR_HSIZE_SHIFT	0
 26#define DCMIPP_P0SCSZR_VSIZE_SHIFT	16
 27#define DCMIPP_P0PPCR	0x5c0
 28#define DCMIPP_P0PPCR_BSM_1_2		0x1
 29#define DCMIPP_P0PPCR_BSM_1_4		0x2
 30#define DCMIPP_P0PPCR_BSM_2_4		0x3
 31#define DCMIPP_P0PPCR_BSM_MASK		GENMASK(8, 7)
 32#define DCMIPP_P0PPCR_BSM_SHIFT		0x7
 33#define DCMIPP_P0PPCR_LSM		BIT(10)
 34#define DCMIPP_P0PPCR_OELS		BIT(11)
 35
 36#define IS_SINK(pad) (!(pad))
 37#define IS_SRC(pad)  ((pad))
 38
 39struct dcmipp_byteproc_pix_map {
 40	unsigned int code;
 41	unsigned int bpp;
 42};
 43
 44#define PIXMAP_MBUS_BPP(mbus, byteperpixel)		\
 45	{						\
 46		.code = MEDIA_BUS_FMT_##mbus,		\
 47		.bpp = byteperpixel,			\
 48	}
 49static const struct dcmipp_byteproc_pix_map dcmipp_byteproc_pix_map_list[] = {
 50	PIXMAP_MBUS_BPP(RGB565_2X8_LE, 2),
 51	PIXMAP_MBUS_BPP(RGB565_1X16, 2),
 52	PIXMAP_MBUS_BPP(YUYV8_2X8, 2),
 53	PIXMAP_MBUS_BPP(YUYV8_1X16, 2),
 54	PIXMAP_MBUS_BPP(YVYU8_2X8, 2),
 55	PIXMAP_MBUS_BPP(YVYU8_1X16, 2),
 56	PIXMAP_MBUS_BPP(UYVY8_2X8, 2),
 57	PIXMAP_MBUS_BPP(UYVY8_1X16, 2),
 58	PIXMAP_MBUS_BPP(VYUY8_2X8, 2),
 59	PIXMAP_MBUS_BPP(VYUY8_1X16, 2),
 60	PIXMAP_MBUS_BPP(Y8_1X8, 1),
 61	PIXMAP_MBUS_BPP(SBGGR8_1X8, 1),
 62	PIXMAP_MBUS_BPP(SGBRG8_1X8, 1),
 63	PIXMAP_MBUS_BPP(SGRBG8_1X8, 1),
 64	PIXMAP_MBUS_BPP(SRGGB8_1X8, 1),
 65	PIXMAP_MBUS_BPP(SBGGR10_1X10, 2),
 66	PIXMAP_MBUS_BPP(SGBRG10_1X10, 2),
 67	PIXMAP_MBUS_BPP(SGRBG10_1X10, 2),
 68	PIXMAP_MBUS_BPP(SRGGB10_1X10, 2),
 69	PIXMAP_MBUS_BPP(SBGGR12_1X12, 2),
 70	PIXMAP_MBUS_BPP(SGBRG12_1X12, 2),
 71	PIXMAP_MBUS_BPP(SGRBG12_1X12, 2),
 72	PIXMAP_MBUS_BPP(SRGGB12_1X12, 2),
 73	PIXMAP_MBUS_BPP(SBGGR14_1X14, 2),
 74	PIXMAP_MBUS_BPP(SGBRG14_1X14, 2),
 75	PIXMAP_MBUS_BPP(SGRBG14_1X14, 2),
 76	PIXMAP_MBUS_BPP(SRGGB14_1X14, 2),
 77	PIXMAP_MBUS_BPP(JPEG_1X8, 1),
 78};
 79
 80static const struct dcmipp_byteproc_pix_map *
 81dcmipp_byteproc_pix_map_by_code(u32 code)
 82{
 83	unsigned int i;
 84
 85	for (i = 0; i < ARRAY_SIZE(dcmipp_byteproc_pix_map_list); i++) {
 86		if (dcmipp_byteproc_pix_map_list[i].code == code)
 87			return &dcmipp_byteproc_pix_map_list[i];
 88	}
 89
 90	return NULL;
 91}
 92
 93struct dcmipp_byteproc_device {
 94	struct dcmipp_ent_device ved;
 95	struct v4l2_subdev sd;
 96	struct device *dev;
 97	void __iomem *regs;
 98};
 99
100static const struct v4l2_mbus_framefmt fmt_default = {
101	.width = DCMIPP_FMT_WIDTH_DEFAULT,
102	.height = DCMIPP_FMT_HEIGHT_DEFAULT,
103	.code = MEDIA_BUS_FMT_RGB565_2X8_LE,
104	.field = V4L2_FIELD_NONE,
105	.colorspace = DCMIPP_COLORSPACE_DEFAULT,
106	.ycbcr_enc = DCMIPP_YCBCR_ENC_DEFAULT,
107	.quantization = DCMIPP_QUANTIZATION_DEFAULT,
108	.xfer_func = DCMIPP_XFER_FUNC_DEFAULT,
109};
110
111static const struct v4l2_rect crop_min = {
112	.width = DCMIPP_FRAME_MIN_WIDTH,
113	.height = DCMIPP_FRAME_MIN_HEIGHT,
114	.top = 0,
115	.left = 0,
116};
117
118static void dcmipp_byteproc_adjust_crop(struct v4l2_rect *r,
119					struct v4l2_rect *compose)
120{
121	/* Disallow rectangles smaller than the minimal one. */
122	v4l2_rect_set_min_size(r, &crop_min);
123	v4l2_rect_map_inside(r, compose);
124}
125
126static void dcmipp_byteproc_adjust_compose(struct v4l2_rect *r,
127					   const struct v4l2_mbus_framefmt *fmt)
128{
129	r->top = 0;
130	r->left = 0;
131
132	/* Compose is not possible for JPEG or Bayer formats */
133	if (fmt->code >= MEDIA_BUS_FMT_SBGGR8_1X8 &&
134	    fmt->code <= MEDIA_BUS_FMT_JPEG_1X8) {
135		r->width = fmt->width;
136		r->height = fmt->height;
137		return;
138	}
139
140	/* Adjust height - we can only perform 1/2 decimation */
141	if (r->height <= (fmt->height / 2))
142		r->height = fmt->height / 2;
143	else
144		r->height = fmt->height;
145
146	/* Adjust width /2 or /4 for 8bits formats and /2 for 16bits formats */
147	if (fmt->code == MEDIA_BUS_FMT_Y8_1X8 && r->width <= (fmt->width / 4))
148		r->width = fmt->width / 4;
149	else if (r->width <= (fmt->width / 2))
150		r->width = fmt->width / 2;
151	else
152		r->width = fmt->width;
153}
154
155static void dcmipp_byteproc_adjust_fmt(struct v4l2_mbus_framefmt *fmt)
156{
157	const struct dcmipp_byteproc_pix_map *vpix;
158
159	/* Only accept code in the pix map table */
160	vpix = dcmipp_byteproc_pix_map_by_code(fmt->code);
161	if (!vpix)
162		fmt->code = fmt_default.code;
163
164	fmt->width = clamp_t(u32, fmt->width, DCMIPP_FRAME_MIN_WIDTH,
165			     DCMIPP_FRAME_MAX_WIDTH) & ~1;
166	fmt->height = clamp_t(u32, fmt->height, DCMIPP_FRAME_MIN_HEIGHT,
167			      DCMIPP_FRAME_MAX_HEIGHT) & ~1;
168
169	if (fmt->field == V4L2_FIELD_ANY || fmt->field == V4L2_FIELD_ALTERNATE)
170		fmt->field = fmt_default.field;
171
172	dcmipp_colorimetry_clamp(fmt);
173}
174
175static int dcmipp_byteproc_init_state(struct v4l2_subdev *sd,
176				      struct v4l2_subdev_state *sd_state)
177{
178	unsigned int i;
179
180	for (i = 0; i < sd->entity.num_pads; i++) {
181		struct v4l2_mbus_framefmt *mf;
182		struct v4l2_rect *r;
183
184		mf = v4l2_subdev_state_get_format(sd_state, i);
185		*mf = fmt_default;
186
187		if (IS_SINK(i))
188			r = v4l2_subdev_state_get_compose(sd_state, i);
189		else
190			r = v4l2_subdev_state_get_crop(sd_state, i);
191
192		r->top = 0;
193		r->left = 0;
194		r->width = DCMIPP_FMT_WIDTH_DEFAULT;
195		r->height = DCMIPP_FMT_HEIGHT_DEFAULT;
196	}
197
198	return 0;
199}
200
201static int
202dcmipp_byteproc_enum_mbus_code(struct v4l2_subdev *sd,
203			       struct v4l2_subdev_state *sd_state,
204			       struct v4l2_subdev_mbus_code_enum *code)
205{
206	const struct dcmipp_byteproc_pix_map *vpix;
207	struct v4l2_mbus_framefmt *sink_fmt;
208
209	if (IS_SINK(code->pad)) {
210		if (code->index >= ARRAY_SIZE(dcmipp_byteproc_pix_map_list))
211			return -EINVAL;
212		vpix = &dcmipp_byteproc_pix_map_list[code->index];
213		code->code = vpix->code;
214	} else {
215		/* byteproc doesn't support transformation on format */
216		if (code->index > 0)
217			return -EINVAL;
218
219		sink_fmt = v4l2_subdev_state_get_format(sd_state, 0);
220		code->code = sink_fmt->code;
221	}
222
223	return 0;
224}
225
226static int
227dcmipp_byteproc_enum_frame_size(struct v4l2_subdev *sd,
228				struct v4l2_subdev_state *sd_state,
229				struct v4l2_subdev_frame_size_enum *fse)
230{
231	struct v4l2_rect *compose;
232
233	if (fse->index)
234		return -EINVAL;
235
236	fse->min_width = DCMIPP_FRAME_MIN_WIDTH;
237	fse->min_height = DCMIPP_FRAME_MIN_HEIGHT;
238
239	if (IS_SINK(fse->pad)) {
240		fse->max_width = DCMIPP_FRAME_MAX_WIDTH;
241		fse->max_height = DCMIPP_FRAME_MAX_HEIGHT;
242	} else {
243		compose = v4l2_subdev_state_get_compose(sd_state, 0);
244		fse->max_width = compose->width;
245		fse->max_height = compose->height;
246	}
247
248	return 0;
249}
250
251static int dcmipp_byteproc_set_fmt(struct v4l2_subdev *sd,
252				   struct v4l2_subdev_state *sd_state,
253				   struct v4l2_subdev_format *fmt)
254{
255	struct v4l2_mbus_framefmt *mf;
256	struct v4l2_rect *crop, *compose;
257
258	if (v4l2_subdev_is_streaming(sd))
259		return -EBUSY;
260
261	mf = v4l2_subdev_state_get_format(sd_state, fmt->pad);
262
263	crop = v4l2_subdev_state_get_crop(sd_state, 1);
264	compose = v4l2_subdev_state_get_compose(sd_state, 0);
265
266	if (IS_SRC(fmt->pad)) {
267		fmt->format = *v4l2_subdev_state_get_format(sd_state, 0);
268		fmt->format.width = crop->width;
269		fmt->format.height = crop->height;
270	} else {
271		dcmipp_byteproc_adjust_fmt(&fmt->format);
272		crop->top = 0;
273		crop->left = 0;
274		crop->width = fmt->format.width;
275		crop->height = fmt->format.height;
276		*compose = *crop;
277		/* Set the same format on SOURCE pad as well */
278		*v4l2_subdev_state_get_format(sd_state, 1) = fmt->format;
279	}
280	*mf = fmt->format;
281
282	return 0;
283}
284
285static int dcmipp_byteproc_get_selection(struct v4l2_subdev *sd,
286					 struct v4l2_subdev_state *sd_state,
287					 struct v4l2_subdev_selection *s)
288{
289	struct v4l2_mbus_framefmt *sink_fmt;
290	struct v4l2_rect *crop, *compose;
291
292	/*
293	 * In the HW, the decimation block is located prior to the crop hence:
294	 * Compose is done on the sink pad
295	 * Crop is done on the src pad
296	 */
297	if (IS_SINK(s->pad) &&
298	    (s->target == V4L2_SEL_TGT_CROP ||
299	     s->target == V4L2_SEL_TGT_CROP_BOUNDS ||
300	     s->target == V4L2_SEL_TGT_CROP_DEFAULT))
301		return -EINVAL;
302
303	if (IS_SRC(s->pad) &&
304	    (s->target == V4L2_SEL_TGT_COMPOSE ||
305	     s->target == V4L2_SEL_TGT_COMPOSE_BOUNDS ||
306	     s->target == V4L2_SEL_TGT_COMPOSE_DEFAULT))
307		return -EINVAL;
308
309	sink_fmt = v4l2_subdev_state_get_format(sd_state, 0);
310	crop = v4l2_subdev_state_get_crop(sd_state, 1);
311	compose = v4l2_subdev_state_get_compose(sd_state, 0);
312
313	switch (s->target) {
314	case V4L2_SEL_TGT_CROP:
315		s->r = *crop;
316		break;
317	case V4L2_SEL_TGT_CROP_BOUNDS:
318	case V4L2_SEL_TGT_CROP_DEFAULT:
319		s->r = *compose;
320		break;
321	case V4L2_SEL_TGT_COMPOSE:
322		s->r = *compose;
323		break;
324	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
325	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
326		s->r.top = 0;
327		s->r.left = 0;
328		s->r.width = sink_fmt->width;
329		s->r.height = sink_fmt->height;
330		break;
331	default:
332		return -EINVAL;
333	}
334
335	return 0;
336}
337
338static int dcmipp_byteproc_set_selection(struct v4l2_subdev *sd,
339					 struct v4l2_subdev_state *sd_state,
340					 struct v4l2_subdev_selection *s)
341{
342	struct dcmipp_byteproc_device *byteproc = v4l2_get_subdevdata(sd);
343	struct v4l2_mbus_framefmt *mf;
344	struct v4l2_rect *crop, *compose;
345
346	/*
347	 * In the HW, the decimation block is located prior to the crop hence:
348	 * Compose is done on the sink pad
349	 * Crop is done on the src pad
350	 */
351	if ((s->target == V4L2_SEL_TGT_CROP ||
352	     s->target == V4L2_SEL_TGT_CROP_BOUNDS ||
353	     s->target == V4L2_SEL_TGT_CROP_DEFAULT) && IS_SINK(s->pad))
354		return -EINVAL;
355
356	if ((s->target == V4L2_SEL_TGT_COMPOSE ||
357	     s->target == V4L2_SEL_TGT_COMPOSE_BOUNDS ||
358	     s->target == V4L2_SEL_TGT_COMPOSE_DEFAULT) && IS_SRC(s->pad))
359		return -EINVAL;
360
361	crop = v4l2_subdev_state_get_crop(sd_state, 1);
362	compose = v4l2_subdev_state_get_compose(sd_state, 0);
363
364	switch (s->target) {
365	case V4L2_SEL_TGT_CROP:
366		dcmipp_byteproc_adjust_crop(&s->r, compose);
367
368		*crop = s->r;
369		mf = v4l2_subdev_state_get_format(sd_state, 1);
370		mf->width = s->r.width;
371		mf->height = s->r.height;
372
373		dev_dbg(byteproc->dev, "s_selection: crop (%d,%d)/%ux%u\n",
374			crop->left, crop->top, crop->width, crop->height);
375		break;
376	case V4L2_SEL_TGT_COMPOSE:
377		mf = v4l2_subdev_state_get_format(sd_state, 0);
378		dcmipp_byteproc_adjust_compose(&s->r, mf);
379		*compose = s->r;
380		*crop = s->r;
381
382		mf = v4l2_subdev_state_get_format(sd_state, 1);
383		mf->width = s->r.width;
384		mf->height = s->r.height;
385
386		dev_dbg(byteproc->dev, "s_selection: compose (%d,%d)/%ux%u\n",
387			compose->left, compose->top,
388			compose->width, compose->height);
389		break;
390	default:
391		return -EINVAL;
392	}
393
394	return 0;
395}
396
397static int dcmipp_byteproc_configure_scale_crop
398			(struct dcmipp_byteproc_device *byteproc,
399			 struct v4l2_subdev_state *state)
400{
401	const struct dcmipp_byteproc_pix_map *vpix;
402	struct v4l2_mbus_framefmt *sink_fmt;
403	u32 hprediv, vprediv;
404	struct v4l2_rect *compose, *crop;
405	u32 val = 0;
406
407	sink_fmt = v4l2_subdev_state_get_format(state, 0);
408	compose = v4l2_subdev_state_get_compose(state, 0);
409	crop = v4l2_subdev_state_get_crop(state, 1);
410
411	/* find output format bpp */
412	vpix = dcmipp_byteproc_pix_map_by_code(sink_fmt->code);
413	if (!vpix)
414		return -EINVAL;
415
416	/* clear decimation/crop */
417	reg_clear(byteproc, DCMIPP_P0PPCR, DCMIPP_P0PPCR_BSM_MASK);
418	reg_clear(byteproc, DCMIPP_P0PPCR, DCMIPP_P0PPCR_LSM);
419	reg_write(byteproc, DCMIPP_P0SCSTR, 0);
420	reg_write(byteproc, DCMIPP_P0SCSZR, 0);
421
422	/* Ignore decimation/crop with JPEG */
423	if (vpix->code == MEDIA_BUS_FMT_JPEG_1X8)
424		return 0;
425
426	/* decimation */
427	hprediv = sink_fmt->width / compose->width;
428	if (hprediv == 4)
429		val |= DCMIPP_P0PPCR_BSM_1_4 << DCMIPP_P0PPCR_BSM_SHIFT;
430	else if ((vpix->code == MEDIA_BUS_FMT_Y8_1X8) && (hprediv == 2))
431		val |= DCMIPP_P0PPCR_BSM_1_2 << DCMIPP_P0PPCR_BSM_SHIFT;
432	else if (hprediv == 2)
433		val |= DCMIPP_P0PPCR_BSM_2_4 << DCMIPP_P0PPCR_BSM_SHIFT;
434
435	vprediv = sink_fmt->height / compose->height;
436	if (vprediv == 2)
437		val |= DCMIPP_P0PPCR_LSM | DCMIPP_P0PPCR_OELS;
438
439	/* decimate using bytes and lines skipping */
440	if (val) {
441		reg_set(byteproc, DCMIPP_P0PPCR, val);
442
443		dev_dbg(byteproc->dev, "decimate to %dx%d [prediv=%dx%d]\n",
444			compose->width, compose->height,
445			hprediv, vprediv);
446	}
447
448	dev_dbg(byteproc->dev, "crop to %dx%d\n", crop->width, crop->height);
449
450	/* expressed in 32-bits words on X axis, lines on Y axis */
451	reg_write(byteproc, DCMIPP_P0SCSTR,
452		  (((crop->left * vpix->bpp) / 4) <<
453		   DCMIPP_P0SCSTR_HSTART_SHIFT) |
454		  (crop->top << DCMIPP_P0SCSTR_VSTART_SHIFT));
455	reg_write(byteproc, DCMIPP_P0SCSZR,
456		  DCMIPP_P0SCSZR_ENABLE |
457		  (((crop->width * vpix->bpp) / 4) <<
458		   DCMIPP_P0SCSZR_HSIZE_SHIFT) |
459		  (crop->height << DCMIPP_P0SCSZR_VSIZE_SHIFT));
460
461	return 0;
462}
463
464static int dcmipp_byteproc_enable_streams(struct v4l2_subdev *sd,
465					  struct v4l2_subdev_state *state,
466					  u32 pad, u64 streams_mask)
467{
468	struct dcmipp_byteproc_device *byteproc = v4l2_get_subdevdata(sd);
469	struct v4l2_subdev *s_subdev;
470	struct media_pad *s_pad;
471	int ret;
472
473	/* Get source subdev */
474	s_pad = media_pad_remote_pad_first(&sd->entity.pads[0]);
475	if (!s_pad || !is_media_entity_v4l2_subdev(s_pad->entity))
476		return -EINVAL;
477	s_subdev = media_entity_to_v4l2_subdev(s_pad->entity);
478
479	ret = dcmipp_byteproc_configure_scale_crop(byteproc, state);
480	if (ret)
481		return ret;
482
483	ret = v4l2_subdev_enable_streams(s_subdev, s_pad->index, BIT_ULL(0));
484	if (ret < 0) {
485		dev_err(byteproc->dev,
486			"failed to start source subdev streaming (%d)\n", ret);
487		return ret;
488	}
489
490	return 0;
491}
492
493static int dcmipp_byteproc_disable_streams(struct v4l2_subdev *sd,
494					   struct v4l2_subdev_state *state,
495					   u32 pad, u64 streams_mask)
496{
497	struct dcmipp_byteproc_device *byteproc = v4l2_get_subdevdata(sd);
498	struct v4l2_subdev *s_subdev;
499	struct media_pad *s_pad;
500	int ret;
501
502	/* Get source subdev */
503	s_pad = media_pad_remote_pad_first(&sd->entity.pads[0]);
504	if (!s_pad || !is_media_entity_v4l2_subdev(s_pad->entity))
505		return -EINVAL;
506	s_subdev = media_entity_to_v4l2_subdev(s_pad->entity);
507
508	ret = v4l2_subdev_disable_streams(s_subdev, s_pad->index, BIT_ULL(0));
509	if (ret < 0) {
510		dev_err(byteproc->dev,
511			"failed to start source subdev streaming (%d)\n", ret);
512		return ret;
513	}
514
515	return 0;
516}
517
518static const struct v4l2_subdev_pad_ops dcmipp_byteproc_pad_ops = {
519	.enum_mbus_code		= dcmipp_byteproc_enum_mbus_code,
520	.enum_frame_size	= dcmipp_byteproc_enum_frame_size,
521	.get_fmt		= v4l2_subdev_get_fmt,
522	.set_fmt		= dcmipp_byteproc_set_fmt,
523	.get_selection		= dcmipp_byteproc_get_selection,
524	.set_selection		= dcmipp_byteproc_set_selection,
525	.enable_streams		= dcmipp_byteproc_enable_streams,
526	.disable_streams	= dcmipp_byteproc_disable_streams,
527};
528
529static const struct v4l2_subdev_video_ops dcmipp_byteproc_video_ops = {
530	.s_stream = v4l2_subdev_s_stream_helper,
531};
532
533static const struct v4l2_subdev_ops dcmipp_byteproc_ops = {
534	.pad = &dcmipp_byteproc_pad_ops,
535	.video = &dcmipp_byteproc_video_ops,
536};
537
538static void dcmipp_byteproc_release(struct v4l2_subdev *sd)
539{
540	struct dcmipp_byteproc_device *byteproc = v4l2_get_subdevdata(sd);
541
542	kfree(byteproc);
543}
544
545static const struct v4l2_subdev_internal_ops dcmipp_byteproc_int_ops = {
546	.init_state = dcmipp_byteproc_init_state,
547	.release = dcmipp_byteproc_release,
548};
549
550void dcmipp_byteproc_ent_release(struct dcmipp_ent_device *ved)
551{
552	struct dcmipp_byteproc_device *byteproc =
553			container_of(ved, struct dcmipp_byteproc_device, ved);
554
555	dcmipp_ent_sd_unregister(ved, &byteproc->sd);
556}
557
558struct dcmipp_ent_device *
559dcmipp_byteproc_ent_init(struct device *dev, const char *entity_name,
560			 struct v4l2_device *v4l2_dev, void __iomem *regs)
561{
562	struct dcmipp_byteproc_device *byteproc;
563	const unsigned long pads_flag[] = {
564		MEDIA_PAD_FL_SINK, MEDIA_PAD_FL_SOURCE,
565	};
566	int ret;
567
568	/* Allocate the byteproc struct */
569	byteproc = kzalloc(sizeof(*byteproc), GFP_KERNEL);
570	if (!byteproc)
571		return ERR_PTR(-ENOMEM);
572
573	byteproc->regs = regs;
574
575	/* Initialize ved and sd */
576	ret = dcmipp_ent_sd_register(&byteproc->ved, &byteproc->sd,
577				     v4l2_dev, entity_name,
578				     MEDIA_ENT_F_PROC_VIDEO_SCALER,
579				     ARRAY_SIZE(pads_flag), pads_flag,
580				     &dcmipp_byteproc_int_ops,
581				     &dcmipp_byteproc_ops,
582				     NULL, NULL);
583	if (ret) {
584		kfree(byteproc);
585		return ERR_PTR(ret);
586	}
587
588	byteproc->dev = dev;
589
590	return &byteproc->ved;
591}
~/ Read-only file preview.