FILE
dcmipp-byteproc.c
File preview with syntax highlighting.
linux-6.19.14/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 <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.