| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Copyright (c) 2011 Atmel Corporation |
|---|
| 3 | 4 | * Josh Wu, <josh.wu@atmel.com> |
|---|
| .. | .. |
|---|
| 5 | 6 | * Based on previous work by Lars Haring, <lars.haring@atmel.com> |
|---|
| 6 | 7 | * and Sedji Gaouaou |
|---|
| 7 | 8 | * Based on the bttv driver for Bt848 with respective copyright holders |
|---|
| 8 | | - * |
|---|
| 9 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 10 | | - * it under the terms of the GNU General Public License version 2 as |
|---|
| 11 | | - * published by the Free Software Foundation. |
|---|
| 12 | 9 | */ |
|---|
| 13 | 10 | |
|---|
| 14 | 11 | #include <linux/clk.h> |
|---|
| .. | .. |
|---|
| 110 | 107 | bool enable_preview_path; |
|---|
| 111 | 108 | |
|---|
| 112 | 109 | struct completion complete; |
|---|
| 113 | | - /* ISI peripherial clock */ |
|---|
| 110 | + /* ISI peripheral clock */ |
|---|
| 114 | 111 | struct clk *pclk; |
|---|
| 115 | 112 | unsigned int irq; |
|---|
| 116 | 113 | |
|---|
| .. | .. |
|---|
| 151 | 148 | u32 fourcc = isi->current_fmt->fourcc; |
|---|
| 152 | 149 | |
|---|
| 153 | 150 | isi->enable_preview_path = fourcc == V4L2_PIX_FMT_RGB565 || |
|---|
| 154 | | - fourcc == V4L2_PIX_FMT_RGB32; |
|---|
| 151 | + fourcc == V4L2_PIX_FMT_RGB32 || |
|---|
| 152 | + fourcc == V4L2_PIX_FMT_Y16; |
|---|
| 155 | 153 | |
|---|
| 156 | 154 | /* According to sensor's output format to set cfg2 */ |
|---|
| 157 | 155 | cfg2 = isi->current_fmt->swap; |
|---|
| .. | .. |
|---|
| 557 | 555 | return NULL; |
|---|
| 558 | 556 | } |
|---|
| 559 | 557 | |
|---|
| 558 | +static void isi_try_fse(struct atmel_isi *isi, const struct isi_format *isi_fmt, |
|---|
| 559 | + struct v4l2_subdev_pad_config *pad_cfg) |
|---|
| 560 | +{ |
|---|
| 561 | + int ret; |
|---|
| 562 | + struct v4l2_subdev_frame_size_enum fse = { |
|---|
| 563 | + .code = isi_fmt->mbus_code, |
|---|
| 564 | + .which = V4L2_SUBDEV_FORMAT_TRY, |
|---|
| 565 | + }; |
|---|
| 566 | + |
|---|
| 567 | + ret = v4l2_subdev_call(isi->entity.subdev, pad, enum_frame_size, |
|---|
| 568 | + pad_cfg, &fse); |
|---|
| 569 | + /* |
|---|
| 570 | + * Attempt to obtain format size from subdev. If not available, |
|---|
| 571 | + * just use the maximum ISI can receive. |
|---|
| 572 | + */ |
|---|
| 573 | + if (ret) { |
|---|
| 574 | + pad_cfg->try_crop.width = MAX_SUPPORT_WIDTH; |
|---|
| 575 | + pad_cfg->try_crop.height = MAX_SUPPORT_HEIGHT; |
|---|
| 576 | + } else { |
|---|
| 577 | + pad_cfg->try_crop.width = fse.max_width; |
|---|
| 578 | + pad_cfg->try_crop.height = fse.max_height; |
|---|
| 579 | + } |
|---|
| 580 | +} |
|---|
| 581 | + |
|---|
| 560 | 582 | static int isi_try_fmt(struct atmel_isi *isi, struct v4l2_format *f, |
|---|
| 561 | 583 | const struct isi_format **current_fmt) |
|---|
| 562 | 584 | { |
|---|
| 563 | 585 | const struct isi_format *isi_fmt; |
|---|
| 564 | 586 | struct v4l2_pix_format *pixfmt = &f->fmt.pix; |
|---|
| 565 | | - struct v4l2_subdev_pad_config pad_cfg; |
|---|
| 587 | + struct v4l2_subdev_pad_config pad_cfg = {}; |
|---|
| 566 | 588 | struct v4l2_subdev_format format = { |
|---|
| 567 | 589 | .which = V4L2_SUBDEV_FORMAT_TRY, |
|---|
| 568 | 590 | }; |
|---|
| .. | .. |
|---|
| 579 | 601 | pixfmt->height = clamp(pixfmt->height, 0U, MAX_SUPPORT_HEIGHT); |
|---|
| 580 | 602 | |
|---|
| 581 | 603 | v4l2_fill_mbus_format(&format.format, pixfmt, isi_fmt->mbus_code); |
|---|
| 604 | + |
|---|
| 605 | + isi_try_fse(isi, isi_fmt, &pad_cfg); |
|---|
| 606 | + |
|---|
| 582 | 607 | ret = v4l2_subdev_call(isi->entity.subdev, pad, set_fmt, |
|---|
| 583 | 608 | &pad_cfg, &format); |
|---|
| 584 | 609 | if (ret < 0) |
|---|
| .. | .. |
|---|
| 655 | 680 | static int isi_querycap(struct file *file, void *priv, |
|---|
| 656 | 681 | struct v4l2_capability *cap) |
|---|
| 657 | 682 | { |
|---|
| 658 | | - strlcpy(cap->driver, "atmel-isi", sizeof(cap->driver)); |
|---|
| 659 | | - strlcpy(cap->card, "Atmel Image Sensor Interface", sizeof(cap->card)); |
|---|
| 660 | | - strlcpy(cap->bus_info, "platform:isi", sizeof(cap->bus_info)); |
|---|
| 683 | + strscpy(cap->driver, "atmel-isi", sizeof(cap->driver)); |
|---|
| 684 | + strscpy(cap->card, "Atmel Image Sensor Interface", sizeof(cap->card)); |
|---|
| 685 | + strscpy(cap->bus_info, "platform:isi", sizeof(cap->bus_info)); |
|---|
| 661 | 686 | return 0; |
|---|
| 662 | 687 | } |
|---|
| 663 | 688 | |
|---|
| .. | .. |
|---|
| 668 | 693 | return -EINVAL; |
|---|
| 669 | 694 | |
|---|
| 670 | 695 | i->type = V4L2_INPUT_TYPE_CAMERA; |
|---|
| 671 | | - strlcpy(i->name, "Camera", sizeof(i->name)); |
|---|
| 696 | + strscpy(i->name, "Camera", sizeof(i->name)); |
|---|
| 672 | 697 | return 0; |
|---|
| 673 | 698 | } |
|---|
| 674 | 699 | |
|---|
| .. | .. |
|---|
| 790 | 815 | struct platform_device *pdev) |
|---|
| 791 | 816 | { |
|---|
| 792 | 817 | struct device_node *np = pdev->dev.of_node; |
|---|
| 793 | | - struct v4l2_fwnode_endpoint ep; |
|---|
| 818 | + struct v4l2_fwnode_endpoint ep = { .bus_type = 0 }; |
|---|
| 794 | 819 | int err; |
|---|
| 795 | 820 | |
|---|
| 796 | 821 | /* Default settings for ISI */ |
|---|
| .. | .. |
|---|
| 993 | 1018 | .mbus_code = MEDIA_BUS_FMT_VYUY8_2X8, |
|---|
| 994 | 1019 | .bpp = 2, |
|---|
| 995 | 1020 | .swap = ISI_CFG2_YCC_SWAP_MODE_1, |
|---|
| 1021 | + }, { |
|---|
| 1022 | + .fourcc = V4L2_PIX_FMT_GREY, |
|---|
| 1023 | + .mbus_code = MEDIA_BUS_FMT_Y10_1X10, |
|---|
| 1024 | + .bpp = 1, |
|---|
| 1025 | + .swap = ISI_CFG2_GS_MODE_2_PIXEL | ISI_CFG2_GRAYSCALE, |
|---|
| 1026 | + }, { |
|---|
| 1027 | + .fourcc = V4L2_PIX_FMT_Y16, |
|---|
| 1028 | + .mbus_code = MEDIA_BUS_FMT_Y10_1X10, |
|---|
| 1029 | + .bpp = 2, |
|---|
| 1030 | + .swap = ISI_CFG2_GS_MODE_2_PIXEL | ISI_CFG2_GRAYSCALE, |
|---|
| 996 | 1031 | }, |
|---|
| 997 | 1032 | }; |
|---|
| 998 | 1033 | |
|---|
| .. | .. |
|---|
| 1059 | 1094 | return ret; |
|---|
| 1060 | 1095 | } |
|---|
| 1061 | 1096 | |
|---|
| 1062 | | - ret = video_register_device(isi->vdev, VFL_TYPE_GRABBER, -1); |
|---|
| 1097 | + ret = video_register_device(isi->vdev, VFL_TYPE_VIDEO, -1); |
|---|
| 1063 | 1098 | if (ret) { |
|---|
| 1064 | 1099 | dev_err(isi->dev, "Failed to register video device\n"); |
|---|
| 1065 | 1100 | return ret; |
|---|
| .. | .. |
|---|
| 1078 | 1113 | |
|---|
| 1079 | 1114 | dev_dbg(isi->dev, "Removing %s\n", video_device_node_name(isi->vdev)); |
|---|
| 1080 | 1115 | |
|---|
| 1081 | | - /* Checks internaly if vdev have been init or not */ |
|---|
| 1116 | + /* Checks internally if vdev have been init or not */ |
|---|
| 1082 | 1117 | video_unregister_device(isi->vdev); |
|---|
| 1083 | 1118 | } |
|---|
| 1084 | 1119 | |
|---|
| .. | .. |
|---|
| 1124 | 1159 | |
|---|
| 1125 | 1160 | static int isi_graph_init(struct atmel_isi *isi) |
|---|
| 1126 | 1161 | { |
|---|
| 1127 | | - struct v4l2_async_subdev **subdevs = NULL; |
|---|
| 1128 | 1162 | int ret; |
|---|
| 1129 | 1163 | |
|---|
| 1130 | 1164 | /* Parse the graph to extract a list of subdevice DT nodes. */ |
|---|
| .. | .. |
|---|
| 1134 | 1168 | return ret; |
|---|
| 1135 | 1169 | } |
|---|
| 1136 | 1170 | |
|---|
| 1137 | | - /* Register the subdevices notifier. */ |
|---|
| 1138 | | - subdevs = devm_kzalloc(isi->dev, sizeof(*subdevs), GFP_KERNEL); |
|---|
| 1139 | | - if (!subdevs) { |
|---|
| 1171 | + v4l2_async_notifier_init(&isi->notifier); |
|---|
| 1172 | + |
|---|
| 1173 | + ret = v4l2_async_notifier_add_subdev(&isi->notifier, &isi->entity.asd); |
|---|
| 1174 | + if (ret) { |
|---|
| 1140 | 1175 | of_node_put(isi->entity.node); |
|---|
| 1141 | | - return -ENOMEM; |
|---|
| 1176 | + return ret; |
|---|
| 1142 | 1177 | } |
|---|
| 1143 | 1178 | |
|---|
| 1144 | | - subdevs[0] = &isi->entity.asd; |
|---|
| 1145 | | - |
|---|
| 1146 | | - isi->notifier.subdevs = subdevs; |
|---|
| 1147 | | - isi->notifier.num_subdevs = 1; |
|---|
| 1148 | 1179 | isi->notifier.ops = &isi_graph_notify_ops; |
|---|
| 1149 | 1180 | |
|---|
| 1150 | 1181 | ret = v4l2_async_notifier_register(&isi->v4l2_dev, &isi->notifier); |
|---|
| 1151 | 1182 | if (ret < 0) { |
|---|
| 1152 | 1183 | dev_err(isi->dev, "Notifier registration failed\n"); |
|---|
| 1153 | | - of_node_put(isi->entity.node); |
|---|
| 1184 | + v4l2_async_notifier_cleanup(&isi->notifier); |
|---|
| 1154 | 1185 | return ret; |
|---|
| 1155 | 1186 | } |
|---|
| 1156 | 1187 | |
|---|
| .. | .. |
|---|
| 1202 | 1233 | isi->vdev->fops = &isi_fops; |
|---|
| 1203 | 1234 | isi->vdev->v4l2_dev = &isi->v4l2_dev; |
|---|
| 1204 | 1235 | isi->vdev->queue = &isi->queue; |
|---|
| 1205 | | - strlcpy(isi->vdev->name, KBUILD_MODNAME, sizeof(isi->vdev->name)); |
|---|
| 1236 | + strscpy(isi->vdev->name, KBUILD_MODNAME, sizeof(isi->vdev->name)); |
|---|
| 1206 | 1237 | isi->vdev->release = video_device_release; |
|---|
| 1207 | 1238 | isi->vdev->ioctl_ops = &isi_ioctl_ops; |
|---|
| 1208 | 1239 | isi->vdev->lock = &isi->lock; |
|---|
| .. | .. |
|---|
| 1303 | 1334 | isi->fb_descriptors_phys); |
|---|
| 1304 | 1335 | pm_runtime_disable(&pdev->dev); |
|---|
| 1305 | 1336 | v4l2_async_notifier_unregister(&isi->notifier); |
|---|
| 1337 | + v4l2_async_notifier_cleanup(&isi->notifier); |
|---|
| 1306 | 1338 | v4l2_device_unregister(&isi->v4l2_dev); |
|---|
| 1307 | 1339 | |
|---|
| 1308 | 1340 | return 0; |
|---|