2 * Support for Medifield PNW Camera Imaging ISP subsystem.
4 * Copyright (c) 2010 Intel Corporation. All Rights Reserved.
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License version
8 * 2 as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 #include <linux/module.h>
22 #include <linux/uaccess.h>
23 #include <linux/delay.h>
24 #include <linux/device.h>
26 #include <linux/sched.h>
27 #include <linux/slab.h>
28 #include <asm/intel-mid.h>
30 #include <media/v4l2-event.h>
31 #include <media/v4l2-mediabus.h>
32 #include "atomisp_cmd.h"
33 #include "atomisp_common.h"
34 #include "atomisp_compat.h"
35 #include "atomisp_internal.h"
37 const struct atomisp_in_fmt_conv atomisp_in_fmt_conv[] = {
38 { MEDIA_BUS_FMT_SBGGR8_1X8, 8, 8, ATOMISP_INPUT_FORMAT_RAW_8, CSS_BAYER_ORDER_BGGR, CSS_FORMAT_RAW_8 },
39 { MEDIA_BUS_FMT_SGBRG8_1X8, 8, 8, ATOMISP_INPUT_FORMAT_RAW_8, CSS_BAYER_ORDER_GBRG, CSS_FORMAT_RAW_8 },
40 { MEDIA_BUS_FMT_SGRBG8_1X8, 8, 8, ATOMISP_INPUT_FORMAT_RAW_8, CSS_BAYER_ORDER_GRBG, CSS_FORMAT_RAW_8 },
41 { MEDIA_BUS_FMT_SRGGB8_1X8, 8, 8, ATOMISP_INPUT_FORMAT_RAW_8, CSS_BAYER_ORDER_RGGB, CSS_FORMAT_RAW_8 },
42 { MEDIA_BUS_FMT_SBGGR10_1X10, 10, 10, ATOMISP_INPUT_FORMAT_RAW_10, CSS_BAYER_ORDER_BGGR, CSS_FORMAT_RAW_10 },
43 { MEDIA_BUS_FMT_SGBRG10_1X10, 10, 10, ATOMISP_INPUT_FORMAT_RAW_10, CSS_BAYER_ORDER_GBRG, CSS_FORMAT_RAW_10 },
44 { MEDIA_BUS_FMT_SGRBG10_1X10, 10, 10, ATOMISP_INPUT_FORMAT_RAW_10, CSS_BAYER_ORDER_GRBG, CSS_FORMAT_RAW_10 },
45 { MEDIA_BUS_FMT_SRGGB10_1X10, 10, 10, ATOMISP_INPUT_FORMAT_RAW_10, CSS_BAYER_ORDER_RGGB, CSS_FORMAT_RAW_10 },
46 { MEDIA_BUS_FMT_SBGGR12_1X12, 12, 12, ATOMISP_INPUT_FORMAT_RAW_12, CSS_BAYER_ORDER_BGGR, CSS_FORMAT_RAW_12 },
47 { MEDIA_BUS_FMT_SGBRG12_1X12, 12, 12, ATOMISP_INPUT_FORMAT_RAW_12, CSS_BAYER_ORDER_GBRG, CSS_FORMAT_RAW_12 },
48 { MEDIA_BUS_FMT_SGRBG12_1X12, 12, 12, ATOMISP_INPUT_FORMAT_RAW_12, CSS_BAYER_ORDER_GRBG, CSS_FORMAT_RAW_12 },
49 { MEDIA_BUS_FMT_SRGGB12_1X12, 12, 12, ATOMISP_INPUT_FORMAT_RAW_12, CSS_BAYER_ORDER_RGGB, CSS_FORMAT_RAW_12 },
50 { MEDIA_BUS_FMT_UYVY8_1X16, 8, 8, ATOMISP_INPUT_FORMAT_YUV422_8, 0, IA_CSS_STREAM_FORMAT_YUV422_8 },
51 { MEDIA_BUS_FMT_YUYV8_1X16, 8, 8, ATOMISP_INPUT_FORMAT_YUV422_8, 0, IA_CSS_STREAM_FORMAT_YUV422_8 },
52 { MEDIA_BUS_FMT_JPEG_1X8, 8, 8, CSS_FRAME_FORMAT_BINARY_8, 0, IA_CSS_STREAM_FORMAT_BINARY_8 },
53 { V4L2_MBUS_FMT_CUSTOM_NV12, 12, 12, CSS_FRAME_FORMAT_NV12, 0, CSS_FRAME_FORMAT_NV12 },
54 { V4L2_MBUS_FMT_CUSTOM_NV21, 12, 12, CSS_FRAME_FORMAT_NV21, 0, CSS_FRAME_FORMAT_NV21 },
55 { V4L2_MBUS_FMT_CUSTOM_YUV420, 12, 12, ATOMISP_INPUT_FORMAT_YUV420_8_LEGACY, 0, IA_CSS_STREAM_FORMAT_YUV420_8_LEGACY },
56 { V4L2_MBUS_FMT_CUSTOM_M10MO_RAW, 8, 8, CSS_FRAME_FORMAT_BINARY_8, 0, IA_CSS_STREAM_FORMAT_BINARY_8 },
57 /* no valid V4L2 MBUS code for metadata format, so leave it 0. */
58 { 0, 0, 0, ATOMISP_INPUT_FORMAT_EMBEDDED, 0, IA_CSS_STREAM_FORMAT_EMBEDDED },
65 } compressed_codes[] = {
66 { MEDIA_BUS_FMT_SBGGR10_1X10, MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8 },
67 { MEDIA_BUS_FMT_SGBRG10_1X10, MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8 },
68 { MEDIA_BUS_FMT_SGRBG10_1X10, MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8 },
69 { MEDIA_BUS_FMT_SRGGB10_1X10, MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8 },
72 u32 atomisp_subdev_uncompressed_code(u32 code)
76 for (i = 0; i < ARRAY_SIZE(compressed_codes); i++)
77 if (code == compressed_codes[i].compressed)
78 return compressed_codes[i].code;
83 bool atomisp_subdev_is_compressed(u32 code)
87 for (i = 0; i < ARRAY_SIZE(atomisp_in_fmt_conv) - 1; i++)
88 if (code == atomisp_in_fmt_conv[i].code)
89 return atomisp_in_fmt_conv[i].bpp !=
90 atomisp_in_fmt_conv[i].depth;
95 const struct atomisp_in_fmt_conv *atomisp_find_in_fmt_conv(u32 code)
99 for (i = 0; i < ARRAY_SIZE(atomisp_in_fmt_conv) - 1; i++)
100 if (code == atomisp_in_fmt_conv[i].code)
101 return atomisp_in_fmt_conv + i;
106 const struct atomisp_in_fmt_conv *atomisp_find_in_fmt_conv_by_atomisp_in_fmt(
107 enum atomisp_css_stream_format atomisp_in_fmt)
111 for (i = 0; i < ARRAY_SIZE(atomisp_in_fmt_conv) - 1; i++)
112 if (atomisp_in_fmt_conv[i].atomisp_in_fmt == atomisp_in_fmt)
113 return atomisp_in_fmt_conv + i;
118 bool atomisp_subdev_format_conversion(struct atomisp_sub_device *asd,
119 unsigned int source_pad)
121 struct v4l2_mbus_framefmt *sink, *src;
123 sink = atomisp_subdev_get_ffmt(&asd->subdev, NULL,
124 V4L2_SUBDEV_FORMAT_ACTIVE,
125 ATOMISP_SUBDEV_PAD_SINK);
126 src = atomisp_subdev_get_ffmt(&asd->subdev, NULL,
127 V4L2_SUBDEV_FORMAT_ACTIVE, source_pad);
129 return atomisp_is_mbuscode_raw(sink->code)
130 && !atomisp_is_mbuscode_raw(src->code);
133 uint16_t atomisp_subdev_source_pad(struct video_device * vdev)
135 struct media_link *link;
137 list_for_each_entry(link, &vdev->entity.links, list) {
139 ret = link->source->index;
147 * V4L2 subdev operations
151 * isp_subdev_ioctl - CCDC module private ioctl's
152 * @sd: ISP V4L2 subdevice
153 * @cmd: ioctl command
154 * @arg: ioctl argument
156 * Return 0 on success or a negative error code otherwise.
158 static long isp_subdev_ioctl(struct v4l2_subdev *sd,
159 unsigned int cmd, void *arg)
165 * isp_subdev_set_power - Power on/off the CCDC module
166 * @sd: ISP V4L2 subdevice
169 * Return 0 on success or a negative error code otherwise.
171 static int isp_subdev_set_power(struct v4l2_subdev *sd, int on)
176 static int isp_subdev_subscribe_event(struct v4l2_subdev *sd,
178 struct v4l2_event_subscription *sub)
180 struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd);
181 struct atomisp_device *isp = isp_sd->isp;
183 if (sub->type != V4L2_EVENT_FRAME_SYNC &&
184 sub->type != V4L2_EVENT_FRAME_END &&
185 sub->type != V4L2_EVENT_ATOMISP_3A_STATS_READY &&
186 sub->type != V4L2_EVENT_ATOMISP_METADATA_READY &&
187 sub->type != V4L2_EVENT_ATOMISP_PAUSE_BUFFER &&
188 sub->type != V4L2_EVENT_ATOMISP_CSS_RESET &&
189 sub->type != V4L2_EVENT_ATOMISP_RAW_BUFFERS_ALLOC_DONE &&
190 sub->type != V4L2_EVENT_ATOMISP_ACC_COMPLETE)
193 if (sub->type == V4L2_EVENT_FRAME_SYNC &&
194 !atomisp_css_valid_sof(isp))
197 return v4l2_event_subscribe(fh, sub, 16, NULL);
200 static int isp_subdev_unsubscribe_event(struct v4l2_subdev *sd,
202 struct v4l2_event_subscription *sub)
204 return v4l2_event_unsubscribe(fh, sub);
208 * isp_subdev_enum_mbus_code - Handle pixel format enumeration
209 * @sd: pointer to v4l2 subdev structure
210 * @fh : V4L2 subdev file handle
211 * @code: pointer to v4l2_subdev_pad_mbus_code_enum structure
212 * return -EINVAL or zero on success
214 static int isp_subdev_enum_mbus_code(struct v4l2_subdev *sd,
215 struct v4l2_subdev_pad_config *cfg,
216 struct v4l2_subdev_mbus_code_enum *code)
218 if (code->index >= ARRAY_SIZE(atomisp_in_fmt_conv) - 1)
221 code->code = atomisp_in_fmt_conv[code->index].code;
226 static int isp_subdev_validate_rect(struct v4l2_subdev *sd, uint32_t pad,
230 case ATOMISP_SUBDEV_PAD_SINK:
232 case V4L2_SEL_TGT_CROP:
238 case V4L2_SEL_TGT_COMPOSE:
247 struct v4l2_rect *atomisp_subdev_get_rect(struct v4l2_subdev *sd,
248 struct v4l2_subdev_pad_config *cfg,
249 uint32_t which, uint32_t pad,
252 struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd);
254 if (which == V4L2_SUBDEV_FORMAT_TRY) {
256 case V4L2_SEL_TGT_CROP:
257 return v4l2_subdev_get_try_crop(sd, cfg, pad);
258 case V4L2_SEL_TGT_COMPOSE:
259 return v4l2_subdev_get_try_compose(sd, cfg, pad);
264 case V4L2_SEL_TGT_CROP:
265 return &isp_sd->fmt[pad].crop;
266 case V4L2_SEL_TGT_COMPOSE:
267 return &isp_sd->fmt[pad].compose;
273 struct v4l2_mbus_framefmt
274 *atomisp_subdev_get_ffmt(struct v4l2_subdev *sd,
275 struct v4l2_subdev_pad_config *cfg, uint32_t which,
278 struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd);
280 if (which == V4L2_SUBDEV_FORMAT_TRY)
281 return v4l2_subdev_get_try_format(sd, cfg, pad);
283 return &isp_sd->fmt[pad].fmt;
286 static void isp_get_fmt_rect(struct v4l2_subdev *sd,
287 struct v4l2_subdev_pad_config *cfg, uint32_t which,
288 struct v4l2_mbus_framefmt **ffmt,
289 struct v4l2_rect *crop[ATOMISP_SUBDEV_PADS_NUM],
290 struct v4l2_rect *comp[ATOMISP_SUBDEV_PADS_NUM])
294 for (i = 0; i < ATOMISP_SUBDEV_PADS_NUM; i++) {
295 ffmt[i] = atomisp_subdev_get_ffmt(sd, cfg, which, i);
296 crop[i] = atomisp_subdev_get_rect(sd, cfg, which, i,
298 comp[i] = atomisp_subdev_get_rect(sd, cfg, which, i,
299 V4L2_SEL_TGT_COMPOSE);
303 static void isp_subdev_propagate(struct v4l2_subdev *sd,
304 struct v4l2_subdev_pad_config *cfg,
305 uint32_t which, uint32_t pad, uint32_t target,
308 struct v4l2_mbus_framefmt *ffmt[ATOMISP_SUBDEV_PADS_NUM];
309 struct v4l2_rect *crop[ATOMISP_SUBDEV_PADS_NUM],
310 *comp[ATOMISP_SUBDEV_PADS_NUM];
312 if (flags & V4L2_SEL_FLAG_KEEP_CONFIG)
315 isp_get_fmt_rect(sd, cfg, which, ffmt, crop, comp);
318 case ATOMISP_SUBDEV_PAD_SINK: {
319 struct v4l2_rect r = {0};
321 /* Only crop target supported on sink pad. */
322 r.width = ffmt[pad]->width;
323 r.height = ffmt[pad]->height;
325 atomisp_subdev_set_selection(sd, cfg, which, pad,
332 static int isp_subdev_get_selection(struct v4l2_subdev *sd,
333 struct v4l2_subdev_pad_config *cfg,
334 struct v4l2_subdev_selection *sel)
336 struct v4l2_rect *rec;
337 int rval = isp_subdev_validate_rect(sd, sel->pad, sel->target);
342 rec = atomisp_subdev_get_rect(sd, cfg, sel->which, sel->pad,
351 static char *atomisp_pad_str[] = { "ATOMISP_SUBDEV_PAD_SINK",
352 "ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE",
353 "ATOMISP_SUBDEV_PAD_SOURCE_VF",
354 "ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW",
355 "ATOMISP_SUBDEV_PAD_SOURCE_VIDEO"};
357 int atomisp_subdev_set_selection(struct v4l2_subdev *sd,
358 struct v4l2_subdev_pad_config *cfg,
359 uint32_t which, uint32_t pad, uint32_t target,
360 uint32_t flags, struct v4l2_rect *r)
362 struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd);
363 struct atomisp_device *isp = isp_sd->isp;
364 struct v4l2_mbus_framefmt *ffmt[ATOMISP_SUBDEV_PADS_NUM];
365 uint16_t vdev_pad = atomisp_subdev_source_pad(sd->devnode);
366 struct v4l2_rect *crop[ATOMISP_SUBDEV_PADS_NUM],
367 *comp[ATOMISP_SUBDEV_PADS_NUM];
368 enum atomisp_input_stream_id stream_id;
370 unsigned int padding_w = pad_w;
371 unsigned int padding_h = pad_h;
373 stream_id = atomisp_source_pad_to_stream_id(isp_sd, vdev_pad);
375 isp_get_fmt_rect(sd, cfg, which, ffmt, crop, comp);
378 "sel: pad %s tgt %s l %d t %d w %d h %d which %s f 0x%8.8x\n",
379 atomisp_pad_str[pad], target == V4L2_SEL_TGT_CROP
380 ? "V4L2_SEL_TGT_CROP" : "V4L2_SEL_TGT_COMPOSE",
381 r->left, r->top, r->width, r->height,
382 which == V4L2_SUBDEV_FORMAT_TRY ? "V4L2_SUBDEV_FORMAT_TRY"
383 : "V4L2_SUBDEV_FORMAT_ACTIVE", flags);
385 r->width = rounddown(r->width, ATOM_ISP_STEP_WIDTH);
386 r->height = rounddown(r->height, ATOM_ISP_STEP_HEIGHT);
389 case ATOMISP_SUBDEV_PAD_SINK: {
390 /* Only crop target supported on sink pad. */
391 unsigned int dvs_w, dvs_h;
393 crop[pad]->width = ffmt[pad]->width;
394 crop[pad]->height = ffmt[pad]->height;
396 /* Workaround for BYT 1080p perfectshot since the maxinum resolution of
397 * front camera ov2722 is 1932x1092 and cannot use pad_w > 12*/
398 if (!strncmp(isp->inputs[isp_sd->input_curr].camera->name,
399 "ov2722", 6) && crop[pad]->height == 1092) {
404 if (isp->inputs[isp_sd->input_curr].type == SOC_CAMERA) {
409 if (atomisp_subdev_format_conversion(isp_sd,
411 && crop[pad]->width && crop[pad]->height)
412 crop[pad]->width -= padding_w, crop[pad]->height -= padding_h;
414 /* if subdev type is SOC camera,we do not need to set DVS */
415 if (isp->inputs[isp_sd->input_curr].type == SOC_CAMERA)
416 isp_sd->params.video_dis_en = 0;
418 if (isp_sd->params.video_dis_en &&
419 isp_sd->run_mode->val == ATOMISP_RUN_MODE_VIDEO &&
420 !isp_sd->continuous_mode->val) {
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
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);
432 crop[pad]->width = min(crop[pad]->width, r->width);
433 crop[pad]->height = min(crop[pad]->height, r->height);
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];
440 atomisp_subdev_set_selection(
441 sd, cfg, which, i, V4L2_SEL_TGT_COMPOSE,
446 if (which == V4L2_SUBDEV_FORMAT_TRY)
449 if (isp_sd->params.video_dis_en &&
450 isp_sd->run_mode->val == ATOMISP_RUN_MODE_VIDEO &&
451 !isp_sd->continuous_mode->val) {
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) {
459 * For CSS2.0, digital zoom needs to set dvs envelope to 12
460 * when dvs is disabled.
466 atomisp_css_video_set_dis_envelope(isp_sd, dvs_w, dvs_h);
467 atomisp_css_input_set_effective_resolution(isp_sd, stream_id,
468 crop[pad]->width, crop[pad]->height);
472 case ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE:
473 case ATOMISP_SUBDEV_PAD_SOURCE_VIDEO: {
474 /* Only compose target is supported on source pads. */
476 if (isp_sd->vfpp->val == ATOMISP_VFPP_DISABLE_LOWLAT) {
477 /* Scaling is disabled in this mode */
478 r->width = crop[ATOMISP_SUBDEV_PAD_SINK]->width;
479 r->height = crop[ATOMISP_SUBDEV_PAD_SINK]->height;
482 if (crop[ATOMISP_SUBDEV_PAD_SINK]->width == r->width
483 && crop[ATOMISP_SUBDEV_PAD_SINK]->height == r->height)
484 isp_sd->params.yuv_ds_en = false;
486 isp_sd->params.yuv_ds_en = true;
488 comp[pad]->width = r->width;
489 comp[pad]->height = r->height;
491 if (r->width == 0 || r->height == 0 ||
492 crop[ATOMISP_SUBDEV_PAD_SINK]->width == 0 ||
493 crop[ATOMISP_SUBDEV_PAD_SINK]->height == 0)
496 * do cropping on sensor input if ratio of required resolution
497 * is different with sensor output resolution ratio:
499 * ratio = width / height
501 * if ratio_output < ratio_sensor:
502 * effect_width = sensor_height * out_width / out_height;
503 * effect_height = sensor_height;
505 * effect_width = sensor_width;
506 * effect_height = sensor_width * out_height / out_width;
509 if (r->width * crop[ATOMISP_SUBDEV_PAD_SINK]->height <
510 crop[ATOMISP_SUBDEV_PAD_SINK]->width * r->height)
511 atomisp_css_input_set_effective_resolution(isp_sd,
513 rounddown(crop[ATOMISP_SUBDEV_PAD_SINK]->
514 height * r->width / r->height,
515 ATOM_ISP_STEP_WIDTH),
516 crop[ATOMISP_SUBDEV_PAD_SINK]->height);
518 atomisp_css_input_set_effective_resolution(isp_sd,
520 crop[ATOMISP_SUBDEV_PAD_SINK]->width,
521 rounddown(crop[ATOMISP_SUBDEV_PAD_SINK]->
522 width * r->height / r->width,
523 ATOM_ISP_STEP_WIDTH));
527 case ATOMISP_SUBDEV_PAD_SOURCE_VF:
528 case ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW:
529 comp[pad]->width = r->width;
530 comp[pad]->height = r->height;
536 /* Set format dimensions on non-sink pads as well. */
537 if (pad != ATOMISP_SUBDEV_PAD_SINK) {
538 ffmt[pad]->width = comp[pad]->width;
539 ffmt[pad]->height = comp[pad]->height;
542 if (!atomisp_subdev_get_rect(sd, cfg, which, pad, target))
544 *r = *atomisp_subdev_get_rect(sd, cfg, which, pad, target);
546 dev_dbg(isp->dev, "sel actual: l %d t %d w %d h %d\n",
547 r->left, r->top, r->width, r->height);
552 static int isp_subdev_set_selection(struct v4l2_subdev *sd,
553 struct v4l2_subdev_pad_config *cfg,
554 struct v4l2_subdev_selection *sel)
556 int rval = isp_subdev_validate_rect(sd, sel->pad, sel->target);
560 return atomisp_subdev_set_selection(sd, cfg, sel->which, sel->pad,
561 sel->target, sel->flags, &sel->r);
564 static int atomisp_get_sensor_bin_factor(struct atomisp_sub_device *asd)
566 struct v4l2_control ctrl = {0};
567 struct atomisp_device *isp = asd->isp;
571 if (isp->inputs[asd->input_curr].type == FILE_INPUT ||
572 isp->inputs[asd->input_curr].type == TEST_PATTERN)
575 ctrl.id = V4L2_CID_BIN_FACTOR_HORZ;
577 v4l2_g_ctrl(isp->inputs[asd->input_curr].camera->ctrl_handler,
580 ctrl.id = V4L2_CID_BIN_FACTOR_VERT;
582 v4l2_g_ctrl(isp->inputs[asd->input_curr].camera->ctrl_handler,
587 * ISP needs to know binning factor from sensor.
588 * In case horizontal and vertical sensor's binning factors
589 * are different or sensor does not support binning factor CID,
590 * ISP will apply default 0 value.
592 if (ret || hbin != vbin)
598 void atomisp_subdev_set_ffmt(struct v4l2_subdev *sd,
599 struct v4l2_subdev_pad_config *cfg, uint32_t which,
600 uint32_t pad, struct v4l2_mbus_framefmt *ffmt)
602 struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd);
603 struct atomisp_device *isp = isp_sd->isp;
604 struct v4l2_mbus_framefmt *__ffmt =
605 atomisp_subdev_get_ffmt(sd, cfg, which, pad);
606 uint16_t vdev_pad = atomisp_subdev_source_pad(sd->devnode);
607 enum atomisp_input_stream_id stream_id;
609 dev_dbg(isp->dev, "ffmt: pad %s w %d h %d code 0x%8.8x which %s\n",
610 atomisp_pad_str[pad], ffmt->width, ffmt->height, ffmt->code,
611 which == V4L2_SUBDEV_FORMAT_TRY ? "V4L2_SUBDEV_FORMAT_TRY"
612 : "V4L2_SUBDEV_FORMAT_ACTIVE");
614 stream_id = atomisp_source_pad_to_stream_id(isp_sd, vdev_pad);
617 case ATOMISP_SUBDEV_PAD_SINK: {
618 const struct atomisp_in_fmt_conv *fc =
619 atomisp_find_in_fmt_conv(ffmt->code);
622 fc = atomisp_in_fmt_conv;
623 ffmt->code = fc->code;
624 dev_dbg(isp->dev, "using 0x%8.8x instead\n",
630 isp_subdev_propagate(sd, cfg, which, pad,
631 V4L2_SEL_TGT_CROP, 0);
633 if (which == V4L2_SUBDEV_FORMAT_ACTIVE) {
634 atomisp_css_input_set_resolution(isp_sd,
636 atomisp_css_input_set_binning_factor(isp_sd,
638 atomisp_get_sensor_bin_factor(isp_sd));
639 atomisp_css_input_set_bayer_order(isp_sd, stream_id,
641 atomisp_css_input_set_format(isp_sd, stream_id,
643 atomisp_css_set_default_isys_config(isp_sd, stream_id,
649 case ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE:
650 case ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW:
651 case ATOMISP_SUBDEV_PAD_SOURCE_VF:
652 case ATOMISP_SUBDEV_PAD_SOURCE_VIDEO:
653 __ffmt->code = ffmt->code;
659 * isp_subdev_get_format - Retrieve the video format on a pad
660 * @sd : ISP V4L2 subdevice
661 * @fh : V4L2 subdev file handle
665 * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
666 * to the format type.
668 static int isp_subdev_get_format(struct v4l2_subdev *sd,
669 struct v4l2_subdev_pad_config *cfg,
670 struct v4l2_subdev_format *fmt)
672 fmt->format = *atomisp_subdev_get_ffmt(sd, cfg, fmt->which, fmt->pad);
678 * isp_subdev_set_format - Set the video format on a pad
679 * @sd : ISP subdev V4L2 subdevice
680 * @fh : V4L2 subdev file handle
684 * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
685 * to the format type.
687 static int isp_subdev_set_format(struct v4l2_subdev *sd,
688 struct v4l2_subdev_pad_config *cfg,
689 struct v4l2_subdev_format *fmt)
691 atomisp_subdev_set_ffmt(sd, cfg, fmt->which, fmt->pad, &fmt->format);
696 /* V4L2 subdev core operations */
697 static const struct v4l2_subdev_core_ops isp_subdev_v4l2_core_ops = {
698 .ioctl = isp_subdev_ioctl, .s_power = isp_subdev_set_power,
699 .subscribe_event = isp_subdev_subscribe_event,
700 .unsubscribe_event = isp_subdev_unsubscribe_event,
703 /* V4L2 subdev pad operations */
704 static const struct v4l2_subdev_pad_ops isp_subdev_v4l2_pad_ops = {
705 .enum_mbus_code = isp_subdev_enum_mbus_code,
706 .get_fmt = isp_subdev_get_format,
707 .set_fmt = isp_subdev_set_format,
708 .get_selection = isp_subdev_get_selection,
709 .set_selection = isp_subdev_set_selection,
710 .link_validate = v4l2_subdev_link_validate_default,
713 /* V4L2 subdev operations */
714 static const struct v4l2_subdev_ops isp_subdev_v4l2_ops = {
715 .core = &isp_subdev_v4l2_core_ops,
716 .pad = &isp_subdev_v4l2_pad_ops,
719 static void isp_subdev_init_params(struct atomisp_sub_device *asd)
723 /* parameters initialization */
724 INIT_LIST_HEAD(&asd->s3a_stats);
725 INIT_LIST_HEAD(&asd->s3a_stats_in_css);
726 INIT_LIST_HEAD(&asd->s3a_stats_ready);
727 INIT_LIST_HEAD(&asd->dis_stats);
728 INIT_LIST_HEAD(&asd->dis_stats_in_css);
729 spin_lock_init(&asd->dis_stats_lock);
730 for (i = 0; i < ATOMISP_METADATA_TYPE_NUM; i++) {
731 INIT_LIST_HEAD(&asd->metadata[i]);
732 INIT_LIST_HEAD(&asd->metadata_in_css[i]);
733 INIT_LIST_HEAD(&asd->metadata_ready[i]);
738 * isp_subdev_link_setup - Setup isp subdev connections
739 * @entity: ispsubdev media entity
740 * @local: Pad at the local end of the link
741 * @remote: Pad at the remote end of the link
744 * return -EINVAL or zero on success
746 static int isp_subdev_link_setup(struct media_entity *entity,
747 const struct media_pad *local,
748 const struct media_pad *remote, u32 flags)
750 struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
751 struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd);
752 struct atomisp_device *isp = isp_sd->isp;
755 switch (local->index | is_media_entity_v4l2_subdev(remote->entity)) {
756 case ATOMISP_SUBDEV_PAD_SINK | MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN:
757 /* Read from the sensor CSI2-ports. */
758 if (!(flags & MEDIA_LNK_FL_ENABLED)) {
759 isp_sd->input = ATOMISP_SUBDEV_INPUT_NONE;
763 if (isp_sd->input != ATOMISP_SUBDEV_INPUT_NONE)
766 for (i = 0; i < ATOMISP_CAMERA_NR_PORTS; i++) {
767 if (remote->entity != &isp->csi2_port[i].subdev.entity)
770 isp_sd->input = ATOMISP_SUBDEV_INPUT_CSI2_PORT1 + i;
776 case ATOMISP_SUBDEV_PAD_SINK | MEDIA_ENT_F_OLD_BASE:
777 /* read from memory */
778 if (flags & MEDIA_LNK_FL_ENABLED) {
779 if (isp_sd->input >= ATOMISP_SUBDEV_INPUT_CSI2_PORT1 &&
780 isp_sd->input < (ATOMISP_SUBDEV_INPUT_CSI2_PORT1
781 + ATOMISP_CAMERA_NR_PORTS))
783 isp_sd->input = ATOMISP_SUBDEV_INPUT_MEMORY;
785 if (isp_sd->input == ATOMISP_SUBDEV_INPUT_MEMORY)
786 isp_sd->input = ATOMISP_SUBDEV_INPUT_NONE;
790 case ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW | MEDIA_ENT_F_OLD_BASE:
791 /* always write to memory */
794 case ATOMISP_SUBDEV_PAD_SOURCE_VF | MEDIA_ENT_F_OLD_BASE:
795 /* always write to memory */
798 case ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE | MEDIA_ENT_F_OLD_BASE:
799 /* always write to memory */
802 case ATOMISP_SUBDEV_PAD_SOURCE_VIDEO | MEDIA_ENT_F_OLD_BASE:
803 /* always write to memory */
813 /* media operations */
814 static const struct media_entity_operations isp_subdev_media_ops = {
815 .link_setup = isp_subdev_link_setup,
816 .link_validate = v4l2_subdev_link_validate,
817 /* .set_power = v4l2_subdev_set_power, */
820 static int __atomisp_update_run_mode(struct atomisp_sub_device *asd)
822 struct atomisp_device *isp = asd->isp;
823 struct v4l2_ctrl *ctrl = asd->run_mode;
825 struct v4l2_streamparm p = {0};
826 int modes[] = { CI_MODE_NONE,
828 CI_MODE_STILL_CAPTURE,
833 if (ctrl->val != ATOMISP_RUN_MODE_VIDEO &&
834 asd->continuous_mode->val)
835 mode = ATOMISP_RUN_MODE_PREVIEW;
840 isp->inputs[asd->input_curr].camera->ctrl_handler,
844 return v4l2_ctrl_s_ctrl(c, mode);
846 /* Fall back to obsolete s_parm */
847 p.parm.capture.capturemode = modes[mode];
849 return v4l2_subdev_call(
850 isp->inputs[asd->input_curr].camera, video, s_parm, &p);
853 int atomisp_update_run_mode(struct atomisp_sub_device *asd)
857 mutex_lock(asd->ctrl_handler.lock);
858 rval = __atomisp_update_run_mode(asd);
859 mutex_unlock(asd->ctrl_handler.lock);
864 static int s_ctrl(struct v4l2_ctrl *ctrl)
866 struct atomisp_sub_device *asd = container_of(
867 ctrl->handler, struct atomisp_sub_device, ctrl_handler);
870 case V4L2_CID_RUN_MODE:
871 return __atomisp_update_run_mode(asd);
872 case V4L2_CID_DEPTH_MODE:
873 if (asd->streaming != ATOMISP_DEVICE_STREAMING_DISABLED) {
874 dev_err(asd->isp->dev, "ISP is streaming, it is not supported to change the depth mode\n");
883 static const struct v4l2_ctrl_ops ctrl_ops = {
887 static const struct v4l2_ctrl_config ctrl_fmt_auto = {
889 .id = V4L2_CID_FMT_AUTO,
890 .name = "Automatic format guessing",
891 .type = V4L2_CTRL_TYPE_BOOLEAN,
898 static const char * const ctrl_run_mode_menu[] = {
902 "Continuous capture",
906 static const struct v4l2_ctrl_config ctrl_run_mode = {
908 .id = V4L2_CID_RUN_MODE,
909 .name = "Atomisp run mode",
910 .type = V4L2_CTRL_TYPE_MENU,
914 .qmenu = ctrl_run_mode_menu,
917 static const char * const ctrl_vfpp_mode_menu[] = {
918 "Enable", /* vfpp always enabled */
919 "Disable to scaler mode", /* CSS into video mode and disable */
920 "Disable to low latency mode", /* CSS into still mode and disable */
923 static const struct v4l2_ctrl_config ctrl_vfpp = {
925 .name = "Atomisp vf postprocess",
926 .type = V4L2_CTRL_TYPE_MENU,
930 .qmenu = ctrl_vfpp_mode_menu,
934 * Control for ISP continuous mode
936 * When enabled, capture processing is possible without
937 * stopping the preview pipeline. When disabled, ISP needs
938 * to be restarted between preview and capture.
940 static const struct v4l2_ctrl_config ctrl_continuous_mode = {
942 .id = V4L2_CID_ATOMISP_CONTINUOUS_MODE,
943 .type = V4L2_CTRL_TYPE_BOOLEAN,
944 .name = "Continuous mode",
952 * Control for continuous mode raw buffer size
954 * The size of the RAW ringbuffer sets limit on how much
955 * back in time application can go when requesting capture
956 * frames to be rendered, and how many frames can be rendered
957 * in a burst at full sensor rate.
959 * Note: this setting has a big impact on memory consumption of
962 static const struct v4l2_ctrl_config ctrl_continuous_raw_buffer_size = {
964 .id = V4L2_CID_ATOMISP_CONTINUOUS_RAW_BUFFER_SIZE,
965 .type = V4L2_CTRL_TYPE_INTEGER,
966 .name = "Continuous raw ringbuffer size",
968 .max = 100, /* depends on CSS version, runtime checked */
974 * Control for enabling continuous viewfinder
976 * When enabled, and ISP is in continuous mode (see ctrl_continuous_mode ),
977 * preview pipeline continues concurrently with capture
978 * processing. When disabled, and continuous mode is used,
979 * preview is paused while captures are processed, but
980 * full pipeline restart is not needed.
982 * By setting this to disabled, capture processing is
983 * essentially given priority over preview, and the effective
984 * capture output rate may be higher than with continuous
985 * viewfinder enabled.
987 static const struct v4l2_ctrl_config ctrl_continuous_viewfinder = {
988 .id = V4L2_CID_ATOMISP_CONTINUOUS_VIEWFINDER,
989 .type = V4L2_CTRL_TYPE_BOOLEAN,
990 .name = "Continuous viewfinder",
998 * Control for enabling Lock&Unlock Raw Buffer mechanism
1000 * When enabled, Raw Buffer can be locked and unlocked.
1001 * Application can hold the exp_id of Raw Buffer
1002 * and unlock it when no longer needed.
1003 * Note: Make sure set this configuration before creating stream.
1005 static const struct v4l2_ctrl_config ctrl_enable_raw_buffer_lock = {
1006 .id = V4L2_CID_ENABLE_RAW_BUFFER_LOCK,
1007 .type = V4L2_CTRL_TYPE_BOOLEAN,
1008 .name = "Lock Unlock Raw Buffer",
1016 * Control to disable digital zoom of the whole stream
1018 * When it is true, pipe configuation enable_dz will be set to false.
1019 * This can help get a better performance by disabling pp binary.
1021 * Note: Make sure set this configuration before creating stream.
1023 static const struct v4l2_ctrl_config ctrl_disable_dz = {
1024 .id = V4L2_CID_DISABLE_DZ,
1025 .type = V4L2_CTRL_TYPE_BOOLEAN,
1026 .name = "Disable digital zoom",
1034 * Control for ISP depth mode
1036 * When enabled, that means ISP will deal with dual streams and sensors will be
1037 * in slave/master mode.
1038 * slave sensor will have no output until master sensor is streamed on.
1040 static const struct v4l2_ctrl_config ctrl_depth_mode = {
1042 .id = V4L2_CID_DEPTH_MODE,
1043 .type = V4L2_CTRL_TYPE_BOOLEAN,
1044 .name = "Depth mode",
1053 * Control for selectting ISP version
1055 * When enabled, that means ISP version will be used ISP2.7. when disable, the
1056 * isp will default to use ISP2.2.
1057 * Note: Make sure set this configuration before creating stream.
1059 static const struct v4l2_ctrl_config ctrl_select_isp_version = {
1061 .id = V4L2_CID_ATOMISP_SELECT_ISP_VERSION,
1062 .type = V4L2_CTRL_TYPE_BOOLEAN,
1063 .name = "Select Isp version",
1072 * Control for ISP ion device fd
1074 * userspace will open ion device and pass the fd to kernel.
1075 * this fd will be used to map shared fd to buffer.
1077 static const struct v4l2_ctrl_config ctrl_ion_dev_fd = {
1079 .id = V4L2_CID_ATOMISP_ION_DEVICE_FD,
1080 .type = V4L2_CTRL_TYPE_INTEGER,
1081 .name = "Ion Device Fd",
1090 static void atomisp_init_subdev_pipe(struct atomisp_sub_device *asd,
1091 struct atomisp_video_pipe *pipe, enum v4l2_buf_type buf_type)
1093 pipe->type = buf_type;
1095 pipe->isp = asd->isp;
1096 spin_lock_init(&pipe->irq_lock);
1097 INIT_LIST_HEAD(&pipe->activeq);
1098 INIT_LIST_HEAD(&pipe->activeq_out);
1099 INIT_LIST_HEAD(&pipe->buffers_waiting_for_param);
1100 INIT_LIST_HEAD(&pipe->per_frame_params);
1101 memset(pipe->frame_request_config_id,
1102 0, VIDEO_MAX_FRAME * sizeof(unsigned int));
1103 memset(pipe->frame_params,
1104 0, VIDEO_MAX_FRAME *
1105 sizeof(struct atomisp_css_params_with_list *));
1108 static void atomisp_init_acc_pipe(struct atomisp_sub_device *asd,
1109 struct atomisp_acc_pipe *pipe)
1112 pipe->isp = asd->isp;
1113 INIT_LIST_HEAD(&asd->acc.fw);
1114 INIT_LIST_HEAD(&asd->acc.memory_maps);
1115 ida_init(&asd->acc.ida);
1119 * isp_subdev_init_entities - Initialize V4L2 subdev and media entity
1120 * @asd: ISP CCDC module
1122 * Return 0 on success and a negative error code on failure.
1124 static int isp_subdev_init_entities(struct atomisp_sub_device *asd)
1126 struct v4l2_subdev *sd = &asd->subdev;
1127 struct media_pad *pads = asd->pads;
1128 struct media_entity *me = &sd->entity;
1131 asd->input = ATOMISP_SUBDEV_INPUT_NONE;
1133 v4l2_subdev_init(sd, &isp_subdev_v4l2_ops);
1134 sprintf(sd->name, "ATOMISP_SUBDEV_%d", asd->index);
1135 v4l2_set_subdevdata(sd, asd);
1136 sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE;
1138 pads[ATOMISP_SUBDEV_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
1139 pads[ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW].flags = MEDIA_PAD_FL_SOURCE;
1140 pads[ATOMISP_SUBDEV_PAD_SOURCE_VF].flags = MEDIA_PAD_FL_SOURCE;
1141 pads[ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE].flags = MEDIA_PAD_FL_SOURCE;
1142 pads[ATOMISP_SUBDEV_PAD_SOURCE_VIDEO].flags = MEDIA_PAD_FL_SOURCE;
1144 asd->fmt[ATOMISP_SUBDEV_PAD_SINK].fmt.code =
1145 MEDIA_BUS_FMT_SBGGR10_1X10;
1146 asd->fmt[ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW].fmt.code =
1147 MEDIA_BUS_FMT_SBGGR10_1X10;
1148 asd->fmt[ATOMISP_SUBDEV_PAD_SOURCE_VF].fmt.code =
1149 MEDIA_BUS_FMT_SBGGR10_1X10;
1150 asd->fmt[ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE].fmt.code =
1151 MEDIA_BUS_FMT_SBGGR10_1X10;
1152 asd->fmt[ATOMISP_SUBDEV_PAD_SOURCE_VIDEO].fmt.code =
1153 MEDIA_BUS_FMT_SBGGR10_1X10;
1155 me->ops = &isp_subdev_media_ops;
1156 me->function = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN;
1157 ret = media_entity_pads_init(me, ATOMISP_SUBDEV_PADS_NUM, pads);
1161 atomisp_init_subdev_pipe(asd, &asd->video_in,
1162 V4L2_BUF_TYPE_VIDEO_OUTPUT);
1164 atomisp_init_subdev_pipe(asd, &asd->video_out_preview,
1165 V4L2_BUF_TYPE_VIDEO_CAPTURE);
1167 atomisp_init_subdev_pipe(asd, &asd->video_out_vf,
1168 V4L2_BUF_TYPE_VIDEO_CAPTURE);
1170 atomisp_init_subdev_pipe(asd, &asd->video_out_capture,
1171 V4L2_BUF_TYPE_VIDEO_CAPTURE);
1173 atomisp_init_subdev_pipe(asd, &asd->video_out_video_capture,
1174 V4L2_BUF_TYPE_VIDEO_CAPTURE);
1176 atomisp_init_acc_pipe(asd, &asd->video_acc);
1178 ret = atomisp_video_init(&asd->video_in, "MEMORY");
1182 ret = atomisp_video_init(&asd->video_out_capture, "CAPTURE");
1186 ret = atomisp_video_init(&asd->video_out_vf, "VIEWFINDER");
1190 ret = atomisp_video_init(&asd->video_out_preview, "PREVIEW");
1194 ret = atomisp_video_init(&asd->video_out_video_capture, "VIDEO");
1198 atomisp_acc_init(&asd->video_acc, "ACC");
1200 ret = v4l2_ctrl_handler_init(&asd->ctrl_handler, 1);
1204 asd->fmt_auto = v4l2_ctrl_new_custom(&asd->ctrl_handler,
1205 &ctrl_fmt_auto, NULL);
1206 asd->run_mode = v4l2_ctrl_new_custom(&asd->ctrl_handler,
1207 &ctrl_run_mode, NULL);
1208 asd->vfpp = v4l2_ctrl_new_custom(&asd->ctrl_handler,
1210 asd->continuous_mode = v4l2_ctrl_new_custom(&asd->ctrl_handler,
1211 &ctrl_continuous_mode, NULL);
1212 asd->continuous_viewfinder = v4l2_ctrl_new_custom(&asd->ctrl_handler,
1213 &ctrl_continuous_viewfinder,
1215 asd->continuous_raw_buffer_size =
1216 v4l2_ctrl_new_custom(&asd->ctrl_handler,
1217 &ctrl_continuous_raw_buffer_size,
1220 asd->enable_raw_buffer_lock =
1221 v4l2_ctrl_new_custom(&asd->ctrl_handler,
1222 &ctrl_enable_raw_buffer_lock,
1225 v4l2_ctrl_new_custom(&asd->ctrl_handler,
1229 v4l2_ctrl_new_custom(&asd->ctrl_handler,
1233 asd->select_isp_version =
1234 v4l2_ctrl_new_custom(&asd->ctrl_handler,
1235 &ctrl_select_isp_version,
1240 v4l2_ctrl_new_custom(&asd->ctrl_handler,
1246 /* Make controls visible on subdev as well. */
1247 asd->subdev.ctrl_handler = &asd->ctrl_handler;
1248 spin_lock_init(&asd->raw_buffer_bitmap_lock);
1249 return asd->ctrl_handler.error;
1252 int atomisp_create_pads_links(struct atomisp_device *isp)
1254 struct atomisp_sub_device *asd;
1256 isp->num_of_streams = 2;
1257 for (i = 0; i < ATOMISP_CAMERA_NR_PORTS; i++) {
1258 for (j = 0; j < isp->num_of_streams; j++) {
1260 media_create_pad_link(&isp->csi2_port[i].subdev.
1261 entity, CSI2_PAD_SOURCE,
1262 &isp->asd[j].subdev.entity,
1263 ATOMISP_SUBDEV_PAD_SINK, 0);
1268 for (i = 0; i < isp->input_cnt - 2; i++) {
1269 ret = media_create_pad_link(&isp->inputs[i].camera->entity, 0,
1270 &isp->csi2_port[isp->inputs[i].
1271 port].subdev.entity,
1273 MEDIA_LNK_FL_ENABLED |
1274 MEDIA_LNK_FL_IMMUTABLE);
1278 for (i = 0; i < isp->num_of_streams; i++) {
1280 ret = media_create_pad_link(&asd->subdev.entity,
1281 ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW,
1282 &asd->video_out_preview.vdev.entity,
1286 ret = media_create_pad_link(&asd->subdev.entity,
1287 ATOMISP_SUBDEV_PAD_SOURCE_VF,
1288 &asd->video_out_vf.vdev.entity, 0,
1292 ret = media_create_pad_link(&asd->subdev.entity,
1293 ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE,
1294 &asd->video_out_capture.vdev.entity,
1298 ret = media_create_pad_link(&asd->subdev.entity,
1299 ATOMISP_SUBDEV_PAD_SOURCE_VIDEO,
1300 &asd->video_out_video_capture.vdev.
1305 * file input only supported on subdev0
1306 * so do not create pad link for subdevs other then subdev0
1310 ret = media_create_pad_link(&asd->video_in.vdev.entity,
1311 0, &asd->subdev.entity,
1312 ATOMISP_SUBDEV_PAD_SINK, 0);
1319 static void atomisp_subdev_cleanup_entities(struct atomisp_sub_device *asd)
1321 v4l2_ctrl_handler_free(&asd->ctrl_handler);
1323 media_entity_cleanup(&asd->subdev.entity);
1326 void atomisp_subdev_cleanup_pending_events(struct atomisp_sub_device *asd)
1328 struct v4l2_fh *fh, *fh_tmp;
1329 struct v4l2_event event;
1330 unsigned int i, pending_event;
1332 list_for_each_entry_safe(fh, fh_tmp,
1333 &asd->subdev.devnode->fh_list, list) {
1334 pending_event = v4l2_event_pending(fh);
1335 for (i = 0; i < pending_event; i++)
1336 v4l2_event_dequeue(fh, &event, 1);
1340 void atomisp_subdev_unregister_entities(struct atomisp_sub_device *asd)
1342 atomisp_subdev_cleanup_entities(asd);
1343 v4l2_device_unregister_subdev(&asd->subdev);
1344 atomisp_video_unregister(&asd->video_in);
1345 atomisp_video_unregister(&asd->video_out_preview);
1346 atomisp_video_unregister(&asd->video_out_vf);
1347 atomisp_video_unregister(&asd->video_out_capture);
1348 atomisp_video_unregister(&asd->video_out_video_capture);
1349 atomisp_acc_unregister(&asd->video_acc);
1352 int atomisp_subdev_register_entities(struct atomisp_sub_device *asd,
1353 struct v4l2_device *vdev)
1357 /* Register the subdev and video node. */
1358 ret = v4l2_device_register_subdev(vdev, &asd->subdev);
1362 ret = atomisp_video_register(&asd->video_out_capture, vdev);
1366 ret = atomisp_video_register(&asd->video_out_vf, vdev);
1370 ret = atomisp_video_register(&asd->video_out_preview, vdev);
1374 ret = atomisp_video_register(&asd->video_out_video_capture, vdev);
1378 ret = atomisp_acc_register(&asd->video_acc, vdev);
1383 * file input only supported on subdev0
1384 * so do not create video node for subdevs other then subdev0
1388 ret = atomisp_video_register(&asd->video_in, vdev);
1395 atomisp_subdev_unregister_entities(asd);
1400 * atomisp_subdev_init - ISP Subdevice initialization.
1401 * @dev: Device pointer specific to the ATOM ISP.
1403 * TODO: Get the initialisation values from platform data.
1405 * Return 0 on success or a negative error code otherwise.
1407 int atomisp_subdev_init(struct atomisp_device *isp)
1409 struct atomisp_sub_device *asd;
1413 * CSS2.0 running ISP2400 support
1416 isp->num_of_streams = 2;
1417 isp->asd = devm_kzalloc(isp->dev, sizeof(struct atomisp_sub_device) *
1418 isp->num_of_streams, GFP_KERNEL);
1421 for (i = 0; i < isp->num_of_streams; i++) {
1423 spin_lock_init(&asd->lock);
1425 isp_subdev_init_params(asd);
1427 ret = isp_subdev_init_entities(asd);
1429 atomisp_subdev_cleanup_entities(asd);