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 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 } 595