]> Git Repo - linux.git/blob - drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-byteproc.c
Linux 6.14-rc3
[linux.git] / drivers / media / platform / st / stm32 / stm32-dcmipp / dcmipp-byteproc.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 <[email protected]>
7  *          Alain Volmat <[email protected]>
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
39 struct 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         }
49 static 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
80 static const struct dcmipp_byteproc_pix_map *
81 dcmipp_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
93 struct dcmipp_byteproc_device {
94         struct dcmipp_ent_device ved;
95         struct v4l2_subdev sd;
96         struct device *dev;
97         void __iomem *regs;
98 };
99
100 static 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
111 static 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
118 static 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
126 static 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_JPEG_1X8 ||
134             fmt->code == MEDIA_BUS_FMT_SBGGR8_1X8 ||
135             fmt->code == MEDIA_BUS_FMT_SGBRG8_1X8 ||
136             fmt->code == MEDIA_BUS_FMT_SGRBG8_1X8 ||
137             fmt->code == MEDIA_BUS_FMT_SRGGB8_1X8) {
138                 r->width = fmt->width;
139                 r->height = fmt->height;
140                 return;
141         }
142
143         /* Adjust height - we can only perform 1/2 decimation */
144         if (r->height <= (fmt->height / 2))
145                 r->height = fmt->height / 2;
146         else
147                 r->height = fmt->height;
148
149         /* Adjust width /2 or /4 for 8bits formats and /2 for 16bits formats */
150         if (fmt->code == MEDIA_BUS_FMT_Y8_1X8 && r->width <= (fmt->width / 4))
151                 r->width = fmt->width / 4;
152         else if (r->width <= (fmt->width / 2))
153                 r->width = fmt->width / 2;
154         else
155                 r->width = fmt->width;
156 }
157
158 static void dcmipp_byteproc_adjust_fmt(struct v4l2_mbus_framefmt *fmt)
159 {
160         const struct dcmipp_byteproc_pix_map *vpix;
161
162         /* Only accept code in the pix map table */
163         vpix = dcmipp_byteproc_pix_map_by_code(fmt->code);
164         if (!vpix)
165                 fmt->code = fmt_default.code;
166
167         fmt->width = clamp_t(u32, fmt->width, DCMIPP_FRAME_MIN_WIDTH,
168                              DCMIPP_FRAME_MAX_WIDTH) & ~1;
169         fmt->height = clamp_t(u32, fmt->height, DCMIPP_FRAME_MIN_HEIGHT,
170                               DCMIPP_FRAME_MAX_HEIGHT) & ~1;
171
172         if (fmt->field == V4L2_FIELD_ANY || fmt->field == V4L2_FIELD_ALTERNATE)
173                 fmt->field = fmt_default.field;
174
175         dcmipp_colorimetry_clamp(fmt);
176 }
177
178 static int dcmipp_byteproc_init_state(struct v4l2_subdev *sd,
179                                       struct v4l2_subdev_state *sd_state)
180 {
181         unsigned int i;
182
183         for (i = 0; i < sd->entity.num_pads; i++) {
184                 struct v4l2_mbus_framefmt *mf;
185                 struct v4l2_rect *r;
186
187                 mf = v4l2_subdev_state_get_format(sd_state, i);
188                 *mf = fmt_default;
189
190                 if (IS_SINK(i))
191                         r = v4l2_subdev_state_get_compose(sd_state, i);
192                 else
193                         r = v4l2_subdev_state_get_crop(sd_state, i);
194
195                 r->top = 0;
196                 r->left = 0;
197                 r->width = DCMIPP_FMT_WIDTH_DEFAULT;
198                 r->height = DCMIPP_FMT_HEIGHT_DEFAULT;
199         }
200
201         return 0;
202 }
203
204 static int
205 dcmipp_byteproc_enum_mbus_code(struct v4l2_subdev *sd,
206                                struct v4l2_subdev_state *sd_state,
207                                struct v4l2_subdev_mbus_code_enum *code)
208 {
209         const struct dcmipp_byteproc_pix_map *vpix;
210         struct v4l2_mbus_framefmt *sink_fmt;
211
212         if (IS_SINK(code->pad)) {
213                 if (code->index >= ARRAY_SIZE(dcmipp_byteproc_pix_map_list))
214                         return -EINVAL;
215                 vpix = &dcmipp_byteproc_pix_map_list[code->index];
216                 code->code = vpix->code;
217         } else {
218                 /* byteproc doesn't support transformation on format */
219                 if (code->index > 0)
220                         return -EINVAL;
221
222                 sink_fmt = v4l2_subdev_state_get_format(sd_state, 0);
223                 code->code = sink_fmt->code;
224         }
225
226         return 0;
227 }
228
229 static int
230 dcmipp_byteproc_enum_frame_size(struct v4l2_subdev *sd,
231                                 struct v4l2_subdev_state *sd_state,
232                                 struct v4l2_subdev_frame_size_enum *fse)
233 {
234         struct v4l2_rect *compose;
235
236         if (fse->index)
237                 return -EINVAL;
238
239         fse->min_width = DCMIPP_FRAME_MIN_WIDTH;
240         fse->min_height = DCMIPP_FRAME_MIN_HEIGHT;
241
242         if (IS_SINK(fse->pad)) {
243                 fse->max_width = DCMIPP_FRAME_MAX_WIDTH;
244                 fse->max_height = DCMIPP_FRAME_MAX_HEIGHT;
245         } else {
246                 compose = v4l2_subdev_state_get_compose(sd_state, 0);
247                 fse->max_width = compose->width;
248                 fse->max_height = compose->height;
249         }
250
251         return 0;
252 }
253
254 static int dcmipp_byteproc_set_fmt(struct v4l2_subdev *sd,
255                                    struct v4l2_subdev_state *sd_state,
256                                    struct v4l2_subdev_format *fmt)
257 {
258         struct v4l2_mbus_framefmt *mf;
259         struct v4l2_rect *crop, *compose;
260
261         if (v4l2_subdev_is_streaming(sd))
262                 return -EBUSY;
263
264         mf = v4l2_subdev_state_get_format(sd_state, fmt->pad);
265
266         crop = v4l2_subdev_state_get_crop(sd_state, 1);
267         compose = v4l2_subdev_state_get_compose(sd_state, 0);
268
269         if (IS_SRC(fmt->pad)) {
270                 fmt->format = *v4l2_subdev_state_get_format(sd_state, 0);
271                 fmt->format.width = crop->width;
272                 fmt->format.height = crop->height;
273         } else {
274                 dcmipp_byteproc_adjust_fmt(&fmt->format);
275                 crop->top = 0;
276                 crop->left = 0;
277                 crop->width = fmt->format.width;
278                 crop->height = fmt->format.height;
279                 *compose = *crop;
280                 /* Set the same format on SOURCE pad as well */
281                 *v4l2_subdev_state_get_format(sd_state, 1) = fmt->format;
282         }
283         *mf = fmt->format;
284
285         return 0;
286 }
287
288 static int dcmipp_byteproc_get_selection(struct v4l2_subdev *sd,
289                                          struct v4l2_subdev_state *sd_state,
290                                          struct v4l2_subdev_selection *s)
291 {
292         struct v4l2_mbus_framefmt *sink_fmt;
293         struct v4l2_rect *crop, *compose;
294
295         /*
296          * In the HW, the decimation block is located prior to the crop hence:
297          * Compose is done on the sink pad
298          * Crop is done on the src pad
299          */
300         if (IS_SINK(s->pad) &&
301             (s->target == V4L2_SEL_TGT_CROP ||
302              s->target == V4L2_SEL_TGT_CROP_BOUNDS ||
303              s->target == V4L2_SEL_TGT_CROP_DEFAULT))
304                 return -EINVAL;
305
306         if (IS_SRC(s->pad) &&
307             (s->target == V4L2_SEL_TGT_COMPOSE ||
308              s->target == V4L2_SEL_TGT_COMPOSE_BOUNDS ||
309              s->target == V4L2_SEL_TGT_COMPOSE_DEFAULT))
310                 return -EINVAL;
311
312         sink_fmt = v4l2_subdev_state_get_format(sd_state, 0);
313         crop = v4l2_subdev_state_get_crop(sd_state, 1);
314         compose = v4l2_subdev_state_get_compose(sd_state, 0);
315
316         switch (s->target) {
317         case V4L2_SEL_TGT_CROP:
318                 s->r = *crop;
319                 break;
320         case V4L2_SEL_TGT_CROP_BOUNDS:
321         case V4L2_SEL_TGT_CROP_DEFAULT:
322                 s->r = *compose;
323                 break;
324         case V4L2_SEL_TGT_COMPOSE:
325                 s->r = *compose;
326                 break;
327         case V4L2_SEL_TGT_COMPOSE_BOUNDS:
328         case V4L2_SEL_TGT_COMPOSE_DEFAULT:
329                 s->r.top = 0;
330                 s->r.left = 0;
331                 s->r.width = sink_fmt->width;
332                 s->r.height = sink_fmt->height;
333                 break;
334         default:
335                 return -EINVAL;
336         }
337
338         return 0;
339 }
340
341 static int dcmipp_byteproc_set_selection(struct v4l2_subdev *sd,
342                                          struct v4l2_subdev_state *sd_state,
343                                          struct v4l2_subdev_selection *s)
344 {
345         struct dcmipp_byteproc_device *byteproc = v4l2_get_subdevdata(sd);
346         struct v4l2_mbus_framefmt *mf;
347         struct v4l2_rect *crop, *compose;
348
349         /*
350          * In the HW, the decimation block is located prior to the crop hence:
351          * Compose is done on the sink pad
352          * Crop is done on the src pad
353          */
354         if ((s->target == V4L2_SEL_TGT_CROP ||
355              s->target == V4L2_SEL_TGT_CROP_BOUNDS ||
356              s->target == V4L2_SEL_TGT_CROP_DEFAULT) && IS_SINK(s->pad))
357                 return -EINVAL;
358
359         if ((s->target == V4L2_SEL_TGT_COMPOSE ||
360              s->target == V4L2_SEL_TGT_COMPOSE_BOUNDS ||
361              s->target == V4L2_SEL_TGT_COMPOSE_DEFAULT) && IS_SRC(s->pad))
362                 return -EINVAL;
363
364         crop = v4l2_subdev_state_get_crop(sd_state, 1);
365         compose = v4l2_subdev_state_get_compose(sd_state, 0);
366
367         switch (s->target) {
368         case V4L2_SEL_TGT_CROP:
369                 dcmipp_byteproc_adjust_crop(&s->r, compose);
370
371                 *crop = s->r;
372                 mf = v4l2_subdev_state_get_format(sd_state, 1);
373                 mf->width = s->r.width;
374                 mf->height = s->r.height;
375
376                 dev_dbg(byteproc->dev, "s_selection: crop %ux%u@(%u,%u)\n",
377                         crop->width, crop->height, crop->left, crop->top);
378                 break;
379         case V4L2_SEL_TGT_COMPOSE:
380                 mf = v4l2_subdev_state_get_format(sd_state, 0);
381                 dcmipp_byteproc_adjust_compose(&s->r, mf);
382                 *compose = s->r;
383                 *crop = s->r;
384
385                 mf = v4l2_subdev_state_get_format(sd_state, 1);
386                 mf->width = s->r.width;
387                 mf->height = s->r.height;
388
389                 dev_dbg(byteproc->dev, "s_selection: compose %ux%u@(%u,%u)\n",
390                         compose->width, compose->height,
391                         compose->left, compose->top);
392                 break;
393         default:
394                 return -EINVAL;
395         }
396
397         return 0;
398 }
399
400 static int dcmipp_byteproc_configure_scale_crop
401                         (struct dcmipp_byteproc_device *byteproc,
402                          struct v4l2_subdev_state *state)
403 {
404         const struct dcmipp_byteproc_pix_map *vpix;
405         struct v4l2_mbus_framefmt *sink_fmt;
406         u32 hprediv, vprediv;
407         struct v4l2_rect *compose, *crop;
408         u32 val = 0;
409
410         sink_fmt = v4l2_subdev_state_get_format(state, 0);
411         compose = v4l2_subdev_state_get_compose(state, 0);
412         crop = v4l2_subdev_state_get_crop(state, 1);
413
414         /* find output format bpp */
415         vpix = dcmipp_byteproc_pix_map_by_code(sink_fmt->code);
416         if (!vpix)
417                 return -EINVAL;
418
419         /* clear decimation/crop */
420         reg_clear(byteproc, DCMIPP_P0PPCR, DCMIPP_P0PPCR_BSM_MASK);
421         reg_clear(byteproc, DCMIPP_P0PPCR, DCMIPP_P0PPCR_LSM);
422         reg_write(byteproc, DCMIPP_P0SCSTR, 0);
423         reg_write(byteproc, DCMIPP_P0SCSZR, 0);
424
425         /* Ignore decimation/crop with JPEG */
426         if (vpix->code == MEDIA_BUS_FMT_JPEG_1X8)
427                 return 0;
428
429         /* decimation */
430         hprediv = sink_fmt->width / compose->width;
431         if (hprediv == 4)
432                 val |= DCMIPP_P0PPCR_BSM_1_4 << DCMIPP_P0PPCR_BSM_SHIFT;
433         else if ((vpix->code == MEDIA_BUS_FMT_Y8_1X8) && (hprediv == 2))
434                 val |= DCMIPP_P0PPCR_BSM_1_2 << DCMIPP_P0PPCR_BSM_SHIFT;
435         else if (hprediv == 2)
436                 val |= DCMIPP_P0PPCR_BSM_2_4 << DCMIPP_P0PPCR_BSM_SHIFT;
437
438         vprediv = sink_fmt->height / compose->height;
439         if (vprediv == 2)
440                 val |= DCMIPP_P0PPCR_LSM | DCMIPP_P0PPCR_OELS;
441
442         /* decimate using bytes and lines skipping */
443         if (val) {
444                 reg_set(byteproc, DCMIPP_P0PPCR, val);
445
446                 dev_dbg(byteproc->dev, "decimate to %dx%d [prediv=%dx%d]\n",
447                         compose->width, compose->height,
448                         hprediv, vprediv);
449         }
450
451         dev_dbg(byteproc->dev, "crop to %dx%d\n", crop->width, crop->height);
452
453         /* expressed in 32-bits words on X axis, lines on Y axis */
454         reg_write(byteproc, DCMIPP_P0SCSTR,
455                   (((crop->left * vpix->bpp) / 4) <<
456                    DCMIPP_P0SCSTR_HSTART_SHIFT) |
457                   (crop->top << DCMIPP_P0SCSTR_VSTART_SHIFT));
458         reg_write(byteproc, DCMIPP_P0SCSZR,
459                   DCMIPP_P0SCSZR_ENABLE |
460                   (((crop->width * vpix->bpp) / 4) <<
461                    DCMIPP_P0SCSZR_HSIZE_SHIFT) |
462                   (crop->height << DCMIPP_P0SCSZR_VSIZE_SHIFT));
463
464         return 0;
465 }
466
467 static int dcmipp_byteproc_enable_streams(struct v4l2_subdev *sd,
468                                           struct v4l2_subdev_state *state,
469                                           u32 pad, u64 streams_mask)
470 {
471         struct dcmipp_byteproc_device *byteproc = v4l2_get_subdevdata(sd);
472         struct v4l2_subdev *s_subdev;
473         struct media_pad *s_pad;
474         int ret;
475
476         /* Get source subdev */
477         s_pad = media_pad_remote_pad_first(&sd->entity.pads[0]);
478         if (!s_pad || !is_media_entity_v4l2_subdev(s_pad->entity))
479                 return -EINVAL;
480         s_subdev = media_entity_to_v4l2_subdev(s_pad->entity);
481
482         ret = dcmipp_byteproc_configure_scale_crop(byteproc, state);
483         if (ret)
484                 return ret;
485
486         ret = v4l2_subdev_enable_streams(s_subdev, s_pad->index, BIT_ULL(0));
487         if (ret < 0) {
488                 dev_err(byteproc->dev,
489                         "failed to start source subdev streaming (%d)\n", ret);
490                 return ret;
491         }
492
493         return 0;
494 }
495
496 static int dcmipp_byteproc_disable_streams(struct v4l2_subdev *sd,
497                                            struct v4l2_subdev_state *state,
498                                            u32 pad, u64 streams_mask)
499 {
500         struct dcmipp_byteproc_device *byteproc = v4l2_get_subdevdata(sd);
501         struct v4l2_subdev *s_subdev;
502         struct media_pad *s_pad;
503         int ret;
504
505         /* Get source subdev */
506         s_pad = media_pad_remote_pad_first(&sd->entity.pads[0]);
507         if (!s_pad || !is_media_entity_v4l2_subdev(s_pad->entity))
508                 return -EINVAL;
509         s_subdev = media_entity_to_v4l2_subdev(s_pad->entity);
510
511         ret = v4l2_subdev_disable_streams(s_subdev, s_pad->index, BIT_ULL(0));
512         if (ret < 0) {
513                 dev_err(byteproc->dev,
514                         "failed to start source subdev streaming (%d)\n", ret);
515                 return ret;
516         }
517
518         return 0;
519 }
520
521 static const struct v4l2_subdev_pad_ops dcmipp_byteproc_pad_ops = {
522         .enum_mbus_code         = dcmipp_byteproc_enum_mbus_code,
523         .enum_frame_size        = dcmipp_byteproc_enum_frame_size,
524         .get_fmt                = v4l2_subdev_get_fmt,
525         .set_fmt                = dcmipp_byteproc_set_fmt,
526         .get_selection          = dcmipp_byteproc_get_selection,
527         .set_selection          = dcmipp_byteproc_set_selection,
528         .enable_streams         = dcmipp_byteproc_enable_streams,
529         .disable_streams        = dcmipp_byteproc_disable_streams,
530 };
531
532 static const struct v4l2_subdev_video_ops dcmipp_byteproc_video_ops = {
533         .s_stream = v4l2_subdev_s_stream_helper,
534 };
535
536 static const struct v4l2_subdev_ops dcmipp_byteproc_ops = {
537         .pad = &dcmipp_byteproc_pad_ops,
538         .video = &dcmipp_byteproc_video_ops,
539 };
540
541 static void dcmipp_byteproc_release(struct v4l2_subdev *sd)
542 {
543         struct dcmipp_byteproc_device *byteproc = v4l2_get_subdevdata(sd);
544
545         kfree(byteproc);
546 }
547
548 static const struct v4l2_subdev_internal_ops dcmipp_byteproc_int_ops = {
549         .init_state = dcmipp_byteproc_init_state,
550         .release = dcmipp_byteproc_release,
551 };
552
553 void dcmipp_byteproc_ent_release(struct dcmipp_ent_device *ved)
554 {
555         struct dcmipp_byteproc_device *byteproc =
556                         container_of(ved, struct dcmipp_byteproc_device, ved);
557
558         dcmipp_ent_sd_unregister(ved, &byteproc->sd);
559 }
560
561 struct dcmipp_ent_device *
562 dcmipp_byteproc_ent_init(struct device *dev, const char *entity_name,
563                          struct v4l2_device *v4l2_dev, void __iomem *regs)
564 {
565         struct dcmipp_byteproc_device *byteproc;
566         const unsigned long pads_flag[] = {
567                 MEDIA_PAD_FL_SINK, MEDIA_PAD_FL_SOURCE,
568         };
569         int ret;
570
571         /* Allocate the byteproc struct */
572         byteproc = kzalloc(sizeof(*byteproc), GFP_KERNEL);
573         if (!byteproc)
574                 return ERR_PTR(-ENOMEM);
575
576         byteproc->regs = regs;
577
578         /* Initialize ved and sd */
579         ret = dcmipp_ent_sd_register(&byteproc->ved, &byteproc->sd,
580                                      v4l2_dev, entity_name,
581                                      MEDIA_ENT_F_PROC_VIDEO_SCALER,
582                                      ARRAY_SIZE(pads_flag), pads_flag,
583                                      &dcmipp_byteproc_int_ops,
584                                      &dcmipp_byteproc_ops,
585                                      NULL, NULL);
586         if (ret) {
587                 kfree(byteproc);
588                 return ERR_PTR(ret);
589         }
590
591         byteproc->dev = dev;
592
593         return &byteproc->ved;
594 }
This page took 0.062138 seconds and 4 git commands to generate.