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