| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Samsung EXYNOS FIMC-LITE (camera host interface) driver |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (C) 2012 - 2013 Samsung Electronics Co., Ltd. |
|---|
| 5 | 6 | * Author: Sylwester Nawrocki <s.nawrocki@samsung.com> |
|---|
| 6 | | - * |
|---|
| 7 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 8 | | - * it under the terms of the GNU General Public License version 2 as |
|---|
| 9 | | - * published by the Free Software Foundation. |
|---|
| 10 | 7 | */ |
|---|
| 11 | 8 | #define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__ |
|---|
| 12 | 9 | |
|---|
| .. | .. |
|---|
| 28 | 25 | #include <media/v4l2-device.h> |
|---|
| 29 | 26 | #include <media/v4l2-ioctl.h> |
|---|
| 30 | 27 | #include <media/v4l2-mem2mem.h> |
|---|
| 28 | +#include <media/v4l2-rect.h> |
|---|
| 31 | 29 | #include <media/videobuf2-v4l2.h> |
|---|
| 32 | 30 | #include <media/videobuf2-dma-contig.h> |
|---|
| 33 | 31 | #include <media/drv-intf/exynos-fimc.h> |
|---|
| .. | .. |
|---|
| 42 | 40 | |
|---|
| 43 | 41 | static const struct fimc_fmt fimc_lite_formats[] = { |
|---|
| 44 | 42 | { |
|---|
| 45 | | - .name = "YUV 4:2:2 packed, YCbYCr", |
|---|
| 46 | 43 | .fourcc = V4L2_PIX_FMT_YUYV, |
|---|
| 47 | 44 | .colorspace = V4L2_COLORSPACE_JPEG, |
|---|
| 48 | 45 | .depth = { 16 }, |
|---|
| .. | .. |
|---|
| 51 | 48 | .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, |
|---|
| 52 | 49 | .flags = FMT_FLAGS_YUV, |
|---|
| 53 | 50 | }, { |
|---|
| 54 | | - .name = "YUV 4:2:2 packed, CbYCrY", |
|---|
| 55 | 51 | .fourcc = V4L2_PIX_FMT_UYVY, |
|---|
| 56 | 52 | .colorspace = V4L2_COLORSPACE_JPEG, |
|---|
| 57 | 53 | .depth = { 16 }, |
|---|
| .. | .. |
|---|
| 60 | 56 | .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8, |
|---|
| 61 | 57 | .flags = FMT_FLAGS_YUV, |
|---|
| 62 | 58 | }, { |
|---|
| 63 | | - .name = "YUV 4:2:2 packed, CrYCbY", |
|---|
| 64 | 59 | .fourcc = V4L2_PIX_FMT_VYUY, |
|---|
| 65 | 60 | .colorspace = V4L2_COLORSPACE_JPEG, |
|---|
| 66 | 61 | .depth = { 16 }, |
|---|
| .. | .. |
|---|
| 69 | 64 | .mbus_code = MEDIA_BUS_FMT_VYUY8_2X8, |
|---|
| 70 | 65 | .flags = FMT_FLAGS_YUV, |
|---|
| 71 | 66 | }, { |
|---|
| 72 | | - .name = "YUV 4:2:2 packed, YCrYCb", |
|---|
| 73 | 67 | .fourcc = V4L2_PIX_FMT_YVYU, |
|---|
| 74 | 68 | .colorspace = V4L2_COLORSPACE_JPEG, |
|---|
| 75 | 69 | .depth = { 16 }, |
|---|
| .. | .. |
|---|
| 78 | 72 | .mbus_code = MEDIA_BUS_FMT_YVYU8_2X8, |
|---|
| 79 | 73 | .flags = FMT_FLAGS_YUV, |
|---|
| 80 | 74 | }, { |
|---|
| 81 | | - .name = "RAW8 (GRBG)", |
|---|
| 82 | 75 | .fourcc = V4L2_PIX_FMT_SGRBG8, |
|---|
| 83 | 76 | .colorspace = V4L2_COLORSPACE_SRGB, |
|---|
| 84 | 77 | .depth = { 8 }, |
|---|
| .. | .. |
|---|
| 87 | 80 | .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8, |
|---|
| 88 | 81 | .flags = FMT_FLAGS_RAW_BAYER, |
|---|
| 89 | 82 | }, { |
|---|
| 90 | | - .name = "RAW10 (GRBG)", |
|---|
| 91 | 83 | .fourcc = V4L2_PIX_FMT_SGRBG10, |
|---|
| 92 | 84 | .colorspace = V4L2_COLORSPACE_SRGB, |
|---|
| 93 | 85 | .depth = { 16 }, |
|---|
| .. | .. |
|---|
| 96 | 88 | .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, |
|---|
| 97 | 89 | .flags = FMT_FLAGS_RAW_BAYER, |
|---|
| 98 | 90 | }, { |
|---|
| 99 | | - .name = "RAW12 (GRBG)", |
|---|
| 100 | 91 | .fourcc = V4L2_PIX_FMT_SGRBG12, |
|---|
| 101 | 92 | .colorspace = V4L2_COLORSPACE_SRGB, |
|---|
| 102 | 93 | .depth = { 16 }, |
|---|
| .. | .. |
|---|
| 478 | 469 | } |
|---|
| 479 | 470 | |
|---|
| 480 | 471 | set_bit(ST_FLITE_IN_USE, &fimc->state); |
|---|
| 481 | | - ret = pm_runtime_get_sync(&fimc->pdev->dev); |
|---|
| 472 | + ret = pm_runtime_resume_and_get(&fimc->pdev->dev); |
|---|
| 482 | 473 | if (ret < 0) |
|---|
| 483 | | - goto err_pm; |
|---|
| 474 | + goto err_in_use; |
|---|
| 484 | 475 | |
|---|
| 485 | 476 | ret = v4l2_fh_open(file); |
|---|
| 486 | 477 | if (ret < 0) |
|---|
| .. | .. |
|---|
| 508 | 499 | v4l2_fh_release(file); |
|---|
| 509 | 500 | err_pm: |
|---|
| 510 | 501 | pm_runtime_put_sync(&fimc->pdev->dev); |
|---|
| 502 | +err_in_use: |
|---|
| 511 | 503 | clear_bit(ST_FLITE_IN_USE, &fimc->state); |
|---|
| 512 | 504 | unlock: |
|---|
| 513 | 505 | mutex_unlock(&fimc->lock); |
|---|
| .. | .. |
|---|
| 654 | 646 | { |
|---|
| 655 | 647 | struct fimc_lite *fimc = video_drvdata(file); |
|---|
| 656 | 648 | |
|---|
| 657 | | - strlcpy(cap->driver, FIMC_LITE_DRV_NAME, sizeof(cap->driver)); |
|---|
| 658 | | - strlcpy(cap->card, FIMC_LITE_DRV_NAME, sizeof(cap->card)); |
|---|
| 649 | + strscpy(cap->driver, FIMC_LITE_DRV_NAME, sizeof(cap->driver)); |
|---|
| 650 | + strscpy(cap->card, FIMC_LITE_DRV_NAME, sizeof(cap->card)); |
|---|
| 659 | 651 | snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", |
|---|
| 660 | 652 | dev_name(&fimc->pdev->dev)); |
|---|
| 661 | | - |
|---|
| 662 | | - cap->device_caps = V4L2_CAP_STREAMING; |
|---|
| 663 | | - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; |
|---|
| 664 | 653 | return 0; |
|---|
| 665 | 654 | } |
|---|
| 666 | 655 | |
|---|
| 667 | | -static int fimc_lite_enum_fmt_mplane(struct file *file, void *priv, |
|---|
| 668 | | - struct v4l2_fmtdesc *f) |
|---|
| 656 | +static int fimc_lite_enum_fmt(struct file *file, void *priv, |
|---|
| 657 | + struct v4l2_fmtdesc *f) |
|---|
| 669 | 658 | { |
|---|
| 670 | 659 | const struct fimc_fmt *fmt; |
|---|
| 671 | 660 | |
|---|
| .. | .. |
|---|
| 673 | 662 | return -EINVAL; |
|---|
| 674 | 663 | |
|---|
| 675 | 664 | fmt = &fimc_lite_formats[f->index]; |
|---|
| 676 | | - strlcpy(f->description, fmt->name, sizeof(f->description)); |
|---|
| 677 | 665 | f->pixelformat = fmt->fourcc; |
|---|
| 678 | 666 | |
|---|
| 679 | 667 | return 0; |
|---|
| .. | .. |
|---|
| 882 | 870 | return ret; |
|---|
| 883 | 871 | } |
|---|
| 884 | 872 | |
|---|
| 885 | | -/* Return 1 if rectangle a is enclosed in rectangle b, or 0 otherwise. */ |
|---|
| 886 | | -static int enclosed_rectangle(struct v4l2_rect *a, struct v4l2_rect *b) |
|---|
| 887 | | -{ |
|---|
| 888 | | - if (a->left < b->left || a->top < b->top) |
|---|
| 889 | | - return 0; |
|---|
| 890 | | - if (a->left + a->width > b->left + b->width) |
|---|
| 891 | | - return 0; |
|---|
| 892 | | - if (a->top + a->height > b->top + b->height) |
|---|
| 893 | | - return 0; |
|---|
| 894 | | - |
|---|
| 895 | | - return 1; |
|---|
| 896 | | -} |
|---|
| 897 | | - |
|---|
| 898 | 873 | static int fimc_lite_g_selection(struct file *file, void *fh, |
|---|
| 899 | 874 | struct v4l2_selection *sel) |
|---|
| 900 | 875 | { |
|---|
| .. | .. |
|---|
| 936 | 911 | fimc_lite_try_compose(fimc, &rect); |
|---|
| 937 | 912 | |
|---|
| 938 | 913 | if ((sel->flags & V4L2_SEL_FLAG_LE) && |
|---|
| 939 | | - !enclosed_rectangle(&rect, &sel->r)) |
|---|
| 914 | + !v4l2_rect_enclosed(&rect, &sel->r)) |
|---|
| 940 | 915 | return -ERANGE; |
|---|
| 941 | 916 | |
|---|
| 942 | 917 | if ((sel->flags & V4L2_SEL_FLAG_GE) && |
|---|
| 943 | | - !enclosed_rectangle(&sel->r, &rect)) |
|---|
| 918 | + !v4l2_rect_enclosed(&sel->r, &rect)) |
|---|
| 944 | 919 | return -ERANGE; |
|---|
| 945 | 920 | |
|---|
| 946 | 921 | sel->r = rect; |
|---|
| .. | .. |
|---|
| 954 | 929 | |
|---|
| 955 | 930 | static const struct v4l2_ioctl_ops fimc_lite_ioctl_ops = { |
|---|
| 956 | 931 | .vidioc_querycap = fimc_lite_querycap, |
|---|
| 957 | | - .vidioc_enum_fmt_vid_cap_mplane = fimc_lite_enum_fmt_mplane, |
|---|
| 932 | + .vidioc_enum_fmt_vid_cap = fimc_lite_enum_fmt, |
|---|
| 958 | 933 | .vidioc_try_fmt_vid_cap_mplane = fimc_lite_try_fmt_mplane, |
|---|
| 959 | 934 | .vidioc_s_fmt_vid_cap_mplane = fimc_lite_s_fmt_mplane, |
|---|
| 960 | 935 | .vidioc_g_fmt_vid_cap_mplane = fimc_lite_g_fmt_mplane, |
|---|
| .. | .. |
|---|
| 1282 | 1257 | vfd->minor = -1; |
|---|
| 1283 | 1258 | vfd->release = video_device_release_empty; |
|---|
| 1284 | 1259 | vfd->queue = q; |
|---|
| 1260 | + vfd->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_STREAMING; |
|---|
| 1285 | 1261 | fimc->reqbufs_count = 0; |
|---|
| 1286 | 1262 | |
|---|
| 1287 | 1263 | INIT_LIST_HEAD(&fimc->pending_buf_q); |
|---|
| .. | .. |
|---|
| 1310 | 1286 | video_set_drvdata(vfd, fimc); |
|---|
| 1311 | 1287 | fimc->ve.pipe = v4l2_get_subdev_hostdata(sd); |
|---|
| 1312 | 1288 | |
|---|
| 1313 | | - ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1); |
|---|
| 1289 | + ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1); |
|---|
| 1314 | 1290 | if (ret < 0) { |
|---|
| 1315 | 1291 | media_entity_cleanup(&vfd->entity); |
|---|
| 1316 | 1292 | fimc->ve.pipe = NULL; |
|---|
| .. | .. |
|---|
| 1627 | 1603 | struct fimc_lite *fimc = platform_get_drvdata(pdev); |
|---|
| 1628 | 1604 | struct device *dev = &pdev->dev; |
|---|
| 1629 | 1605 | |
|---|
| 1606 | + if (!pm_runtime_enabled(dev)) |
|---|
| 1607 | + clk_disable_unprepare(fimc->clock); |
|---|
| 1608 | + |
|---|
| 1630 | 1609 | pm_runtime_disable(dev); |
|---|
| 1631 | 1610 | pm_runtime_set_suspended(dev); |
|---|
| 1632 | 1611 | fimc_lite_unregister_capture_subdev(fimc); |
|---|