1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Support for Medifield PNW Camera Imaging ISP subsystem. 4 * 5 * Copyright (c) 2010 Intel Corporation. All Rights Reserved. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License version 9 * 2 as published by the Free Software Foundation. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * 17 */ 18 #include <linux/module.h> 19 #include <linux/uaccess.h> 20 #include <linux/delay.h> 21 #include <linux/device.h> 22 #include <linux/mm.h> 23 #include <linux/sched.h> 24 #include <linux/slab.h> 25 26 #include <media/v4l2-event.h> 27 #include <media/v4l2-mediabus.h> 28 #include <media/videobuf2-vmalloc.h> 29 #include "atomisp_cmd.h" 30 #include "atomisp_common.h" 31 #include "atomisp_compat.h" 32 #include "atomisp_fops.h" 33 #include "atomisp_internal.h" 34 35 const struct atomisp_in_fmt_conv atomisp_in_fmt_conv[] = { 36 { MEDIA_BUS_FMT_SBGGR8_1X8, 8, 8, ATOMISP_INPUT_FORMAT_RAW_8, IA_CSS_BAYER_ORDER_BGGR }, 37 { MEDIA_BUS_FMT_SGBRG8_1X8, 8, 8, ATOMISP_INPUT_FORMAT_RAW_8, IA_CSS_BAYER_ORDER_GBRG }, 38 { MEDIA_BUS_FMT_SGRBG8_1X8, 8, 8, ATOMISP_INPUT_FORMAT_RAW_8, IA_CSS_BAYER_ORDER_GRBG }, 39 { MEDIA_BUS_FMT_SRGGB8_1X8, 8, 8, ATOMISP_INPUT_FORMAT_RAW_8, IA_CSS_BAYER_ORDER_RGGB }, 40 { MEDIA_BUS_FMT_SBGGR10_1X10, 10, 10, ATOMISP_INPUT_FORMAT_RAW_10, IA_CSS_BAYER_ORDER_BGGR }, 41 { MEDIA_BUS_FMT_SGBRG10_1X10, 10, 10, ATOMISP_INPUT_FORMAT_RAW_10, IA_CSS_BAYER_ORDER_GBRG }, 42 { MEDIA_BUS_FMT_SGRBG10_1X10, 10, 10, ATOMISP_INPUT_FORMAT_RAW_10, IA_CSS_BAYER_ORDER_GRBG }, 43 { MEDIA_BUS_FMT_SRGGB10_1X10, 10, 10, ATOMISP_INPUT_FORMAT_RAW_10, IA_CSS_BAYER_ORDER_RGGB }, 44 { MEDIA_BUS_FMT_SBGGR12_1X12, 12, 12, ATOMISP_INPUT_FORMAT_RAW_12, IA_CSS_BAYER_ORDER_BGGR }, 45 { MEDIA_BUS_FMT_SGBRG12_1X12, 12, 12, ATOMISP_INPUT_FORMAT_RAW_12, IA_CSS_BAYER_ORDER_GBRG }, 46 { MEDIA_BUS_FMT_SGRBG12_1X12, 12, 12, ATOMISP_INPUT_FORMAT_RAW_12, IA_CSS_BAYER_ORDER_GRBG }, 47 { MEDIA_BUS_FMT_SRGGB12_1X12, 12, 12, ATOMISP_INPUT_FORMAT_RAW_12, IA_CSS_BAYER_ORDER_RGGB }, 48 { MEDIA_BUS_FMT_UYVY8_1X16, 8, 8, ATOMISP_INPUT_FORMAT_YUV422_8, 0 }, 49 { MEDIA_BUS_FMT_YUYV8_1X16, 8, 8, ATOMISP_INPUT_FORMAT_YUV422_8, 0 }, 50 #if 0 // disabled due to clang warnings 51 { MEDIA_BUS_FMT_JPEG_1X8, 8, 8, IA_CSS_FRAME_FORMAT_BINARY_8, 0 }, 52 { V4L2_MBUS_FMT_CUSTOM_NV12, 12, 12, IA_CSS_FRAME_FORMAT_NV12, 0 }, 53 { V4L2_MBUS_FMT_CUSTOM_NV21, 12, 12, IA_CSS_FRAME_FORMAT_NV21, 0 }, 54 #endif 55 { V4L2_MBUS_FMT_CUSTOM_YUV420, 12, 12, ATOMISP_INPUT_FORMAT_YUV420_8_LEGACY, 0 }, 56 #if 0 57 { V4L2_MBUS_FMT_CUSTOM_M10MO_RAW, 8, 8, IA_CSS_FRAME_FORMAT_BINARY_8, 0 }, 58 #endif 59 /* no valid V4L2 MBUS code for metadata format, so leave it 0. */ 60 { 0, 0, 0, ATOMISP_INPUT_FORMAT_EMBEDDED, 0 }, 61 {} 62 }; 63 64 static const struct { 65 u32 code; 66 u32 compressed; 67 } compressed_codes[] = { 68 { MEDIA_BUS_FMT_SBGGR10_1X10, MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8 }, 69 { MEDIA_BUS_FMT_SGBRG10_1X10, MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8 }, 70 { MEDIA_BUS_FMT_SGRBG10_1X10, MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8 }, 71 { MEDIA_BUS_FMT_SRGGB10_1X10, MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8 }, 72 }; 73 74 u32 atomisp_subdev_uncompressed_code(u32 code) 75 { 76 unsigned int i; 77 78 for (i = 0; i < ARRAY_SIZE(compressed_codes); i++) 79 if (code == compressed_codes[i].compressed) 80 return compressed_codes[i].code; 81 82 return code; 83 } 84 85 bool atomisp_subdev_is_compressed(u32 code) 86 { 87 int i; 88 89 for (i = 0; i < ARRAY_SIZE(atomisp_in_fmt_conv) - 1; i++) 90 if (code == atomisp_in_fmt_conv[i].code) 91 return atomisp_in_fmt_conv[i].bpp != 92 atomisp_in_fmt_conv[i].depth; 93 94 return false; 95 } 96 97 const struct atomisp_in_fmt_conv *atomisp_find_in_fmt_conv(u32 code) 98 { 99 int i; 100 101 for (i = 0; i < ARRAY_SIZE(atomisp_in_fmt_conv) - 1; i++) 102 if (code == atomisp_in_fmt_conv[i].code) 103 return atomisp_in_fmt_conv + i; 104 105 return NULL; 106 } 107 108 const struct atomisp_in_fmt_conv *atomisp_find_in_fmt_conv_by_atomisp_in_fmt( 109 enum atomisp_input_format atomisp_in_fmt) 110 { 111 int i; 112 113 for (i = 0; i < ARRAY_SIZE(atomisp_in_fmt_conv) - 1; i++) 114 if (atomisp_in_fmt_conv[i].atomisp_in_fmt == atomisp_in_fmt) 115 return atomisp_in_fmt_conv + i; 116 117 return NULL; 118 } 119 120 bool atomisp_subdev_format_conversion(struct atomisp_sub_device *asd, 121 unsigned int source_pad) 122 { 123 struct v4l2_mbus_framefmt *sink, *src; 124 125 sink = atomisp_subdev_get_ffmt(&asd->subdev, NULL, 126 V4L2_SUBDEV_FORMAT_ACTIVE, 127 ATOMISP_SUBDEV_PAD_SINK); 128 src = atomisp_subdev_get_ffmt(&asd->subdev, NULL, 129 V4L2_SUBDEV_FORMAT_ACTIVE, source_pad); 130 131 return atomisp_is_mbuscode_raw(sink->code) 132 && !atomisp_is_mbuscode_raw(src->code); 133 } 134 135 uint16_t atomisp_subdev_source_pad(struct video_device *vdev) 136 { 137 struct media_link *link; 138 u16 ret = 0; 139 140 list_for_each_entry(link, &vdev->entity.links, list) { 141 if (link->source) { 142 ret = link->source->index; 143 break; 144 } 145 } 146 return ret; 147 } 148 149 /* 150 * V4L2 subdev operations 151 */ 152 153 /* 154 * isp_subdev_ioctl - CCDC module private ioctl's 155 * @sd: ISP V4L2 subdevice 156 * @cmd: ioctl command 157 * @arg: ioctl argument 158 * 159 * Return 0 on success or a negative error code otherwise. 160 */ 161 static long isp_subdev_ioctl(struct v4l2_subdev *sd, 162 unsigned int cmd, void *arg) 163 { 164 return 0; 165 } 166 167 /* 168 * isp_subdev_set_power - Power on/off the CCDC module 169 * @sd: ISP V4L2 subdevice 170 * @on: power on/off 171 * 172 * Return 0 on success or a negative error code otherwise. 173 */ 174 static int isp_subdev_set_power(struct v4l2_subdev *sd, int on) 175 { 176 return 0; 177 } 178 179 static int isp_subdev_subscribe_event(struct v4l2_subdev *sd, 180 struct v4l2_fh *fh, 181 struct v4l2_event_subscription *sub) 182 { 183 struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd); 184 struct atomisp_device *isp = isp_sd->isp; 185 186 if (sub->type != V4L2_EVENT_FRAME_SYNC && 187 sub->type != V4L2_EVENT_FRAME_END && 188 sub->type != V4L2_EVENT_ATOMISP_3A_STATS_READY && 189 sub->type != V4L2_EVENT_ATOMISP_METADATA_READY && 190 sub->type != V4L2_EVENT_ATOMISP_PAUSE_BUFFER && 191 sub->type != V4L2_EVENT_ATOMISP_CSS_RESET && 192 sub->type != V4L2_EVENT_ATOMISP_ACC_COMPLETE) 193 return -EINVAL; 194 195 if (sub->type == V4L2_EVENT_FRAME_SYNC && 196 !atomisp_css_valid_sof(isp)) 197 return -EINVAL; 198 199 return v4l2_event_subscribe(fh, sub, 16, NULL); 200 } 201 202 static int isp_subdev_unsubscribe_event(struct v4l2_subdev *sd, 203 struct v4l2_fh *fh, 204 struct v4l2_event_subscription *sub) 205 { 206 return v4l2_event_unsubscribe(fh, sub); 207 } 208 209 /* 210 * isp_subdev_enum_mbus_code - Handle pixel format enumeration 211 * @sd: pointer to v4l2 subdev structure 212 * @fh : V4L2 subdev file handle 213 * @code: pointer to v4l2_subdev_pad_mbus_code_enum structure 214 * return -EINVAL or zero on success 215 */ 216 static int isp_subdev_enum_mbus_code(struct v4l2_subdev *sd, 217 struct v4l2_subdev_state *sd_state, 218 struct v4l2_subdev_mbus_code_enum *code) 219 { 220 if (code->index >= ARRAY_SIZE(atomisp_in_fmt_conv) - 1) 221 return -EINVAL; 222 223 code->code = atomisp_in_fmt_conv[code->index].code; 224 225 return 0; 226 } 227 228 static int isp_subdev_validate_rect(struct v4l2_subdev *sd, uint32_t pad, 229 uint32_t target) 230 { 231 switch (pad) { 232 case ATOMISP_SUBDEV_PAD_SINK: 233 switch (target) { 234 case V4L2_SEL_TGT_CROP: 235 return 0; 236 } 237 break; 238 default: 239 switch (target) { 240 case V4L2_SEL_TGT_COMPOSE: 241 return 0; 242 } 243 break; 244 } 245 246 return -EINVAL; 247 } 248 249 struct v4l2_rect *atomisp_subdev_get_rect(struct v4l2_subdev *sd, 250 struct v4l2_subdev_state *sd_state, 251 u32 which, uint32_t pad, 252 uint32_t target) 253 { 254 struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd); 255 256 if (which == V4L2_SUBDEV_FORMAT_TRY) { 257 switch (target) { 258 case V4L2_SEL_TGT_CROP: 259 return v4l2_subdev_get_try_crop(sd, sd_state, pad); 260 case V4L2_SEL_TGT_COMPOSE: 261 return v4l2_subdev_get_try_compose(sd, sd_state, pad); 262 } 263 } 264 265 switch (target) { 266 case V4L2_SEL_TGT_CROP: 267 return &isp_sd->fmt[pad].crop; 268 case V4L2_SEL_TGT_COMPOSE: 269 return &isp_sd->fmt[pad].compose; 270 } 271 272 return NULL; 273 } 274 275 struct v4l2_mbus_framefmt 276 *atomisp_subdev_get_ffmt(struct v4l2_subdev *sd, 277 struct v4l2_subdev_state *sd_state, uint32_t which, 278 uint32_t pad) 279 { 280 struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd); 281 282 if (which == V4L2_SUBDEV_FORMAT_TRY) 283 return v4l2_subdev_get_try_format(sd, sd_state, pad); 284 285 return &isp_sd->fmt[pad].fmt; 286 } 287 288 static void isp_get_fmt_rect(struct v4l2_subdev *sd, 289 struct v4l2_subdev_state *sd_state, 290 uint32_t which, 291 struct v4l2_mbus_framefmt **ffmt, 292 struct v4l2_rect *crop[ATOMISP_SUBDEV_PADS_NUM], 293 struct v4l2_rect *comp[ATOMISP_SUBDEV_PADS_NUM]) 294 { 295 unsigned int i; 296 297 for (i = 0; i < ATOMISP_SUBDEV_PADS_NUM; i++) { 298 ffmt[i] = atomisp_subdev_get_ffmt(sd, sd_state, which, i); 299 crop[i] = atomisp_subdev_get_rect(sd, sd_state, which, i, 300 V4L2_SEL_TGT_CROP); 301 comp[i] = atomisp_subdev_get_rect(sd, sd_state, which, i, 302 V4L2_SEL_TGT_COMPOSE); 303 } 304 } 305 306 static void isp_subdev_propagate(struct v4l2_subdev *sd, 307 struct v4l2_subdev_state *sd_state, 308 u32 which, uint32_t pad, uint32_t target, 309 uint32_t flags) 310 { 311 struct v4l2_mbus_framefmt *ffmt[ATOMISP_SUBDEV_PADS_NUM]; 312 struct v4l2_rect *crop[ATOMISP_SUBDEV_PADS_NUM], 313 *comp[ATOMISP_SUBDEV_PADS_NUM]; 314 315 if (flags & V4L2_SEL_FLAG_KEEP_CONFIG) 316 return; 317 318 isp_get_fmt_rect(sd, sd_state, which, ffmt, crop, comp); 319 320 switch (pad) { 321 case ATOMISP_SUBDEV_PAD_SINK: { 322 struct v4l2_rect r = {0}; 323 324 /* Only crop target supported on sink pad. */ 325 r.width = ffmt[pad]->width; 326 r.height = ffmt[pad]->height; 327 328 atomisp_subdev_set_selection(sd, sd_state, which, pad, 329 target, flags, &r); 330 break; 331 } 332 } 333 } 334 335 static int isp_subdev_get_selection(struct v4l2_subdev *sd, 336 struct v4l2_subdev_state *sd_state, 337 struct v4l2_subdev_selection *sel) 338 { 339 struct v4l2_rect *rec; 340 int rval = isp_subdev_validate_rect(sd, sel->pad, sel->target); 341 342 if (rval) 343 return rval; 344 345 rec = atomisp_subdev_get_rect(sd, sd_state, sel->which, sel->pad, 346 sel->target); 347 if (!rec) 348 return -EINVAL; 349 350 sel->r = *rec; 351 return 0; 352 } 353 354 static const char *atomisp_pad_str(unsigned int pad) 355 { 356 static const char *const pad_str[] = { 357 "ATOMISP_SUBDEV_PAD_SINK", 358 "ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE", 359 "ATOMISP_SUBDEV_PAD_SOURCE_VF", 360 "ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW", 361 "ATOMISP_SUBDEV_PAD_SOURCE_VIDEO", 362 }; 363 364 if (pad >= ARRAY_SIZE(pad_str)) 365 return "ATOMISP_INVALID_PAD"; 366 return pad_str[pad]; 367 } 368 369 int atomisp_subdev_set_selection(struct v4l2_subdev *sd, 370 struct v4l2_subdev_state *sd_state, 371 u32 which, uint32_t pad, uint32_t target, 372 u32 flags, struct v4l2_rect *r) 373 { 374 struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd); 375 struct atomisp_device *isp = isp_sd->isp; 376 struct v4l2_mbus_framefmt *ffmt[ATOMISP_SUBDEV_PADS_NUM]; 377 struct v4l2_rect *crop[ATOMISP_SUBDEV_PADS_NUM], 378 *comp[ATOMISP_SUBDEV_PADS_NUM]; 379 unsigned int i; 380 unsigned int padding_w = pad_w; 381 unsigned int padding_h = pad_h; 382 383 isp_get_fmt_rect(sd, sd_state, which, ffmt, crop, comp); 384 385 dev_dbg(isp->dev, 386 "sel: pad %s tgt %s l %d t %d w %d h %d which %s f 0x%8.8x\n", 387 atomisp_pad_str(pad), target == V4L2_SEL_TGT_CROP 388 ? "V4L2_SEL_TGT_CROP" : "V4L2_SEL_TGT_COMPOSE", 389 r->left, r->top, r->width, r->height, 390 which == V4L2_SUBDEV_FORMAT_TRY ? "V4L2_SUBDEV_FORMAT_TRY" 391 : "V4L2_SUBDEV_FORMAT_ACTIVE", flags); 392 393 r->width = rounddown(r->width, ATOM_ISP_STEP_WIDTH); 394 r->height = rounddown(r->height, ATOM_ISP_STEP_HEIGHT); 395 396 switch (pad) { 397 case ATOMISP_SUBDEV_PAD_SINK: { 398 /* Only crop target supported on sink pad. */ 399 unsigned int dvs_w, dvs_h; 400 401 crop[pad]->width = ffmt[pad]->width; 402 crop[pad]->height = ffmt[pad]->height; 403 404 /* Workaround for BYT 1080p perfectshot since the maxinum resolution of 405 * front camera ov2722 is 1932x1092 and cannot use pad_w > 12*/ 406 if (!strncmp(isp->inputs[isp_sd->input_curr].camera->name, 407 "ov2722", 6) && crop[pad]->height == 1092) { 408 padding_w = 12; 409 padding_h = 12; 410 } 411 412 if (atomisp_subdev_format_conversion(isp_sd, 413 isp_sd->capture_pad) 414 && crop[pad]->width && crop[pad]->height) { 415 crop[pad]->width -= padding_w; 416 crop[pad]->height -= padding_h; 417 } 418 419 if (isp_sd->params.video_dis_en && 420 isp_sd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) { 421 /* This resolution contains 20 % of DVS slack 422 * (of the desired captured image before 423 * scaling, or 1 / 6 of what we get from the 424 * sensor) in both width and height. Remove 425 * it. */ 426 crop[pad]->width = roundup(crop[pad]->width * 5 / 6, 427 ATOM_ISP_STEP_WIDTH); 428 crop[pad]->height = roundup(crop[pad]->height * 5 / 6, 429 ATOM_ISP_STEP_HEIGHT); 430 } 431 432 crop[pad]->width = min(crop[pad]->width, r->width); 433 crop[pad]->height = min(crop[pad]->height, r->height); 434 435 if (!(flags & V4L2_SEL_FLAG_KEEP_CONFIG)) { 436 for (i = ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE; 437 i < ATOMISP_SUBDEV_PADS_NUM; i++) { 438 struct v4l2_rect tmp = *crop[pad]; 439 440 atomisp_subdev_set_selection( 441 sd, sd_state, which, i, 442 V4L2_SEL_TGT_COMPOSE, 443 flags, &tmp); 444 } 445 } 446 447 if (which == V4L2_SUBDEV_FORMAT_TRY) 448 break; 449 450 if (isp_sd->params.video_dis_en && 451 isp_sd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) { 452 dvs_w = rounddown(crop[pad]->width / 5, 453 ATOM_ISP_STEP_WIDTH); 454 dvs_h = rounddown(crop[pad]->height / 5, 455 ATOM_ISP_STEP_HEIGHT); 456 } else if (!isp_sd->params.video_dis_en && 457 isp_sd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) { 458 /* 459 * For CSS2.0, digital zoom needs to set dvs envelope to 12 460 * when dvs is disabled. 461 */ 462 dvs_w = dvs_h = 12; 463 } else { 464 dvs_w = dvs_h = 0; 465 } 466 atomisp_css_video_set_dis_envelope(isp_sd, dvs_w, dvs_h); 467 atomisp_css_input_set_effective_resolution(isp_sd, 468 ATOMISP_INPUT_STREAM_GENERAL, 469 crop[pad]->width, 470 crop[pad]->height); 471 break; 472 } 473 case ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE: 474 case ATOMISP_SUBDEV_PAD_SOURCE_VIDEO: { 475 /* Only compose target is supported on source pads. */ 476 477 if (isp_sd->vfpp->val == ATOMISP_VFPP_DISABLE_LOWLAT) { 478 /* Scaling is disabled in this mode */ 479 r->width = crop[ATOMISP_SUBDEV_PAD_SINK]->width; 480 r->height = crop[ATOMISP_SUBDEV_PAD_SINK]->height; 481 } 482 483 if (crop[ATOMISP_SUBDEV_PAD_SINK]->width == r->width 484 && crop[ATOMISP_SUBDEV_PAD_SINK]->height == r->height) 485 isp_sd->params.yuv_ds_en = false; 486 else 487 isp_sd->params.yuv_ds_en = true; 488 489 comp[pad]->width = r->width; 490 comp[pad]->height = r->height; 491 492 if (r->width == 0 || r->height == 0 || 493 crop[ATOMISP_SUBDEV_PAD_SINK]->width == 0 || 494 crop[ATOMISP_SUBDEV_PAD_SINK]->height == 0) 495 break; 496 /* 497 * do cropping on sensor input if ratio of required resolution 498 * is different with sensor output resolution ratio: 499 * 500 * ratio = width / height 501 * 502 * if ratio_output < ratio_sensor: 503 * effect_width = sensor_height * out_width / out_height; 504 * effect_height = sensor_height; 505 * else 506 * effect_width = sensor_width; 507 * effect_height = sensor_width * out_height / out_width; 508 * 509 */ 510 if (r->width * crop[ATOMISP_SUBDEV_PAD_SINK]->height < 511 crop[ATOMISP_SUBDEV_PAD_SINK]->width * r->height) 512 atomisp_css_input_set_effective_resolution(isp_sd, 513 ATOMISP_INPUT_STREAM_GENERAL, 514 rounddown(crop[ATOMISP_SUBDEV_PAD_SINK]-> 515 height * r->width / r->height, 516 ATOM_ISP_STEP_WIDTH), 517 crop[ATOMISP_SUBDEV_PAD_SINK]->height); 518 else 519 atomisp_css_input_set_effective_resolution(isp_sd, 520 ATOMISP_INPUT_STREAM_GENERAL, 521 crop[ATOMISP_SUBDEV_PAD_SINK]->width, 522 rounddown(crop[ATOMISP_SUBDEV_PAD_SINK]-> 523 width * r->height / r->width, 524 ATOM_ISP_STEP_WIDTH)); 525 526 break; 527 } 528 case ATOMISP_SUBDEV_PAD_SOURCE_VF: 529 case ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW: 530 comp[pad]->width = r->width; 531 comp[pad]->height = r->height; 532 break; 533 default: 534 return -EINVAL; 535 } 536 537 /* Set format dimensions on non-sink pads as well. */ 538 if (pad != ATOMISP_SUBDEV_PAD_SINK) { 539 ffmt[pad]->width = comp[pad]->width; 540 ffmt[pad]->height = comp[pad]->height; 541 } 542 543 if (!atomisp_subdev_get_rect(sd, sd_state, which, pad, target)) 544 return -EINVAL; 545 *r = *atomisp_subdev_get_rect(sd, sd_state, which, pad, target); 546 547 dev_dbg(isp->dev, "sel actual: l %d t %d w %d h %d\n", 548 r->left, r->top, r->width, r->height); 549 550 return 0; 551 } 552 553 static int isp_subdev_set_selection(struct v4l2_subdev *sd, 554 struct v4l2_subdev_state *sd_state, 555 struct v4l2_subdev_selection *sel) 556 { 557 int rval = isp_subdev_validate_rect(sd, sel->pad, sel->target); 558 559 if (rval) 560 return rval; 561 562 return atomisp_subdev_set_selection(sd, sd_state, sel->which, 563 sel->pad, 564 sel->target, sel->flags, &sel->r); 565 } 566 567 void atomisp_subdev_set_ffmt(struct v4l2_subdev *sd, 568 struct v4l2_subdev_state *sd_state, 569 uint32_t which, 570 u32 pad, struct v4l2_mbus_framefmt *ffmt) 571 { 572 struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd); 573 struct atomisp_device *isp = isp_sd->isp; 574 struct v4l2_mbus_framefmt *__ffmt = 575 atomisp_subdev_get_ffmt(sd, sd_state, which, pad); 576 577 dev_dbg(isp->dev, "ffmt: pad %s w %d h %d code 0x%8.8x which %s\n", 578 atomisp_pad_str(pad), ffmt->width, ffmt->height, ffmt->code, 579 which == V4L2_SUBDEV_FORMAT_TRY ? "V4L2_SUBDEV_FORMAT_TRY" 580 : "V4L2_SUBDEV_FORMAT_ACTIVE"); 581 582 switch (pad) { 583 case ATOMISP_SUBDEV_PAD_SINK: { 584 const struct atomisp_in_fmt_conv *fc = 585 atomisp_find_in_fmt_conv(ffmt->code); 586 587 if (!fc) { 588 fc = atomisp_in_fmt_conv; 589 ffmt->code = fc->code; 590 dev_dbg(isp->dev, "using 0x%8.8x instead\n", 591 ffmt->code); 592 } 593 594 *__ffmt = *ffmt; 595 596 isp_subdev_propagate(sd, sd_state, which, pad, 597 V4L2_SEL_TGT_CROP, 0); 598 599 if (which == V4L2_SUBDEV_FORMAT_ACTIVE) { 600 atomisp_css_input_set_resolution(isp_sd, 601 ATOMISP_INPUT_STREAM_GENERAL, ffmt); 602 atomisp_css_input_set_binning_factor(isp_sd, 603 ATOMISP_INPUT_STREAM_GENERAL, 604 0); 605 atomisp_css_input_set_bayer_order(isp_sd, ATOMISP_INPUT_STREAM_GENERAL, 606 fc->bayer_order); 607 atomisp_css_input_set_format(isp_sd, ATOMISP_INPUT_STREAM_GENERAL, 608 fc->atomisp_in_fmt); 609 atomisp_css_set_default_isys_config(isp_sd, ATOMISP_INPUT_STREAM_GENERAL, 610 ffmt); 611 } 612 613 break; 614 } 615 case ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE: 616 case ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW: 617 case ATOMISP_SUBDEV_PAD_SOURCE_VF: 618 case ATOMISP_SUBDEV_PAD_SOURCE_VIDEO: 619 __ffmt->code = ffmt->code; 620 break; 621 } 622 } 623 624 /* 625 * isp_subdev_get_format - Retrieve the video format on a pad 626 * @sd : ISP V4L2 subdevice 627 * @fh : V4L2 subdev file handle 628 * @pad: Pad number 629 * @fmt: Format 630 * 631 * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond 632 * to the format type. 633 */ 634 static int isp_subdev_get_format(struct v4l2_subdev *sd, 635 struct v4l2_subdev_state *sd_state, 636 struct v4l2_subdev_format *fmt) 637 { 638 fmt->format = *atomisp_subdev_get_ffmt(sd, sd_state, fmt->which, 639 fmt->pad); 640 641 return 0; 642 } 643 644 /* 645 * isp_subdev_set_format - Set the video format on a pad 646 * @sd : ISP subdev V4L2 subdevice 647 * @fh : V4L2 subdev file handle 648 * @pad: Pad number 649 * @fmt: Format 650 * 651 * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond 652 * to the format type. 653 */ 654 static int isp_subdev_set_format(struct v4l2_subdev *sd, 655 struct v4l2_subdev_state *sd_state, 656 struct v4l2_subdev_format *fmt) 657 { 658 atomisp_subdev_set_ffmt(sd, sd_state, fmt->which, fmt->pad, 659 &fmt->format); 660 661 return 0; 662 } 663 664 /* V4L2 subdev core operations */ 665 static const struct v4l2_subdev_core_ops isp_subdev_v4l2_core_ops = { 666 .ioctl = isp_subdev_ioctl, .s_power = isp_subdev_set_power, 667 .subscribe_event = isp_subdev_subscribe_event, 668 .unsubscribe_event = isp_subdev_unsubscribe_event, 669 }; 670 671 /* V4L2 subdev pad operations */ 672 static const struct v4l2_subdev_pad_ops isp_subdev_v4l2_pad_ops = { 673 .enum_mbus_code = isp_subdev_enum_mbus_code, 674 .get_fmt = isp_subdev_get_format, 675 .set_fmt = isp_subdev_set_format, 676 .get_selection = isp_subdev_get_selection, 677 .set_selection = isp_subdev_set_selection, 678 .link_validate = v4l2_subdev_link_validate_default, 679 }; 680 681 /* V4L2 subdev operations */ 682 static const struct v4l2_subdev_ops isp_subdev_v4l2_ops = { 683 .core = &isp_subdev_v4l2_core_ops, 684 .pad = &isp_subdev_v4l2_pad_ops, 685 }; 686 687 static void isp_subdev_init_params(struct atomisp_sub_device *asd) 688 { 689 unsigned int i; 690 691 /* parameters initialization */ 692 INIT_LIST_HEAD(&asd->s3a_stats); 693 INIT_LIST_HEAD(&asd->s3a_stats_in_css); 694 INIT_LIST_HEAD(&asd->s3a_stats_ready); 695 INIT_LIST_HEAD(&asd->dis_stats); 696 INIT_LIST_HEAD(&asd->dis_stats_in_css); 697 spin_lock_init(&asd->dis_stats_lock); 698 for (i = 0; i < ATOMISP_METADATA_TYPE_NUM; i++) { 699 INIT_LIST_HEAD(&asd->metadata[i]); 700 INIT_LIST_HEAD(&asd->metadata_in_css[i]); 701 INIT_LIST_HEAD(&asd->metadata_ready[i]); 702 } 703 } 704 705 /* media operations */ 706 static const struct media_entity_operations isp_subdev_media_ops = { 707 .link_validate = v4l2_subdev_link_validate, 708 /* .set_power = v4l2_subdev_set_power, */ 709 }; 710 711 static int __atomisp_update_run_mode(struct atomisp_sub_device *asd) 712 { 713 struct atomisp_device *isp = asd->isp; 714 struct v4l2_ctrl *ctrl = asd->run_mode; 715 struct v4l2_ctrl *c; 716 s32 mode; 717 718 mode = ctrl->val; 719 720 c = v4l2_ctrl_find( 721 isp->inputs[asd->input_curr].camera->ctrl_handler, 722 V4L2_CID_RUN_MODE); 723 724 if (c) 725 return v4l2_ctrl_s_ctrl(c, mode); 726 727 return 0; 728 } 729 730 int atomisp_update_run_mode(struct atomisp_sub_device *asd) 731 { 732 int rval; 733 734 mutex_lock(asd->ctrl_handler.lock); 735 rval = __atomisp_update_run_mode(asd); 736 mutex_unlock(asd->ctrl_handler.lock); 737 738 return rval; 739 } 740 741 static int s_ctrl(struct v4l2_ctrl *ctrl) 742 { 743 struct atomisp_sub_device *asd = container_of( 744 ctrl->handler, struct atomisp_sub_device, ctrl_handler); 745 switch (ctrl->id) { 746 case V4L2_CID_RUN_MODE: 747 return __atomisp_update_run_mode(asd); 748 } 749 750 return 0; 751 } 752 753 static const struct v4l2_ctrl_ops ctrl_ops = { 754 .s_ctrl = &s_ctrl, 755 }; 756 757 static const char *const ctrl_run_mode_menu[] = { 758 NULL, 759 "Video", 760 "Still capture", 761 "Continuous capture", 762 "Preview", 763 }; 764 765 static const struct v4l2_ctrl_config ctrl_run_mode = { 766 .ops = &ctrl_ops, 767 .id = V4L2_CID_RUN_MODE, 768 .name = "Atomisp run mode", 769 .type = V4L2_CTRL_TYPE_MENU, 770 .min = 1, 771 .def = 1, 772 .max = 4, 773 .qmenu = ctrl_run_mode_menu, 774 }; 775 776 static const char *const ctrl_vfpp_mode_menu[] = { 777 "Enable", /* vfpp always enabled */ 778 "Disable to scaler mode", /* CSS into video mode and disable */ 779 "Disable to low latency mode", /* CSS into still mode and disable */ 780 }; 781 782 static const struct v4l2_ctrl_config ctrl_vfpp = { 783 .id = V4L2_CID_VFPP, 784 .name = "Atomisp vf postprocess", 785 .type = V4L2_CTRL_TYPE_MENU, 786 .min = 0, 787 .def = 0, 788 .max = 2, 789 .qmenu = ctrl_vfpp_mode_menu, 790 }; 791 792 /* 793 * Control for continuous mode raw buffer size 794 * 795 * The size of the RAW ringbuffer sets limit on how much 796 * back in time application can go when requesting capture 797 * frames to be rendered, and how many frames can be rendered 798 * in a burst at full sensor rate. 799 * 800 * Note: this setting has a big impact on memory consumption of 801 * the CSS subsystem. 802 */ 803 static const struct v4l2_ctrl_config ctrl_continuous_raw_buffer_size = { 804 .ops = &ctrl_ops, 805 .id = V4L2_CID_ATOMISP_CONTINUOUS_RAW_BUFFER_SIZE, 806 .type = V4L2_CTRL_TYPE_INTEGER, 807 .name = "Continuous raw ringbuffer size", 808 .min = 1, 809 .max = 100, /* depends on CSS version, runtime checked */ 810 .step = 1, 811 .def = 3, 812 }; 813 814 /* 815 * Control for enabling continuous viewfinder 816 * 817 * When enabled, and ISP is in continuous mode (see ctrl_continuous_mode ), 818 * preview pipeline continues concurrently with capture 819 * processing. When disabled, and continuous mode is used, 820 * preview is paused while captures are processed, but 821 * full pipeline restart is not needed. 822 * 823 * By setting this to disabled, capture processing is 824 * essentially given priority over preview, and the effective 825 * capture output rate may be higher than with continuous 826 * viewfinder enabled. 827 */ 828 static const struct v4l2_ctrl_config ctrl_continuous_viewfinder = { 829 .id = V4L2_CID_ATOMISP_CONTINUOUS_VIEWFINDER, 830 .type = V4L2_CTRL_TYPE_BOOLEAN, 831 .name = "Continuous viewfinder", 832 .min = 0, 833 .max = 1, 834 .step = 1, 835 .def = 0, 836 }; 837 838 /* 839 * Control for enabling Lock&Unlock Raw Buffer mechanism 840 * 841 * When enabled, Raw Buffer can be locked and unlocked. 842 * Application can hold the exp_id of Raw Buffer 843 * and unlock it when no longer needed. 844 * Note: Make sure set this configuration before creating stream. 845 */ 846 static const struct v4l2_ctrl_config ctrl_enable_raw_buffer_lock = { 847 .id = V4L2_CID_ENABLE_RAW_BUFFER_LOCK, 848 .type = V4L2_CTRL_TYPE_BOOLEAN, 849 .name = "Lock Unlock Raw Buffer", 850 .min = 0, 851 .max = 1, 852 .step = 1, 853 .def = 0, 854 }; 855 856 /* 857 * Control to disable digital zoom of the whole stream 858 * 859 * When it is true, pipe configuration enable_dz will be set to false. 860 * This can help get a better performance by disabling pp binary. 861 * 862 * Note: Make sure set this configuration before creating stream. 863 */ 864 static const struct v4l2_ctrl_config ctrl_disable_dz = { 865 .id = V4L2_CID_DISABLE_DZ, 866 .type = V4L2_CTRL_TYPE_BOOLEAN, 867 .name = "Disable digital zoom", 868 .min = 0, 869 .max = 1, 870 .step = 1, 871 .def = 0, 872 }; 873 874 static int atomisp_init_subdev_pipe(struct atomisp_sub_device *asd, 875 struct atomisp_video_pipe *pipe, enum v4l2_buf_type buf_type) 876 { 877 int ret; 878 879 pipe->type = buf_type; 880 pipe->asd = asd; 881 pipe->isp = asd->isp; 882 spin_lock_init(&pipe->irq_lock); 883 mutex_init(&pipe->vb_queue_mutex); 884 885 /* Init videobuf2 queue structure */ 886 pipe->vb_queue.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 887 pipe->vb_queue.io_modes = VB2_MMAP | VB2_USERPTR; 888 pipe->vb_queue.buf_struct_size = sizeof(struct ia_css_frame); 889 pipe->vb_queue.ops = &atomisp_vb2_ops; 890 pipe->vb_queue.mem_ops = &vb2_vmalloc_memops; 891 pipe->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; 892 ret = vb2_queue_init(&pipe->vb_queue); 893 if (ret) 894 return ret; 895 896 pipe->vdev.queue = &pipe->vb_queue; 897 pipe->vdev.queue->lock = &pipe->vb_queue_mutex; 898 899 INIT_LIST_HEAD(&pipe->buffers_in_css); 900 INIT_LIST_HEAD(&pipe->activeq); 901 INIT_LIST_HEAD(&pipe->buffers_waiting_for_param); 902 INIT_LIST_HEAD(&pipe->per_frame_params); 903 904 return 0; 905 } 906 907 /* 908 * isp_subdev_init_entities - Initialize V4L2 subdev and media entity 909 * @asd: ISP CCDC module 910 * 911 * Return 0 on success and a negative error code on failure. 912 */ 913 static int isp_subdev_init_entities(struct atomisp_sub_device *asd) 914 { 915 struct v4l2_subdev *sd = &asd->subdev; 916 struct media_pad *pads = asd->pads; 917 struct media_entity *me = &sd->entity; 918 int ret; 919 920 v4l2_subdev_init(sd, &isp_subdev_v4l2_ops); 921 sprintf(sd->name, "ATOMISP_SUBDEV"); 922 v4l2_set_subdevdata(sd, asd); 923 sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE; 924 925 pads[ATOMISP_SUBDEV_PAD_SINK].flags = MEDIA_PAD_FL_SINK; 926 pads[ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW].flags = MEDIA_PAD_FL_SOURCE; 927 pads[ATOMISP_SUBDEV_PAD_SOURCE_VF].flags = MEDIA_PAD_FL_SOURCE; 928 pads[ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE].flags = MEDIA_PAD_FL_SOURCE; 929 pads[ATOMISP_SUBDEV_PAD_SOURCE_VIDEO].flags = MEDIA_PAD_FL_SOURCE; 930 931 asd->fmt[ATOMISP_SUBDEV_PAD_SINK].fmt.code = 932 MEDIA_BUS_FMT_SBGGR10_1X10; 933 asd->fmt[ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW].fmt.code = 934 MEDIA_BUS_FMT_SBGGR10_1X10; 935 asd->fmt[ATOMISP_SUBDEV_PAD_SOURCE_VF].fmt.code = 936 MEDIA_BUS_FMT_SBGGR10_1X10; 937 asd->fmt[ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE].fmt.code = 938 MEDIA_BUS_FMT_SBGGR10_1X10; 939 asd->fmt[ATOMISP_SUBDEV_PAD_SOURCE_VIDEO].fmt.code = 940 MEDIA_BUS_FMT_SBGGR10_1X10; 941 942 me->ops = &isp_subdev_media_ops; 943 me->function = MEDIA_ENT_F_PROC_VIDEO_ISP; 944 ret = media_entity_pads_init(me, ATOMISP_SUBDEV_PADS_NUM, pads); 945 if (ret < 0) 946 return ret; 947 948 ret = atomisp_init_subdev_pipe(asd, &asd->video_out_preview, 949 V4L2_BUF_TYPE_VIDEO_CAPTURE); 950 if (ret) 951 return ret; 952 953 ret = atomisp_init_subdev_pipe(asd, &asd->video_out_vf, 954 V4L2_BUF_TYPE_VIDEO_CAPTURE); 955 if (ret) 956 return ret; 957 958 ret = atomisp_init_subdev_pipe(asd, &asd->video_out_capture, 959 V4L2_BUF_TYPE_VIDEO_CAPTURE); 960 if (ret) 961 return ret; 962 963 ret = atomisp_init_subdev_pipe(asd, &asd->video_out_video_capture, 964 V4L2_BUF_TYPE_VIDEO_CAPTURE); 965 if (ret) 966 return ret; 967 968 ret = atomisp_video_init(&asd->video_out_capture, "CAPTURE", 969 ATOMISP_RUN_MODE_STILL_CAPTURE); 970 if (ret < 0) 971 return ret; 972 973 ret = atomisp_video_init(&asd->video_out_vf, "VIEWFINDER", 974 ATOMISP_RUN_MODE_CONTINUOUS_CAPTURE); 975 if (ret < 0) 976 return ret; 977 978 ret = atomisp_video_init(&asd->video_out_preview, "PREVIEW", 979 ATOMISP_RUN_MODE_PREVIEW); 980 if (ret < 0) 981 return ret; 982 983 ret = atomisp_video_init(&asd->video_out_video_capture, "VIDEO", 984 ATOMISP_RUN_MODE_VIDEO); 985 if (ret < 0) 986 return ret; 987 988 ret = v4l2_ctrl_handler_init(&asd->ctrl_handler, 1); 989 if (ret) 990 return ret; 991 992 asd->run_mode = v4l2_ctrl_new_custom(&asd->ctrl_handler, 993 &ctrl_run_mode, NULL); 994 asd->vfpp = v4l2_ctrl_new_custom(&asd->ctrl_handler, 995 &ctrl_vfpp, NULL); 996 asd->continuous_viewfinder = v4l2_ctrl_new_custom(&asd->ctrl_handler, 997 &ctrl_continuous_viewfinder, 998 NULL); 999 asd->continuous_raw_buffer_size = 1000 v4l2_ctrl_new_custom(&asd->ctrl_handler, 1001 &ctrl_continuous_raw_buffer_size, 1002 NULL); 1003 1004 asd->enable_raw_buffer_lock = 1005 v4l2_ctrl_new_custom(&asd->ctrl_handler, 1006 &ctrl_enable_raw_buffer_lock, 1007 NULL); 1008 asd->disable_dz = 1009 v4l2_ctrl_new_custom(&asd->ctrl_handler, 1010 &ctrl_disable_dz, 1011 NULL); 1012 1013 /* Make controls visible on subdev as well. */ 1014 asd->subdev.ctrl_handler = &asd->ctrl_handler; 1015 spin_lock_init(&asd->raw_buffer_bitmap_lock); 1016 return asd->ctrl_handler.error; 1017 } 1018 1019 int atomisp_create_pads_links(struct atomisp_device *isp) 1020 { 1021 int i, ret; 1022 1023 for (i = 0; i < ATOMISP_CAMERA_NR_PORTS; i++) { 1024 ret = media_create_pad_link(&isp->csi2_port[i].subdev.entity, 1025 CSI2_PAD_SOURCE, &isp->asd.subdev.entity, 1026 ATOMISP_SUBDEV_PAD_SINK, 0); 1027 if (ret < 0) 1028 return ret; 1029 } 1030 1031 for (i = 0; i < isp->input_cnt; i++) { 1032 /* Don't create links for the test-pattern-generator */ 1033 if (isp->inputs[i].type == TEST_PATTERN) 1034 continue; 1035 1036 ret = media_create_pad_link(&isp->inputs[i].camera->entity, 0, 1037 &isp->csi2_port[isp->inputs[i]. 1038 port].subdev.entity, 1039 CSI2_PAD_SINK, 1040 MEDIA_LNK_FL_ENABLED | 1041 MEDIA_LNK_FL_IMMUTABLE); 1042 if (ret < 0) 1043 return ret; 1044 } 1045 1046 ret = media_create_pad_link(&isp->asd.subdev.entity, 1047 ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW, 1048 &isp->asd.video_out_preview.vdev.entity, 0, 0); 1049 if (ret < 0) 1050 return ret; 1051 ret = media_create_pad_link(&isp->asd.subdev.entity, 1052 ATOMISP_SUBDEV_PAD_SOURCE_VF, 1053 &isp->asd.video_out_vf.vdev.entity, 0, 0); 1054 if (ret < 0) 1055 return ret; 1056 ret = media_create_pad_link(&isp->asd.subdev.entity, 1057 ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE, 1058 &isp->asd.video_out_capture.vdev.entity, 0, 0); 1059 if (ret < 0) 1060 return ret; 1061 ret = media_create_pad_link(&isp->asd.subdev.entity, 1062 ATOMISP_SUBDEV_PAD_SOURCE_VIDEO, 1063 &isp->asd.video_out_video_capture.vdev.entity, 0, 0); 1064 if (ret < 0) 1065 return ret; 1066 1067 return 0; 1068 } 1069 1070 static void atomisp_subdev_cleanup_entities(struct atomisp_sub_device *asd) 1071 { 1072 v4l2_ctrl_handler_free(&asd->ctrl_handler); 1073 1074 media_entity_cleanup(&asd->subdev.entity); 1075 } 1076 1077 void atomisp_subdev_cleanup_pending_events(struct atomisp_sub_device *asd) 1078 { 1079 struct v4l2_fh *fh, *fh_tmp; 1080 struct v4l2_event event; 1081 unsigned int i, pending_event; 1082 1083 list_for_each_entry_safe(fh, fh_tmp, 1084 &asd->subdev.devnode->fh_list, list) { 1085 pending_event = v4l2_event_pending(fh); 1086 for (i = 0; i < pending_event; i++) 1087 v4l2_event_dequeue(fh, &event, 1); 1088 } 1089 } 1090 1091 void atomisp_subdev_unregister_entities(struct atomisp_sub_device *asd) 1092 { 1093 atomisp_subdev_cleanup_entities(asd); 1094 v4l2_device_unregister_subdev(&asd->subdev); 1095 atomisp_video_unregister(&asd->video_out_preview); 1096 atomisp_video_unregister(&asd->video_out_vf); 1097 atomisp_video_unregister(&asd->video_out_capture); 1098 atomisp_video_unregister(&asd->video_out_video_capture); 1099 } 1100 1101 int atomisp_subdev_register_subdev(struct atomisp_sub_device *asd, 1102 struct v4l2_device *vdev) 1103 { 1104 return v4l2_device_register_subdev(vdev, &asd->subdev); 1105 } 1106 1107 int atomisp_subdev_register_video_nodes(struct atomisp_sub_device *asd, 1108 struct v4l2_device *vdev) 1109 { 1110 int ret; 1111 1112 /* 1113 * FIXME: check if all device caps are properly initialized. 1114 * Should any of those use V4L2_CAP_META_CAPTURE? Probably yes. 1115 */ 1116 1117 asd->video_out_preview.vdev.v4l2_dev = vdev; 1118 asd->video_out_preview.vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; 1119 ret = video_register_device(&asd->video_out_preview.vdev, 1120 VFL_TYPE_VIDEO, -1); 1121 if (ret < 0) 1122 goto error; 1123 1124 asd->video_out_capture.vdev.v4l2_dev = vdev; 1125 asd->video_out_capture.vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; 1126 ret = video_register_device(&asd->video_out_capture.vdev, 1127 VFL_TYPE_VIDEO, -1); 1128 if (ret < 0) 1129 goto error; 1130 1131 asd->video_out_vf.vdev.v4l2_dev = vdev; 1132 asd->video_out_vf.vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; 1133 ret = video_register_device(&asd->video_out_vf.vdev, 1134 VFL_TYPE_VIDEO, -1); 1135 if (ret < 0) 1136 goto error; 1137 1138 asd->video_out_video_capture.vdev.v4l2_dev = vdev; 1139 asd->video_out_video_capture.vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; 1140 ret = video_register_device(&asd->video_out_video_capture.vdev, 1141 VFL_TYPE_VIDEO, -1); 1142 if (ret < 0) 1143 goto error; 1144 1145 return 0; 1146 1147 error: 1148 atomisp_subdev_unregister_entities(asd); 1149 return ret; 1150 } 1151 1152 /* 1153 * atomisp_subdev_init - ISP Subdevice initialization. 1154 * @dev: Device pointer specific to the ATOM ISP. 1155 * 1156 * TODO: Get the initialisation values from platform data. 1157 * 1158 * Return 0 on success or a negative error code otherwise. 1159 */ 1160 int atomisp_subdev_init(struct atomisp_device *isp) 1161 { 1162 int ret; 1163 1164 isp->asd.isp = isp; 1165 isp_subdev_init_params(&isp->asd); 1166 ret = isp_subdev_init_entities(&isp->asd); 1167 if (ret < 0) 1168 atomisp_subdev_cleanup_entities(&isp->asd); 1169 1170 return ret; 1171 } 1172