1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17#include <linux/module.h>
18#include <linux/uaccess.h>
19#include <linux/delay.h>
20#include <linux/device.h>
21#include <linux/mm.h>
22#include <linux/sched.h>
23#include <linux/slab.h>
24
25#include <media/v4l2-event.h>
26#include <media/v4l2-mediabus.h>
27#include "atomisp_cmd.h"
28#include "atomisp_common.h"
29#include "atomisp_compat.h"
30#include "atomisp_internal.h"
31
32const struct atomisp_in_fmt_conv atomisp_in_fmt_conv[] = {
33 { MEDIA_BUS_FMT_SBGGR8_1X8, 8, 8, ATOMISP_INPUT_FORMAT_RAW_8, CSS_BAYER_ORDER_BGGR, CSS_FORMAT_RAW_8 },
34 { MEDIA_BUS_FMT_SGBRG8_1X8, 8, 8, ATOMISP_INPUT_FORMAT_RAW_8, CSS_BAYER_ORDER_GBRG, CSS_FORMAT_RAW_8 },
35 { MEDIA_BUS_FMT_SGRBG8_1X8, 8, 8, ATOMISP_INPUT_FORMAT_RAW_8, CSS_BAYER_ORDER_GRBG, CSS_FORMAT_RAW_8 },
36 { MEDIA_BUS_FMT_SRGGB8_1X8, 8, 8, ATOMISP_INPUT_FORMAT_RAW_8, CSS_BAYER_ORDER_RGGB, CSS_FORMAT_RAW_8 },
37 { MEDIA_BUS_FMT_SBGGR10_1X10, 10, 10, ATOMISP_INPUT_FORMAT_RAW_10, CSS_BAYER_ORDER_BGGR, CSS_FORMAT_RAW_10 },
38 { MEDIA_BUS_FMT_SGBRG10_1X10, 10, 10, ATOMISP_INPUT_FORMAT_RAW_10, CSS_BAYER_ORDER_GBRG, CSS_FORMAT_RAW_10 },
39 { MEDIA_BUS_FMT_SGRBG10_1X10, 10, 10, ATOMISP_INPUT_FORMAT_RAW_10, CSS_BAYER_ORDER_GRBG, CSS_FORMAT_RAW_10 },
40 { MEDIA_BUS_FMT_SRGGB10_1X10, 10, 10, ATOMISP_INPUT_FORMAT_RAW_10, CSS_BAYER_ORDER_RGGB, CSS_FORMAT_RAW_10 },
41 { MEDIA_BUS_FMT_SBGGR12_1X12, 12, 12, ATOMISP_INPUT_FORMAT_RAW_12, CSS_BAYER_ORDER_BGGR, CSS_FORMAT_RAW_12 },
42 { MEDIA_BUS_FMT_SGBRG12_1X12, 12, 12, ATOMISP_INPUT_FORMAT_RAW_12, CSS_BAYER_ORDER_GBRG, CSS_FORMAT_RAW_12 },
43 { MEDIA_BUS_FMT_SGRBG12_1X12, 12, 12, ATOMISP_INPUT_FORMAT_RAW_12, CSS_BAYER_ORDER_GRBG, CSS_FORMAT_RAW_12 },
44 { MEDIA_BUS_FMT_SRGGB12_1X12, 12, 12, ATOMISP_INPUT_FORMAT_RAW_12, CSS_BAYER_ORDER_RGGB, CSS_FORMAT_RAW_12 },
45 { MEDIA_BUS_FMT_UYVY8_1X16, 8, 8, ATOMISP_INPUT_FORMAT_YUV422_8, 0, ATOMISP_INPUT_FORMAT_YUV422_8 },
46 { MEDIA_BUS_FMT_YUYV8_1X16, 8, 8, ATOMISP_INPUT_FORMAT_YUV422_8, 0, ATOMISP_INPUT_FORMAT_YUV422_8 },
47 { MEDIA_BUS_FMT_JPEG_1X8, 8, 8, CSS_FRAME_FORMAT_BINARY_8, 0, ATOMISP_INPUT_FORMAT_BINARY_8 },
48 { V4L2_MBUS_FMT_CUSTOM_NV12, 12, 12, CSS_FRAME_FORMAT_NV12, 0, CSS_FRAME_FORMAT_NV12 },
49 { V4L2_MBUS_FMT_CUSTOM_NV21, 12, 12, CSS_FRAME_FORMAT_NV21, 0, CSS_FRAME_FORMAT_NV21 },
50 { V4L2_MBUS_FMT_CUSTOM_YUV420, 12, 12, ATOMISP_INPUT_FORMAT_YUV420_8_LEGACY, 0, ATOMISP_INPUT_FORMAT_YUV420_8_LEGACY },
51#if 0
52 { V4L2_MBUS_FMT_CUSTOM_M10MO_RAW, 8, 8, CSS_FRAME_FORMAT_BINARY_8, 0, ATOMISP_INPUT_FORMAT_BINARY_8 },
53#endif
54
55 { 0, 0, 0, ATOMISP_INPUT_FORMAT_EMBEDDED, 0, ATOMISP_INPUT_FORMAT_EMBEDDED },
56 {}
57};
58
59static const struct {
60 u32 code;
61 u32 compressed;
62} compressed_codes[] = {
63 { MEDIA_BUS_FMT_SBGGR10_1X10, MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8 },
64 { MEDIA_BUS_FMT_SGBRG10_1X10, MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8 },
65 { MEDIA_BUS_FMT_SGRBG10_1X10, MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8 },
66 { MEDIA_BUS_FMT_SRGGB10_1X10, MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8 },
67};
68
69u32 atomisp_subdev_uncompressed_code(u32 code)
70{
71 unsigned int i;
72
73 for (i = 0; i < ARRAY_SIZE(compressed_codes); i++)
74 if (code == compressed_codes[i].compressed)
75 return compressed_codes[i].code;
76
77 return code;
78}
79
80bool atomisp_subdev_is_compressed(u32 code)
81{
82 int i;
83
84 for (i = 0; i < ARRAY_SIZE(atomisp_in_fmt_conv) - 1; i++)
85 if (code == atomisp_in_fmt_conv[i].code)
86 return atomisp_in_fmt_conv[i].bpp !=
87 atomisp_in_fmt_conv[i].depth;
88
89 return false;
90}
91
92const struct atomisp_in_fmt_conv *atomisp_find_in_fmt_conv(u32 code)
93{
94 int i;
95
96 for (i = 0; i < ARRAY_SIZE(atomisp_in_fmt_conv) - 1; i++)
97 if (code == atomisp_in_fmt_conv[i].code)
98 return atomisp_in_fmt_conv + i;
99
100 return NULL;
101}
102
103const struct atomisp_in_fmt_conv *atomisp_find_in_fmt_conv_by_atomisp_in_fmt(
104 enum atomisp_input_format atomisp_in_fmt)
105{
106 int i;
107
108 for (i = 0; i < ARRAY_SIZE(atomisp_in_fmt_conv) - 1; i++)
109 if (atomisp_in_fmt_conv[i].atomisp_in_fmt == atomisp_in_fmt)
110 return atomisp_in_fmt_conv + i;
111
112 return NULL;
113}
114
115bool atomisp_subdev_format_conversion(struct atomisp_sub_device *asd,
116 unsigned int source_pad)
117{
118 struct v4l2_mbus_framefmt *sink, *src;
119
120 sink = atomisp_subdev_get_ffmt(&asd->subdev, NULL,
121 V4L2_SUBDEV_FORMAT_ACTIVE,
122 ATOMISP_SUBDEV_PAD_SINK);
123 src = atomisp_subdev_get_ffmt(&asd->subdev, NULL,
124 V4L2_SUBDEV_FORMAT_ACTIVE, source_pad);
125
126 return atomisp_is_mbuscode_raw(sink->code)
127 && !atomisp_is_mbuscode_raw(src->code);
128}
129
130uint16_t atomisp_subdev_source_pad(struct video_device * vdev)
131{
132 struct media_link *link;
133 uint16_t ret = 0;
134 list_for_each_entry(link, &vdev->entity.links, list) {
135 if (link->source) {
136 ret = link->source->index;
137 break;
138 }
139 }
140 return ret;
141}
142
143
144
145
146
147
148
149
150
151
152
153
154
155static long isp_subdev_ioctl(struct v4l2_subdev *sd,
156 unsigned int cmd, void *arg)
157{
158 return 0;
159}
160
161
162
163
164
165
166
167
168static int isp_subdev_set_power(struct v4l2_subdev *sd, int on)
169{
170 return 0;
171}
172
173static int isp_subdev_subscribe_event(struct v4l2_subdev *sd,
174 struct v4l2_fh *fh,
175 struct v4l2_event_subscription *sub)
176{
177 struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd);
178 struct atomisp_device *isp = isp_sd->isp;
179
180 if (sub->type != V4L2_EVENT_FRAME_SYNC &&
181 sub->type != V4L2_EVENT_FRAME_END &&
182 sub->type != V4L2_EVENT_ATOMISP_3A_STATS_READY &&
183 sub->type != V4L2_EVENT_ATOMISP_METADATA_READY &&
184 sub->type != V4L2_EVENT_ATOMISP_PAUSE_BUFFER &&
185 sub->type != V4L2_EVENT_ATOMISP_CSS_RESET &&
186 sub->type != V4L2_EVENT_ATOMISP_RAW_BUFFERS_ALLOC_DONE &&
187 sub->type != V4L2_EVENT_ATOMISP_ACC_COMPLETE)
188 return -EINVAL;
189
190 if (sub->type == V4L2_EVENT_FRAME_SYNC &&
191 !atomisp_css_valid_sof(isp))
192 return -EINVAL;
193
194 return v4l2_event_subscribe(fh, sub, 16, NULL);
195}
196
197static int isp_subdev_unsubscribe_event(struct v4l2_subdev *sd,
198 struct v4l2_fh *fh,
199 struct v4l2_event_subscription *sub)
200{
201 return v4l2_event_unsubscribe(fh, sub);
202}
203
204
205
206
207
208
209
210
211static int isp_subdev_enum_mbus_code(struct v4l2_subdev *sd,
212 struct v4l2_subdev_pad_config *cfg,
213 struct v4l2_subdev_mbus_code_enum *code)
214{
215 if (code->index >= ARRAY_SIZE(atomisp_in_fmt_conv) - 1)
216 return -EINVAL;
217
218 code->code = atomisp_in_fmt_conv[code->index].code;
219
220 return 0;
221}
222
223static int isp_subdev_validate_rect(struct v4l2_subdev *sd, uint32_t pad,
224 uint32_t target)
225{
226 switch (pad) {
227 case ATOMISP_SUBDEV_PAD_SINK:
228 switch (target) {
229 case V4L2_SEL_TGT_CROP:
230 return 0;
231 }
232 break;
233 default:
234 switch (target) {
235 case V4L2_SEL_TGT_COMPOSE:
236 return 0;
237 }
238 break;
239 }
240
241 return -EINVAL;
242}
243
244struct v4l2_rect *atomisp_subdev_get_rect(struct v4l2_subdev *sd,
245 struct v4l2_subdev_pad_config *cfg,
246 uint32_t which, uint32_t pad,
247 uint32_t target)
248{
249 struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd);
250
251 if (which == V4L2_SUBDEV_FORMAT_TRY) {
252 switch (target) {
253 case V4L2_SEL_TGT_CROP:
254 return v4l2_subdev_get_try_crop(sd, cfg, pad);
255 case V4L2_SEL_TGT_COMPOSE:
256 return v4l2_subdev_get_try_compose(sd, cfg, pad);
257 }
258 }
259
260 switch (target) {
261 case V4L2_SEL_TGT_CROP:
262 return &isp_sd->fmt[pad].crop;
263 case V4L2_SEL_TGT_COMPOSE:
264 return &isp_sd->fmt[pad].compose;
265 }
266
267 return NULL;
268}
269
270struct v4l2_mbus_framefmt
271*atomisp_subdev_get_ffmt(struct v4l2_subdev *sd,
272 struct v4l2_subdev_pad_config *cfg, uint32_t which,
273 uint32_t pad)
274{
275 struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd);
276
277 if (which == V4L2_SUBDEV_FORMAT_TRY)
278 return v4l2_subdev_get_try_format(sd, cfg, pad);
279
280 return &isp_sd->fmt[pad].fmt;
281}
282
283static void isp_get_fmt_rect(struct v4l2_subdev *sd,
284 struct v4l2_subdev_pad_config *cfg, uint32_t which,
285 struct v4l2_mbus_framefmt **ffmt,
286 struct v4l2_rect *crop[ATOMISP_SUBDEV_PADS_NUM],
287 struct v4l2_rect *comp[ATOMISP_SUBDEV_PADS_NUM])
288{
289 unsigned int i;
290
291 for (i = 0; i < ATOMISP_SUBDEV_PADS_NUM; i++) {
292 ffmt[i] = atomisp_subdev_get_ffmt(sd, cfg, which, i);
293 crop[i] = atomisp_subdev_get_rect(sd, cfg, which, i,
294 V4L2_SEL_TGT_CROP);
295 comp[i] = atomisp_subdev_get_rect(sd, cfg, which, i,
296 V4L2_SEL_TGT_COMPOSE);
297 }
298}
299
300static void isp_subdev_propagate(struct v4l2_subdev *sd,
301 struct v4l2_subdev_pad_config *cfg,
302 uint32_t which, uint32_t pad, uint32_t target,
303 uint32_t flags)
304{
305 struct v4l2_mbus_framefmt *ffmt[ATOMISP_SUBDEV_PADS_NUM];
306 struct v4l2_rect *crop[ATOMISP_SUBDEV_PADS_NUM],
307 *comp[ATOMISP_SUBDEV_PADS_NUM];
308
309 if (flags & V4L2_SEL_FLAG_KEEP_CONFIG)
310 return;
311
312 isp_get_fmt_rect(sd, cfg, which, ffmt, crop, comp);
313
314 switch (pad) {
315 case ATOMISP_SUBDEV_PAD_SINK: {
316 struct v4l2_rect r = {0};
317
318
319 r.width = ffmt[pad]->width;
320 r.height = ffmt[pad]->height;
321
322 atomisp_subdev_set_selection(sd, cfg, which, pad,
323 target, flags, &r);
324 break;
325 }
326 }
327}
328
329static int isp_subdev_get_selection(struct v4l2_subdev *sd,
330 struct v4l2_subdev_pad_config *cfg,
331 struct v4l2_subdev_selection *sel)
332{
333 struct v4l2_rect *rec;
334 int rval = isp_subdev_validate_rect(sd, sel->pad, sel->target);
335
336 if (rval)
337 return rval;
338
339 rec = atomisp_subdev_get_rect(sd, cfg, sel->which, sel->pad,
340 sel->target);
341 if (!rec)
342 return -EINVAL;
343
344 sel->r = *rec;
345 return 0;
346}
347
348static char *atomisp_pad_str[] = { "ATOMISP_SUBDEV_PAD_SINK",
349 "ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE",
350 "ATOMISP_SUBDEV_PAD_SOURCE_VF",
351 "ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW",
352 "ATOMISP_SUBDEV_PAD_SOURCE_VIDEO"};
353
354int atomisp_subdev_set_selection(struct v4l2_subdev *sd,
355 struct v4l2_subdev_pad_config *cfg,
356 uint32_t which, uint32_t pad, uint32_t target,
357 uint32_t flags, struct v4l2_rect *r)
358{
359 struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd);
360 struct atomisp_device *isp = isp_sd->isp;
361 struct v4l2_mbus_framefmt *ffmt[ATOMISP_SUBDEV_PADS_NUM];
362 uint16_t vdev_pad = atomisp_subdev_source_pad(sd->devnode);
363 struct v4l2_rect *crop[ATOMISP_SUBDEV_PADS_NUM],
364 *comp[ATOMISP_SUBDEV_PADS_NUM];
365 enum atomisp_input_stream_id stream_id;
366 unsigned int i;
367 unsigned int padding_w = pad_w;
368 unsigned int padding_h = pad_h;
369
370 stream_id = atomisp_source_pad_to_stream_id(isp_sd, vdev_pad);
371
372 isp_get_fmt_rect(sd, cfg, which, ffmt, crop, comp);
373
374 dev_dbg(isp->dev,
375 "sel: pad %s tgt %s l %d t %d w %d h %d which %s f 0x%8.8x\n",
376 atomisp_pad_str[pad], target == V4L2_SEL_TGT_CROP
377 ? "V4L2_SEL_TGT_CROP" : "V4L2_SEL_TGT_COMPOSE",
378 r->left, r->top, r->width, r->height,
379 which == V4L2_SUBDEV_FORMAT_TRY ? "V4L2_SUBDEV_FORMAT_TRY"
380 : "V4L2_SUBDEV_FORMAT_ACTIVE", flags);
381
382 r->width = rounddown(r->width, ATOM_ISP_STEP_WIDTH);
383 r->height = rounddown(r->height, ATOM_ISP_STEP_HEIGHT);
384
385 switch (pad) {
386 case ATOMISP_SUBDEV_PAD_SINK: {
387
388 unsigned int dvs_w, dvs_h;
389
390 crop[pad]->width = ffmt[pad]->width;
391 crop[pad]->height = ffmt[pad]->height;
392
393
394
395 if (!strncmp(isp->inputs[isp_sd->input_curr].camera->name,
396 "ov2722", 6) && crop[pad]->height == 1092) {
397 padding_w = 12;
398 padding_h = 12;
399 }
400
401 if (isp->inputs[isp_sd->input_curr].type == SOC_CAMERA) {
402 padding_w = 0;
403 padding_h = 0;
404 }
405
406 if (atomisp_subdev_format_conversion(isp_sd,
407 isp_sd->capture_pad)
408 && crop[pad]->width && crop[pad]->height)
409 crop[pad]->width -= padding_w, crop[pad]->height -= padding_h;
410
411
412 if (isp->inputs[isp_sd->input_curr].type == SOC_CAMERA)
413 isp_sd->params.video_dis_en = 0;
414
415 if (isp_sd->params.video_dis_en &&
416 isp_sd->run_mode->val == ATOMISP_RUN_MODE_VIDEO &&
417 !isp_sd->continuous_mode->val) {
418
419
420
421
422
423 crop[pad]->width = roundup(crop[pad]->width * 5 / 6,
424 ATOM_ISP_STEP_WIDTH);
425 crop[pad]->height = roundup(crop[pad]->height * 5 / 6,
426 ATOM_ISP_STEP_HEIGHT);
427 }
428
429 crop[pad]->width = min(crop[pad]->width, r->width);
430 crop[pad]->height = min(crop[pad]->height, r->height);
431
432 if (!(flags & V4L2_SEL_FLAG_KEEP_CONFIG)) {
433 for (i = ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE;
434 i < ATOMISP_SUBDEV_PADS_NUM; i++) {
435 struct v4l2_rect tmp = *crop[pad];
436
437 atomisp_subdev_set_selection(
438 sd, cfg, which, i, V4L2_SEL_TGT_COMPOSE,
439 flags, &tmp);
440 }
441 }
442
443 if (which == V4L2_SUBDEV_FORMAT_TRY)
444 break;
445
446 if (isp_sd->params.video_dis_en &&
447 isp_sd->run_mode->val == ATOMISP_RUN_MODE_VIDEO &&
448 !isp_sd->continuous_mode->val) {
449 dvs_w = rounddown(crop[pad]->width / 5,
450 ATOM_ISP_STEP_WIDTH);
451 dvs_h = rounddown(crop[pad]->height / 5,
452 ATOM_ISP_STEP_HEIGHT);
453 } else if (!isp_sd->params.video_dis_en &&
454 isp_sd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) {
455
456
457
458
459 dvs_w = dvs_h = 12;
460 } else
461 dvs_w = dvs_h = 0;
462
463 atomisp_css_video_set_dis_envelope(isp_sd, dvs_w, dvs_h);
464 atomisp_css_input_set_effective_resolution(isp_sd, stream_id,
465 crop[pad]->width, crop[pad]->height);
466
467 break;
468 }
469 case ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE:
470 case ATOMISP_SUBDEV_PAD_SOURCE_VIDEO: {
471
472
473 if (isp_sd->vfpp->val == ATOMISP_VFPP_DISABLE_LOWLAT) {
474
475 r->width = crop[ATOMISP_SUBDEV_PAD_SINK]->width;
476 r->height = crop[ATOMISP_SUBDEV_PAD_SINK]->height;
477 }
478
479 if (crop[ATOMISP_SUBDEV_PAD_SINK]->width == r->width
480 && crop[ATOMISP_SUBDEV_PAD_SINK]->height == r->height)
481 isp_sd->params.yuv_ds_en = false;
482 else
483 isp_sd->params.yuv_ds_en = true;
484
485 comp[pad]->width = r->width;
486 comp[pad]->height = r->height;
487
488 if (r->width == 0 || r->height == 0 ||
489 crop[ATOMISP_SUBDEV_PAD_SINK]->width == 0 ||
490 crop[ATOMISP_SUBDEV_PAD_SINK]->height == 0)
491 break;
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506 if (r->width * crop[ATOMISP_SUBDEV_PAD_SINK]->height <
507 crop[ATOMISP_SUBDEV_PAD_SINK]->width * r->height)
508 atomisp_css_input_set_effective_resolution(isp_sd,
509 stream_id,
510 rounddown(crop[ATOMISP_SUBDEV_PAD_SINK]->
511 height * r->width / r->height,
512 ATOM_ISP_STEP_WIDTH),
513 crop[ATOMISP_SUBDEV_PAD_SINK]->height);
514 else
515 atomisp_css_input_set_effective_resolution(isp_sd,
516 stream_id,
517 crop[ATOMISP_SUBDEV_PAD_SINK]->width,
518 rounddown(crop[ATOMISP_SUBDEV_PAD_SINK]->
519 width * r->height / r->width,
520 ATOM_ISP_STEP_WIDTH));
521
522 break;
523 }
524 case ATOMISP_SUBDEV_PAD_SOURCE_VF:
525 case ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW:
526 comp[pad]->width = r->width;
527 comp[pad]->height = r->height;
528 break;
529 default:
530 return -EINVAL;
531 }
532
533
534 if (pad != ATOMISP_SUBDEV_PAD_SINK) {
535 ffmt[pad]->width = comp[pad]->width;
536 ffmt[pad]->height = comp[pad]->height;
537 }
538
539 if (!atomisp_subdev_get_rect(sd, cfg, which, pad, target))
540 return -EINVAL;
541 *r = *atomisp_subdev_get_rect(sd, cfg, which, pad, target);
542
543 dev_dbg(isp->dev, "sel actual: l %d t %d w %d h %d\n",
544 r->left, r->top, r->width, r->height);
545
546 return 0;
547}
548
549static int isp_subdev_set_selection(struct v4l2_subdev *sd,
550 struct v4l2_subdev_pad_config *cfg,
551 struct v4l2_subdev_selection *sel)
552{
553 int rval = isp_subdev_validate_rect(sd, sel->pad, sel->target);
554 if (rval)
555 return rval;
556
557 return atomisp_subdev_set_selection(sd, cfg, sel->which, sel->pad,
558 sel->target, sel->flags, &sel->r);
559}
560
561static int atomisp_get_sensor_bin_factor(struct atomisp_sub_device *asd)
562{
563 struct v4l2_control ctrl = {0};
564 struct atomisp_device *isp = asd->isp;
565 int hbin, vbin;
566 int ret;
567
568 if (isp->inputs[asd->input_curr].type == FILE_INPUT ||
569 isp->inputs[asd->input_curr].type == TEST_PATTERN)
570 return 0;
571
572 ctrl.id = V4L2_CID_BIN_FACTOR_HORZ;
573 ret =
574 v4l2_g_ctrl(isp->inputs[asd->input_curr].camera->ctrl_handler,
575 &ctrl);
576 hbin = ctrl.value;
577 ctrl.id = V4L2_CID_BIN_FACTOR_VERT;
578 ret |=
579 v4l2_g_ctrl(isp->inputs[asd->input_curr].camera->ctrl_handler,
580 &ctrl);
581 vbin = ctrl.value;
582
583
584
585
586
587
588
589 if (ret || hbin != vbin)
590 hbin = 0;
591
592 return hbin;
593}
594
595void atomisp_subdev_set_ffmt(struct v4l2_subdev *sd,
596 struct v4l2_subdev_pad_config *cfg, uint32_t which,
597 uint32_t pad, struct v4l2_mbus_framefmt *ffmt)
598{
599 struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd);
600 struct atomisp_device *isp = isp_sd->isp;
601 struct v4l2_mbus_framefmt *__ffmt =
602 atomisp_subdev_get_ffmt(sd, cfg, which, pad);
603 uint16_t vdev_pad = atomisp_subdev_source_pad(sd->devnode);
604 enum atomisp_input_stream_id stream_id;
605
606 dev_dbg(isp->dev, "ffmt: pad %s w %d h %d code 0x%8.8x which %s\n",
607 atomisp_pad_str[pad], ffmt->width, ffmt->height, ffmt->code,
608 which == V4L2_SUBDEV_FORMAT_TRY ? "V4L2_SUBDEV_FORMAT_TRY"
609 : "V4L2_SUBDEV_FORMAT_ACTIVE");
610
611 stream_id = atomisp_source_pad_to_stream_id(isp_sd, vdev_pad);
612
613 switch (pad) {
614 case ATOMISP_SUBDEV_PAD_SINK: {
615 const struct atomisp_in_fmt_conv *fc =
616 atomisp_find_in_fmt_conv(ffmt->code);
617
618 if (!fc) {
619 fc = atomisp_in_fmt_conv;
620 ffmt->code = fc->code;
621 dev_dbg(isp->dev, "using 0x%8.8x instead\n",
622 ffmt->code);
623 }
624
625 *__ffmt = *ffmt;
626
627 isp_subdev_propagate(sd, cfg, which, pad,
628 V4L2_SEL_TGT_CROP, 0);
629
630 if (which == V4L2_SUBDEV_FORMAT_ACTIVE) {
631 atomisp_css_input_set_resolution(isp_sd,
632 stream_id, ffmt);
633 atomisp_css_input_set_binning_factor(isp_sd,
634 stream_id,
635 atomisp_get_sensor_bin_factor(isp_sd));
636 atomisp_css_input_set_bayer_order(isp_sd, stream_id,
637 fc->bayer_order);
638 atomisp_css_input_set_format(isp_sd, stream_id,
639 fc->css_stream_fmt);
640 atomisp_css_set_default_isys_config(isp_sd, stream_id,
641 ffmt);
642 }
643
644 break;
645 }
646 case ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE:
647 case ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW:
648 case ATOMISP_SUBDEV_PAD_SOURCE_VF:
649 case ATOMISP_SUBDEV_PAD_SOURCE_VIDEO:
650 __ffmt->code = ffmt->code;
651 break;
652 }
653}
654
655
656
657
658
659
660
661
662
663
664
665static int isp_subdev_get_format(struct v4l2_subdev *sd,
666 struct v4l2_subdev_pad_config *cfg,
667 struct v4l2_subdev_format *fmt)
668{
669 fmt->format = *atomisp_subdev_get_ffmt(sd, cfg, fmt->which, fmt->pad);
670
671 return 0;
672}
673
674
675
676
677
678
679
680
681
682
683
684static int isp_subdev_set_format(struct v4l2_subdev *sd,
685 struct v4l2_subdev_pad_config *cfg,
686 struct v4l2_subdev_format *fmt)
687{
688 atomisp_subdev_set_ffmt(sd, cfg, fmt->which, fmt->pad, &fmt->format);
689
690 return 0;
691}
692
693
694static const struct v4l2_subdev_core_ops isp_subdev_v4l2_core_ops = {
695 .ioctl = isp_subdev_ioctl, .s_power = isp_subdev_set_power,
696 .subscribe_event = isp_subdev_subscribe_event,
697 .unsubscribe_event = isp_subdev_unsubscribe_event,
698};
699
700
701static const struct v4l2_subdev_pad_ops isp_subdev_v4l2_pad_ops = {
702 .enum_mbus_code = isp_subdev_enum_mbus_code,
703 .get_fmt = isp_subdev_get_format,
704 .set_fmt = isp_subdev_set_format,
705 .get_selection = isp_subdev_get_selection,
706 .set_selection = isp_subdev_set_selection,
707 .link_validate = v4l2_subdev_link_validate_default,
708};
709
710
711static const struct v4l2_subdev_ops isp_subdev_v4l2_ops = {
712 .core = &isp_subdev_v4l2_core_ops,
713 .pad = &isp_subdev_v4l2_pad_ops,
714};
715
716static void isp_subdev_init_params(struct atomisp_sub_device *asd)
717{
718 unsigned int i;
719
720
721 INIT_LIST_HEAD(&asd->s3a_stats);
722 INIT_LIST_HEAD(&asd->s3a_stats_in_css);
723 INIT_LIST_HEAD(&asd->s3a_stats_ready);
724 INIT_LIST_HEAD(&asd->dis_stats);
725 INIT_LIST_HEAD(&asd->dis_stats_in_css);
726 spin_lock_init(&asd->dis_stats_lock);
727 for (i = 0; i < ATOMISP_METADATA_TYPE_NUM; i++) {
728 INIT_LIST_HEAD(&asd->metadata[i]);
729 INIT_LIST_HEAD(&asd->metadata_in_css[i]);
730 INIT_LIST_HEAD(&asd->metadata_ready[i]);
731 }
732}
733
734
735
736
737
738
739
740
741
742
743static int isp_subdev_link_setup(struct media_entity *entity,
744 const struct media_pad *local,
745 const struct media_pad *remote, u32 flags)
746{
747 struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
748 struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd);
749 struct atomisp_device *isp = isp_sd->isp;
750 unsigned int i;
751
752 switch (local->index | is_media_entity_v4l2_subdev(remote->entity)) {
753 case ATOMISP_SUBDEV_PAD_SINK | MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN:
754
755 if (!(flags & MEDIA_LNK_FL_ENABLED)) {
756 isp_sd->input = ATOMISP_SUBDEV_INPUT_NONE;
757 break;
758 }
759
760 if (isp_sd->input != ATOMISP_SUBDEV_INPUT_NONE)
761 return -EBUSY;
762
763 for (i = 0; i < ATOMISP_CAMERA_NR_PORTS; i++) {
764 if (remote->entity != &isp->csi2_port[i].subdev.entity)
765 continue;
766
767 isp_sd->input = ATOMISP_SUBDEV_INPUT_CSI2_PORT1 + i;
768 return 0;
769 }
770
771 return -EINVAL;
772
773 case ATOMISP_SUBDEV_PAD_SINK | MEDIA_ENT_F_OLD_BASE:
774
775 if (flags & MEDIA_LNK_FL_ENABLED) {
776 if (isp_sd->input >= ATOMISP_SUBDEV_INPUT_CSI2_PORT1 &&
777 isp_sd->input < (ATOMISP_SUBDEV_INPUT_CSI2_PORT1
778 + ATOMISP_CAMERA_NR_PORTS))
779 return -EBUSY;
780 isp_sd->input = ATOMISP_SUBDEV_INPUT_MEMORY;
781 } else {
782 if (isp_sd->input == ATOMISP_SUBDEV_INPUT_MEMORY)
783 isp_sd->input = ATOMISP_SUBDEV_INPUT_NONE;
784 }
785 break;
786
787 case ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW | MEDIA_ENT_F_OLD_BASE:
788
789 break;
790
791 case ATOMISP_SUBDEV_PAD_SOURCE_VF | MEDIA_ENT_F_OLD_BASE:
792
793 break;
794
795 case ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE | MEDIA_ENT_F_OLD_BASE:
796
797 break;
798
799 case ATOMISP_SUBDEV_PAD_SOURCE_VIDEO | MEDIA_ENT_F_OLD_BASE:
800
801 break;
802
803 default:
804 return -EINVAL;
805 }
806
807 return 0;
808}
809
810
811static const struct media_entity_operations isp_subdev_media_ops = {
812 .link_setup = isp_subdev_link_setup,
813 .link_validate = v4l2_subdev_link_validate,
814
815};
816
817static int __atomisp_update_run_mode(struct atomisp_sub_device *asd)
818{
819 struct atomisp_device *isp = asd->isp;
820 struct v4l2_ctrl *ctrl = asd->run_mode;
821 struct v4l2_ctrl *c;
822 s32 mode;
823
824 if (ctrl->val != ATOMISP_RUN_MODE_VIDEO &&
825 asd->continuous_mode->val)
826 mode = ATOMISP_RUN_MODE_PREVIEW;
827 else
828 mode = ctrl->val;
829
830 c = v4l2_ctrl_find(
831 isp->inputs[asd->input_curr].camera->ctrl_handler,
832 V4L2_CID_RUN_MODE);
833
834 if (c)
835 return v4l2_ctrl_s_ctrl(c, mode);
836
837 return 0;
838}
839
840int atomisp_update_run_mode(struct atomisp_sub_device *asd)
841{
842 int rval;
843
844 mutex_lock(asd->ctrl_handler.lock);
845 rval = __atomisp_update_run_mode(asd);
846 mutex_unlock(asd->ctrl_handler.lock);
847
848 return rval;
849}
850
851static int s_ctrl(struct v4l2_ctrl *ctrl)
852{
853 struct atomisp_sub_device *asd = container_of(
854 ctrl->handler, struct atomisp_sub_device, ctrl_handler);
855
856 switch (ctrl->id) {
857 case V4L2_CID_RUN_MODE:
858 return __atomisp_update_run_mode(asd);
859 case V4L2_CID_DEPTH_MODE:
860 if (asd->streaming != ATOMISP_DEVICE_STREAMING_DISABLED) {
861 dev_err(asd->isp->dev, "ISP is streaming, it is not supported to change the depth mode\n");
862 return -EINVAL;
863 }
864 break;
865 }
866
867 return 0;
868}
869
870static const struct v4l2_ctrl_ops ctrl_ops = {
871 .s_ctrl = &s_ctrl,
872};
873
874static const struct v4l2_ctrl_config ctrl_fmt_auto = {
875 .ops = &ctrl_ops,
876 .id = V4L2_CID_FMT_AUTO,
877 .name = "Automatic format guessing",
878 .type = V4L2_CTRL_TYPE_BOOLEAN,
879 .min = 0,
880 .max = 1,
881 .step = 1,
882 .def = 1,
883};
884
885static const char * const ctrl_run_mode_menu[] = {
886 NULL,
887 "Video",
888 "Still capture",
889 "Continuous capture",
890 "Preview",
891};
892
893static const struct v4l2_ctrl_config ctrl_run_mode = {
894 .ops = &ctrl_ops,
895 .id = V4L2_CID_RUN_MODE,
896 .name = "Atomisp run mode",
897 .type = V4L2_CTRL_TYPE_MENU,
898 .min = 1,
899 .def = 1,
900 .max = 4,
901 .qmenu = ctrl_run_mode_menu,
902};
903
904static const char * const ctrl_vfpp_mode_menu[] = {
905 "Enable",
906 "Disable to scaler mode",
907 "Disable to low latency mode",
908};
909
910static const struct v4l2_ctrl_config ctrl_vfpp = {
911 .id = V4L2_CID_VFPP,
912 .name = "Atomisp vf postprocess",
913 .type = V4L2_CTRL_TYPE_MENU,
914 .min = 0,
915 .def = 0,
916 .max = 2,
917 .qmenu = ctrl_vfpp_mode_menu,
918};
919
920
921
922
923
924
925
926
927static const struct v4l2_ctrl_config ctrl_continuous_mode = {
928 .ops = &ctrl_ops,
929 .id = V4L2_CID_ATOMISP_CONTINUOUS_MODE,
930 .type = V4L2_CTRL_TYPE_BOOLEAN,
931 .name = "Continuous mode",
932 .min = 0,
933 .max = 1,
934 .step = 1,
935 .def = 0,
936};
937
938
939
940
941
942
943
944
945
946
947
948
949static const struct v4l2_ctrl_config ctrl_continuous_raw_buffer_size = {
950 .ops = &ctrl_ops,
951 .id = V4L2_CID_ATOMISP_CONTINUOUS_RAW_BUFFER_SIZE,
952 .type = V4L2_CTRL_TYPE_INTEGER,
953 .name = "Continuous raw ringbuffer size",
954 .min = 1,
955 .max = 100,
956 .step = 1,
957 .def = 3,
958};
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974static const struct v4l2_ctrl_config ctrl_continuous_viewfinder = {
975 .id = V4L2_CID_ATOMISP_CONTINUOUS_VIEWFINDER,
976 .type = V4L2_CTRL_TYPE_BOOLEAN,
977 .name = "Continuous viewfinder",
978 .min = 0,
979 .max = 1,
980 .step = 1,
981 .def = 0,
982};
983
984
985
986
987
988
989
990
991
992static const struct v4l2_ctrl_config ctrl_enable_raw_buffer_lock = {
993 .id = V4L2_CID_ENABLE_RAW_BUFFER_LOCK,
994 .type = V4L2_CTRL_TYPE_BOOLEAN,
995 .name = "Lock Unlock Raw Buffer",
996 .min = 0,
997 .max = 1,
998 .step = 1,
999 .def = 0,
1000};
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010static const struct v4l2_ctrl_config ctrl_disable_dz = {
1011 .id = V4L2_CID_DISABLE_DZ,
1012 .type = V4L2_CTRL_TYPE_BOOLEAN,
1013 .name = "Disable digital zoom",
1014 .min = 0,
1015 .max = 1,
1016 .step = 1,
1017 .def = 0,
1018};
1019
1020
1021
1022
1023
1024
1025
1026
1027static const struct v4l2_ctrl_config ctrl_depth_mode = {
1028 .ops = &ctrl_ops,
1029 .id = V4L2_CID_DEPTH_MODE,
1030 .type = V4L2_CTRL_TYPE_BOOLEAN,
1031 .name = "Depth mode",
1032 .min = 0,
1033 .max = 1,
1034 .step = 1,
1035 .def = 0,
1036};
1037
1038#ifdef ISP2401
1039
1040
1041
1042
1043
1044
1045
1046static const struct v4l2_ctrl_config ctrl_select_isp_version = {
1047 .ops = &ctrl_ops,
1048 .id = V4L2_CID_ATOMISP_SELECT_ISP_VERSION,
1049 .type = V4L2_CTRL_TYPE_BOOLEAN,
1050 .name = "Select Isp version",
1051 .min = 0,
1052 .max = 1,
1053 .step = 1,
1054 .def = 0,
1055};
1056
1057#ifdef CONFIG_ION
1058
1059
1060
1061
1062
1063
1064static const struct v4l2_ctrl_config ctrl_ion_dev_fd = {
1065 .ops = &ctrl_ops,
1066 .id = V4L2_CID_ATOMISP_ION_DEVICE_FD,
1067 .type = V4L2_CTRL_TYPE_INTEGER,
1068 .name = "Ion Device Fd",
1069 .min = -1,
1070 .max = 1024,
1071 .step = 1,
1072 .def = ION_FD_UNSET
1073};
1074#endif
1075
1076#endif
1077static void atomisp_init_subdev_pipe(struct atomisp_sub_device *asd,
1078 struct atomisp_video_pipe *pipe, enum v4l2_buf_type buf_type)
1079{
1080 pipe->type = buf_type;
1081 pipe->asd = asd;
1082 pipe->isp = asd->isp;
1083 spin_lock_init(&pipe->irq_lock);
1084 INIT_LIST_HEAD(&pipe->activeq);
1085 INIT_LIST_HEAD(&pipe->activeq_out);
1086 INIT_LIST_HEAD(&pipe->buffers_waiting_for_param);
1087 INIT_LIST_HEAD(&pipe->per_frame_params);
1088 memset(pipe->frame_request_config_id,
1089 0, VIDEO_MAX_FRAME * sizeof(unsigned int));
1090 memset(pipe->frame_params,
1091 0, VIDEO_MAX_FRAME *
1092 sizeof(struct atomisp_css_params_with_list *));
1093}
1094
1095static void atomisp_init_acc_pipe(struct atomisp_sub_device *asd,
1096 struct atomisp_acc_pipe *pipe)
1097{
1098 pipe->asd = asd;
1099 pipe->isp = asd->isp;
1100 INIT_LIST_HEAD(&asd->acc.fw);
1101 INIT_LIST_HEAD(&asd->acc.memory_maps);
1102 ida_init(&asd->acc.ida);
1103}
1104
1105
1106
1107
1108
1109
1110
1111static int isp_subdev_init_entities(struct atomisp_sub_device *asd)
1112{
1113 struct v4l2_subdev *sd = &asd->subdev;
1114 struct media_pad *pads = asd->pads;
1115 struct media_entity *me = &sd->entity;
1116 int ret;
1117
1118 asd->input = ATOMISP_SUBDEV_INPUT_NONE;
1119
1120 v4l2_subdev_init(sd, &isp_subdev_v4l2_ops);
1121 sprintf(sd->name, "ATOMISP_SUBDEV_%d", asd->index);
1122 v4l2_set_subdevdata(sd, asd);
1123 sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE;
1124
1125 pads[ATOMISP_SUBDEV_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
1126 pads[ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW].flags = MEDIA_PAD_FL_SOURCE;
1127 pads[ATOMISP_SUBDEV_PAD_SOURCE_VF].flags = MEDIA_PAD_FL_SOURCE;
1128 pads[ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE].flags = MEDIA_PAD_FL_SOURCE;
1129 pads[ATOMISP_SUBDEV_PAD_SOURCE_VIDEO].flags = MEDIA_PAD_FL_SOURCE;
1130
1131 asd->fmt[ATOMISP_SUBDEV_PAD_SINK].fmt.code =
1132 MEDIA_BUS_FMT_SBGGR10_1X10;
1133 asd->fmt[ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW].fmt.code =
1134 MEDIA_BUS_FMT_SBGGR10_1X10;
1135 asd->fmt[ATOMISP_SUBDEV_PAD_SOURCE_VF].fmt.code =
1136 MEDIA_BUS_FMT_SBGGR10_1X10;
1137 asd->fmt[ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE].fmt.code =
1138 MEDIA_BUS_FMT_SBGGR10_1X10;
1139 asd->fmt[ATOMISP_SUBDEV_PAD_SOURCE_VIDEO].fmt.code =
1140 MEDIA_BUS_FMT_SBGGR10_1X10;
1141
1142 me->ops = &isp_subdev_media_ops;
1143 me->function = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN;
1144 ret = media_entity_pads_init(me, ATOMISP_SUBDEV_PADS_NUM, pads);
1145 if (ret < 0)
1146 return ret;
1147
1148 atomisp_init_subdev_pipe(asd, &asd->video_in,
1149 V4L2_BUF_TYPE_VIDEO_OUTPUT);
1150
1151 atomisp_init_subdev_pipe(asd, &asd->video_out_preview,
1152 V4L2_BUF_TYPE_VIDEO_CAPTURE);
1153
1154 atomisp_init_subdev_pipe(asd, &asd->video_out_vf,
1155 V4L2_BUF_TYPE_VIDEO_CAPTURE);
1156
1157 atomisp_init_subdev_pipe(asd, &asd->video_out_capture,
1158 V4L2_BUF_TYPE_VIDEO_CAPTURE);
1159
1160 atomisp_init_subdev_pipe(asd, &asd->video_out_video_capture,
1161 V4L2_BUF_TYPE_VIDEO_CAPTURE);
1162
1163 atomisp_init_acc_pipe(asd, &asd->video_acc);
1164
1165 ret = atomisp_video_init(&asd->video_in, "MEMORY");
1166 if (ret < 0)
1167 return ret;
1168
1169 ret = atomisp_video_init(&asd->video_out_capture, "CAPTURE");
1170 if (ret < 0)
1171 return ret;
1172
1173 ret = atomisp_video_init(&asd->video_out_vf, "VIEWFINDER");
1174 if (ret < 0)
1175 return ret;
1176
1177 ret = atomisp_video_init(&asd->video_out_preview, "PREVIEW");
1178 if (ret < 0)
1179 return ret;
1180
1181 ret = atomisp_video_init(&asd->video_out_video_capture, "VIDEO");
1182 if (ret < 0)
1183 return ret;
1184
1185 atomisp_acc_init(&asd->video_acc, "ACC");
1186
1187 ret = v4l2_ctrl_handler_init(&asd->ctrl_handler, 1);
1188 if (ret)
1189 return ret;
1190
1191 asd->fmt_auto = v4l2_ctrl_new_custom(&asd->ctrl_handler,
1192 &ctrl_fmt_auto, NULL);
1193 asd->run_mode = v4l2_ctrl_new_custom(&asd->ctrl_handler,
1194 &ctrl_run_mode, NULL);
1195 asd->vfpp = v4l2_ctrl_new_custom(&asd->ctrl_handler,
1196 &ctrl_vfpp, NULL);
1197 asd->continuous_mode = v4l2_ctrl_new_custom(&asd->ctrl_handler,
1198 &ctrl_continuous_mode, NULL);
1199 asd->continuous_viewfinder = v4l2_ctrl_new_custom(&asd->ctrl_handler,
1200 &ctrl_continuous_viewfinder,
1201 NULL);
1202 asd->continuous_raw_buffer_size =
1203 v4l2_ctrl_new_custom(&asd->ctrl_handler,
1204 &ctrl_continuous_raw_buffer_size,
1205 NULL);
1206
1207 asd->enable_raw_buffer_lock =
1208 v4l2_ctrl_new_custom(&asd->ctrl_handler,
1209 &ctrl_enable_raw_buffer_lock,
1210 NULL);
1211 asd->depth_mode =
1212 v4l2_ctrl_new_custom(&asd->ctrl_handler,
1213 &ctrl_depth_mode,
1214 NULL);
1215 asd->disable_dz =
1216 v4l2_ctrl_new_custom(&asd->ctrl_handler,
1217 &ctrl_disable_dz,
1218 NULL);
1219#ifdef ISP2401
1220 asd->select_isp_version =
1221 v4l2_ctrl_new_custom(&asd->ctrl_handler,
1222 &ctrl_select_isp_version,
1223 NULL);
1224
1225#ifdef CONFIG_ION
1226 asd->ion_dev_fd =
1227 v4l2_ctrl_new_custom(&asd->ctrl_handler,
1228 &ctrl_ion_dev_fd,
1229 NULL);
1230#endif
1231#endif
1232
1233
1234 asd->subdev.ctrl_handler = &asd->ctrl_handler;
1235 spin_lock_init(&asd->raw_buffer_bitmap_lock);
1236 return asd->ctrl_handler.error;
1237}
1238
1239int atomisp_create_pads_links(struct atomisp_device *isp)
1240{
1241 struct atomisp_sub_device *asd;
1242 int i, j, ret = 0;
1243 isp->num_of_streams = 2;
1244 for (i = 0; i < ATOMISP_CAMERA_NR_PORTS; i++) {
1245 for (j = 0; j < isp->num_of_streams; j++) {
1246 ret =
1247 media_create_pad_link(&isp->csi2_port[i].subdev.
1248 entity, CSI2_PAD_SOURCE,
1249 &isp->asd[j].subdev.entity,
1250 ATOMISP_SUBDEV_PAD_SINK, 0);
1251 if (ret < 0)
1252 return ret;
1253 }
1254 }
1255 for (i = 0; i < isp->input_cnt - 2; i++) {
1256 ret = media_create_pad_link(&isp->inputs[i].camera->entity, 0,
1257 &isp->csi2_port[isp->inputs[i].
1258 port].subdev.entity,
1259 CSI2_PAD_SINK,
1260 MEDIA_LNK_FL_ENABLED |
1261 MEDIA_LNK_FL_IMMUTABLE);
1262 if (ret < 0)
1263 return ret;
1264 }
1265 for (i = 0; i < isp->num_of_streams; i++) {
1266 asd = &isp->asd[i];
1267 ret = media_create_pad_link(&asd->subdev.entity,
1268 ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW,
1269 &asd->video_out_preview.vdev.entity,
1270 0, 0);
1271 if (ret < 0)
1272 return ret;
1273 ret = media_create_pad_link(&asd->subdev.entity,
1274 ATOMISP_SUBDEV_PAD_SOURCE_VF,
1275 &asd->video_out_vf.vdev.entity, 0,
1276 0);
1277 if (ret < 0)
1278 return ret;
1279 ret = media_create_pad_link(&asd->subdev.entity,
1280 ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE,
1281 &asd->video_out_capture.vdev.entity,
1282 0, 0);
1283 if (ret < 0)
1284 return ret;
1285 ret = media_create_pad_link(&asd->subdev.entity,
1286 ATOMISP_SUBDEV_PAD_SOURCE_VIDEO,
1287 &asd->video_out_video_capture.vdev.
1288 entity, 0, 0);
1289 if (ret < 0)
1290 return ret;
1291
1292
1293
1294
1295 if (asd->index)
1296 return 0;
1297 ret = media_create_pad_link(&asd->video_in.vdev.entity,
1298 0, &asd->subdev.entity,
1299 ATOMISP_SUBDEV_PAD_SINK, 0);
1300 if (ret < 0)
1301 return ret;
1302 }
1303 return 0;
1304}
1305
1306static void atomisp_subdev_cleanup_entities(struct atomisp_sub_device *asd)
1307{
1308 v4l2_ctrl_handler_free(&asd->ctrl_handler);
1309
1310 media_entity_cleanup(&asd->subdev.entity);
1311}
1312
1313void atomisp_subdev_cleanup_pending_events(struct atomisp_sub_device *asd)
1314{
1315 struct v4l2_fh *fh, *fh_tmp;
1316 struct v4l2_event event;
1317 unsigned int i, pending_event;
1318
1319 list_for_each_entry_safe(fh, fh_tmp,
1320 &asd->subdev.devnode->fh_list, list) {
1321 pending_event = v4l2_event_pending(fh);
1322 for (i = 0; i < pending_event; i++)
1323 v4l2_event_dequeue(fh, &event, 1);
1324 }
1325}
1326
1327void atomisp_subdev_unregister_entities(struct atomisp_sub_device *asd)
1328{
1329 atomisp_subdev_cleanup_entities(asd);
1330 v4l2_device_unregister_subdev(&asd->subdev);
1331 atomisp_video_unregister(&asd->video_in);
1332 atomisp_video_unregister(&asd->video_out_preview);
1333 atomisp_video_unregister(&asd->video_out_vf);
1334 atomisp_video_unregister(&asd->video_out_capture);
1335 atomisp_video_unregister(&asd->video_out_video_capture);
1336 atomisp_acc_unregister(&asd->video_acc);
1337}
1338
1339int atomisp_subdev_register_entities(struct atomisp_sub_device *asd,
1340 struct v4l2_device *vdev)
1341{
1342 int ret;
1343
1344
1345 ret = v4l2_device_register_subdev(vdev, &asd->subdev);
1346 if (ret < 0)
1347 goto error;
1348
1349 ret = atomisp_video_register(&asd->video_out_capture, vdev);
1350 if (ret < 0)
1351 goto error;
1352
1353 ret = atomisp_video_register(&asd->video_out_vf, vdev);
1354 if (ret < 0)
1355 goto error;
1356
1357 ret = atomisp_video_register(&asd->video_out_preview, vdev);
1358 if (ret < 0)
1359 goto error;
1360
1361 ret = atomisp_video_register(&asd->video_out_video_capture, vdev);
1362 if (ret < 0)
1363 goto error;
1364
1365 ret = atomisp_acc_register(&asd->video_acc, vdev);
1366 if (ret < 0)
1367 goto error;
1368
1369
1370
1371
1372
1373 if (asd->index)
1374 return 0;
1375 ret = atomisp_video_register(&asd->video_in, vdev);
1376 if (ret < 0)
1377 goto error;
1378
1379 return 0;
1380
1381error:
1382 atomisp_subdev_unregister_entities(asd);
1383 return ret;
1384}
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394int atomisp_subdev_init(struct atomisp_device *isp)
1395{
1396 struct atomisp_sub_device *asd;
1397 int i, ret = 0;
1398
1399
1400
1401
1402
1403 isp->num_of_streams = 2;
1404 isp->asd = devm_kzalloc(isp->dev, sizeof(struct atomisp_sub_device) *
1405 isp->num_of_streams, GFP_KERNEL);
1406 if (!isp->asd)
1407 return -ENOMEM;
1408 for (i = 0; i < isp->num_of_streams; i++) {
1409 asd = &isp->asd[i];
1410 spin_lock_init(&asd->lock);
1411 asd->isp = isp;
1412 isp_subdev_init_params(asd);
1413 asd->index = i;
1414 ret = isp_subdev_init_entities(asd);
1415 if (ret < 0) {
1416 atomisp_subdev_cleanup_entities(asd);
1417 break;
1418 }
1419 }
1420
1421 return ret;
1422}
1423