1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * camss-video.c 4 * 5 * Qualcomm MSM Camera Subsystem - V4L2 device node 6 * 7 * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. 8 * Copyright (C) 2015-2018 Linaro Ltd. 9 */ 10 #include <linux/slab.h> 11 #include <media/media-entity.h> 12 #include <media/v4l2-dev.h> 13 #include <media/v4l2-device.h> 14 #include <media/v4l2-ioctl.h> 15 #include <media/v4l2-mc.h> 16 #include <media/videobuf2-dma-sg.h> 17 18 #include "camss-video.h" 19 #include "camss.h" 20 21 #define CAMSS_FRAME_MIN_WIDTH 1 22 #define CAMSS_FRAME_MAX_WIDTH 8191 23 #define CAMSS_FRAME_MIN_HEIGHT 1 24 #define CAMSS_FRAME_MAX_HEIGHT_RDI 8191 25 #define CAMSS_FRAME_MAX_HEIGHT_PIX 4096 26 27 struct fract { 28 u8 numerator; 29 u8 denominator; 30 }; 31 32 /* 33 * struct camss_format_info - ISP media bus format information 34 * @code: V4L2 media bus format code 35 * @pixelformat: V4L2 pixel format FCC identifier 36 * @planes: Number of planes 37 * @hsub: Horizontal subsampling (for each plane) 38 * @vsub: Vertical subsampling (for each plane) 39 * @bpp: Bits per pixel when stored in memory (for each plane) 40 */ 41 struct camss_format_info { 42 u32 code; 43 u32 pixelformat; 44 u8 planes; 45 struct fract hsub[3]; 46 struct fract vsub[3]; 47 unsigned int bpp[3]; 48 }; 49 50 static const struct camss_format_info formats_rdi_8x16[] = { 51 { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_UYVY, 1, 52 { { 1, 1 } }, { { 1, 1 } }, { 16 } }, 53 { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_VYUY, 1, 54 { { 1, 1 } }, { { 1, 1 } }, { 16 } }, 55 { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_YUYV, 1, 56 { { 1, 1 } }, { { 1, 1 } }, { 16 } }, 57 { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_YVYU, 1, 58 { { 1, 1 } }, { { 1, 1 } }, { 16 } }, 59 { MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_PIX_FMT_SBGGR8, 1, 60 { { 1, 1 } }, { { 1, 1 } }, { 8 } }, 61 { MEDIA_BUS_FMT_SGBRG8_1X8, V4L2_PIX_FMT_SGBRG8, 1, 62 { { 1, 1 } }, { { 1, 1 } }, { 8 } }, 63 { MEDIA_BUS_FMT_SGRBG8_1X8, V4L2_PIX_FMT_SGRBG8, 1, 64 { { 1, 1 } }, { { 1, 1 } }, { 8 } }, 65 { MEDIA_BUS_FMT_SRGGB8_1X8, V4L2_PIX_FMT_SRGGB8, 1, 66 { { 1, 1 } }, { { 1, 1 } }, { 8 } }, 67 { MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_PIX_FMT_SBGGR10P, 1, 68 { { 1, 1 } }, { { 1, 1 } }, { 10 } }, 69 { MEDIA_BUS_FMT_SGBRG10_1X10, V4L2_PIX_FMT_SGBRG10P, 1, 70 { { 1, 1 } }, { { 1, 1 } }, { 10 } }, 71 { MEDIA_BUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10P, 1, 72 { { 1, 1 } }, { { 1, 1 } }, { 10 } }, 73 { MEDIA_BUS_FMT_SRGGB10_1X10, V4L2_PIX_FMT_SRGGB10P, 1, 74 { { 1, 1 } }, { { 1, 1 } }, { 10 } }, 75 { MEDIA_BUS_FMT_SBGGR12_1X12, V4L2_PIX_FMT_SBGGR12P, 1, 76 { { 1, 1 } }, { { 1, 1 } }, { 12 } }, 77 { MEDIA_BUS_FMT_SGBRG12_1X12, V4L2_PIX_FMT_SGBRG12P, 1, 78 { { 1, 1 } }, { { 1, 1 } }, { 12 } }, 79 { MEDIA_BUS_FMT_SGRBG12_1X12, V4L2_PIX_FMT_SGRBG12P, 1, 80 { { 1, 1 } }, { { 1, 1 } }, { 12 } }, 81 { MEDIA_BUS_FMT_SRGGB12_1X12, V4L2_PIX_FMT_SRGGB12P, 1, 82 { { 1, 1 } }, { { 1, 1 } }, { 12 } }, 83 { MEDIA_BUS_FMT_Y10_1X10, V4L2_PIX_FMT_Y10P, 1, 84 { { 1, 1 } }, { { 1, 1 } }, { 10 } }, 85 }; 86 87 static const struct camss_format_info formats_rdi_8x96[] = { 88 { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_UYVY, 1, 89 { { 1, 1 } }, { { 1, 1 } }, { 16 } }, 90 { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_VYUY, 1, 91 { { 1, 1 } }, { { 1, 1 } }, { 16 } }, 92 { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_YUYV, 1, 93 { { 1, 1 } }, { { 1, 1 } }, { 16 } }, 94 { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_YVYU, 1, 95 { { 1, 1 } }, { { 1, 1 } }, { 16 } }, 96 { MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_PIX_FMT_SBGGR8, 1, 97 { { 1, 1 } }, { { 1, 1 } }, { 8 } }, 98 { MEDIA_BUS_FMT_SGBRG8_1X8, V4L2_PIX_FMT_SGBRG8, 1, 99 { { 1, 1 } }, { { 1, 1 } }, { 8 } }, 100 { MEDIA_BUS_FMT_SGRBG8_1X8, V4L2_PIX_FMT_SGRBG8, 1, 101 { { 1, 1 } }, { { 1, 1 } }, { 8 } }, 102 { MEDIA_BUS_FMT_SRGGB8_1X8, V4L2_PIX_FMT_SRGGB8, 1, 103 { { 1, 1 } }, { { 1, 1 } }, { 8 } }, 104 { MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_PIX_FMT_SBGGR10P, 1, 105 { { 1, 1 } }, { { 1, 1 } }, { 10 } }, 106 { MEDIA_BUS_FMT_SGBRG10_1X10, V4L2_PIX_FMT_SGBRG10P, 1, 107 { { 1, 1 } }, { { 1, 1 } }, { 10 } }, 108 { MEDIA_BUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10P, 1, 109 { { 1, 1 } }, { { 1, 1 } }, { 10 } }, 110 { MEDIA_BUS_FMT_SRGGB10_1X10, V4L2_PIX_FMT_SRGGB10P, 1, 111 { { 1, 1 } }, { { 1, 1 } }, { 10 } }, 112 { MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_PIX_FMT_SBGGR10, 1, 113 { { 1, 1 } }, { { 1, 1 } }, { 16 } }, 114 { MEDIA_BUS_FMT_SBGGR12_1X12, V4L2_PIX_FMT_SBGGR12P, 1, 115 { { 1, 1 } }, { { 1, 1 } }, { 12 } }, 116 { MEDIA_BUS_FMT_SGBRG12_1X12, V4L2_PIX_FMT_SGBRG12P, 1, 117 { { 1, 1 } }, { { 1, 1 } }, { 12 } }, 118 { MEDIA_BUS_FMT_SGRBG12_1X12, V4L2_PIX_FMT_SGRBG12P, 1, 119 { { 1, 1 } }, { { 1, 1 } }, { 12 } }, 120 { MEDIA_BUS_FMT_SRGGB12_1X12, V4L2_PIX_FMT_SRGGB12P, 1, 121 { { 1, 1 } }, { { 1, 1 } }, { 12 } }, 122 { MEDIA_BUS_FMT_SBGGR14_1X14, V4L2_PIX_FMT_SBGGR14P, 1, 123 { { 1, 1 } }, { { 1, 1 } }, { 14 } }, 124 { MEDIA_BUS_FMT_SGBRG14_1X14, V4L2_PIX_FMT_SGBRG14P, 1, 125 { { 1, 1 } }, { { 1, 1 } }, { 14 } }, 126 { MEDIA_BUS_FMT_SGRBG14_1X14, V4L2_PIX_FMT_SGRBG14P, 1, 127 { { 1, 1 } }, { { 1, 1 } }, { 14 } }, 128 { MEDIA_BUS_FMT_SRGGB14_1X14, V4L2_PIX_FMT_SRGGB14P, 1, 129 { { 1, 1 } }, { { 1, 1 } }, { 14 } }, 130 { MEDIA_BUS_FMT_Y10_1X10, V4L2_PIX_FMT_Y10P, 1, 131 { { 1, 1 } }, { { 1, 1 } }, { 10 } }, 132 { MEDIA_BUS_FMT_Y10_2X8_PADHI_LE, V4L2_PIX_FMT_Y10, 1, 133 { { 1, 1 } }, { { 1, 1 } }, { 16 } }, 134 }; 135 136 static const struct camss_format_info formats_rdi_845[] = { 137 { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_UYVY, 1, 138 { { 1, 1 } }, { { 1, 1 } }, { 16 } }, 139 { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_VYUY, 1, 140 { { 1, 1 } }, { { 1, 1 } }, { 16 } }, 141 { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_YUYV, 1, 142 { { 1, 1 } }, { { 1, 1 } }, { 16 } }, 143 { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_YVYU, 1, 144 { { 1, 1 } }, { { 1, 1 } }, { 16 } }, 145 { MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_PIX_FMT_SBGGR8, 1, 146 { { 1, 1 } }, { { 1, 1 } }, { 8 } }, 147 { MEDIA_BUS_FMT_SGBRG8_1X8, V4L2_PIX_FMT_SGBRG8, 1, 148 { { 1, 1 } }, { { 1, 1 } }, { 8 } }, 149 { MEDIA_BUS_FMT_SGRBG8_1X8, V4L2_PIX_FMT_SGRBG8, 1, 150 { { 1, 1 } }, { { 1, 1 } }, { 8 } }, 151 { MEDIA_BUS_FMT_SRGGB8_1X8, V4L2_PIX_FMT_SRGGB8, 1, 152 { { 1, 1 } }, { { 1, 1 } }, { 8 } }, 153 { MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_PIX_FMT_SBGGR10P, 1, 154 { { 1, 1 } }, { { 1, 1 } }, { 10 } }, 155 { MEDIA_BUS_FMT_SGBRG10_1X10, V4L2_PIX_FMT_SGBRG10P, 1, 156 { { 1, 1 } }, { { 1, 1 } }, { 10 } }, 157 { MEDIA_BUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10P, 1, 158 { { 1, 1 } }, { { 1, 1 } }, { 10 } }, 159 { MEDIA_BUS_FMT_SRGGB10_1X10, V4L2_PIX_FMT_SRGGB10P, 1, 160 { { 1, 1 } }, { { 1, 1 } }, { 10 } }, 161 { MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_PIX_FMT_SBGGR10, 1, 162 { { 1, 1 } }, { { 1, 1 } }, { 16 } }, 163 { MEDIA_BUS_FMT_SBGGR12_1X12, V4L2_PIX_FMT_SBGGR12P, 1, 164 { { 1, 1 } }, { { 1, 1 } }, { 12 } }, 165 { MEDIA_BUS_FMT_SGBRG12_1X12, V4L2_PIX_FMT_SGBRG12P, 1, 166 { { 1, 1 } }, { { 1, 1 } }, { 12 } }, 167 { MEDIA_BUS_FMT_SGRBG12_1X12, V4L2_PIX_FMT_SGRBG12P, 1, 168 { { 1, 1 } }, { { 1, 1 } }, { 12 } }, 169 { MEDIA_BUS_FMT_SRGGB12_1X12, V4L2_PIX_FMT_SRGGB12P, 1, 170 { { 1, 1 } }, { { 1, 1 } }, { 12 } }, 171 { MEDIA_BUS_FMT_SBGGR14_1X14, V4L2_PIX_FMT_SBGGR14P, 1, 172 { { 1, 1 } }, { { 1, 1 } }, { 14 } }, 173 { MEDIA_BUS_FMT_SGBRG14_1X14, V4L2_PIX_FMT_SGBRG14P, 1, 174 { { 1, 1 } }, { { 1, 1 } }, { 14 } }, 175 { MEDIA_BUS_FMT_SGRBG14_1X14, V4L2_PIX_FMT_SGRBG14P, 1, 176 { { 1, 1 } }, { { 1, 1 } }, { 14 } }, 177 { MEDIA_BUS_FMT_SRGGB14_1X14, V4L2_PIX_FMT_SRGGB14P, 1, 178 { { 1, 1 } }, { { 1, 1 } }, { 14 } }, 179 { MEDIA_BUS_FMT_Y8_1X8, V4L2_PIX_FMT_GREY, 1, 180 { { 1, 1 } }, { { 1, 1 } }, { 8 } }, 181 { MEDIA_BUS_FMT_Y10_1X10, V4L2_PIX_FMT_Y10P, 1, 182 { { 1, 1 } }, { { 1, 1 } }, { 10 } }, 183 { MEDIA_BUS_FMT_Y10_2X8_PADHI_LE, V4L2_PIX_FMT_Y10, 1, 184 { { 1, 1 } }, { { 1, 1 } }, { 16 } }, 185 }; 186 187 static const struct camss_format_info formats_pix_8x16[] = { 188 { MEDIA_BUS_FMT_YUYV8_1_5X8, V4L2_PIX_FMT_NV12, 1, 189 { { 1, 1 } }, { { 2, 3 } }, { 8 } }, 190 { MEDIA_BUS_FMT_YVYU8_1_5X8, V4L2_PIX_FMT_NV12, 1, 191 { { 1, 1 } }, { { 2, 3 } }, { 8 } }, 192 { MEDIA_BUS_FMT_UYVY8_1_5X8, V4L2_PIX_FMT_NV12, 1, 193 { { 1, 1 } }, { { 2, 3 } }, { 8 } }, 194 { MEDIA_BUS_FMT_VYUY8_1_5X8, V4L2_PIX_FMT_NV12, 1, 195 { { 1, 1 } }, { { 2, 3 } }, { 8 } }, 196 { MEDIA_BUS_FMT_YUYV8_1_5X8, V4L2_PIX_FMT_NV21, 1, 197 { { 1, 1 } }, { { 2, 3 } }, { 8 } }, 198 { MEDIA_BUS_FMT_YVYU8_1_5X8, V4L2_PIX_FMT_NV21, 1, 199 { { 1, 1 } }, { { 2, 3 } }, { 8 } }, 200 { MEDIA_BUS_FMT_UYVY8_1_5X8, V4L2_PIX_FMT_NV21, 1, 201 { { 1, 1 } }, { { 2, 3 } }, { 8 } }, 202 { MEDIA_BUS_FMT_VYUY8_1_5X8, V4L2_PIX_FMT_NV21, 1, 203 { { 1, 1 } }, { { 2, 3 } }, { 8 } }, 204 { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_NV16, 1, 205 { { 1, 1 } }, { { 1, 2 } }, { 8 } }, 206 { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_NV16, 1, 207 { { 1, 1 } }, { { 1, 2 } }, { 8 } }, 208 { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_NV16, 1, 209 { { 1, 1 } }, { { 1, 2 } }, { 8 } }, 210 { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_NV16, 1, 211 { { 1, 1 } }, { { 1, 2 } }, { 8 } }, 212 { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_NV61, 1, 213 { { 1, 1 } }, { { 1, 2 } }, { 8 } }, 214 { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_NV61, 1, 215 { { 1, 1 } }, { { 1, 2 } }, { 8 } }, 216 { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_NV61, 1, 217 { { 1, 1 } }, { { 1, 2 } }, { 8 } }, 218 { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_NV61, 1, 219 { { 1, 1 } }, { { 1, 2 } }, { 8 } }, 220 }; 221 222 static const struct camss_format_info formats_pix_8x96[] = { 223 { MEDIA_BUS_FMT_YUYV8_1_5X8, V4L2_PIX_FMT_NV12, 1, 224 { { 1, 1 } }, { { 2, 3 } }, { 8 } }, 225 { MEDIA_BUS_FMT_YVYU8_1_5X8, V4L2_PIX_FMT_NV12, 1, 226 { { 1, 1 } }, { { 2, 3 } }, { 8 } }, 227 { MEDIA_BUS_FMT_UYVY8_1_5X8, V4L2_PIX_FMT_NV12, 1, 228 { { 1, 1 } }, { { 2, 3 } }, { 8 } }, 229 { MEDIA_BUS_FMT_VYUY8_1_5X8, V4L2_PIX_FMT_NV12, 1, 230 { { 1, 1 } }, { { 2, 3 } }, { 8 } }, 231 { MEDIA_BUS_FMT_YUYV8_1_5X8, V4L2_PIX_FMT_NV21, 1, 232 { { 1, 1 } }, { { 2, 3 } }, { 8 } }, 233 { MEDIA_BUS_FMT_YVYU8_1_5X8, V4L2_PIX_FMT_NV21, 1, 234 { { 1, 1 } }, { { 2, 3 } }, { 8 } }, 235 { MEDIA_BUS_FMT_UYVY8_1_5X8, V4L2_PIX_FMT_NV21, 1, 236 { { 1, 1 } }, { { 2, 3 } }, { 8 } }, 237 { MEDIA_BUS_FMT_VYUY8_1_5X8, V4L2_PIX_FMT_NV21, 1, 238 { { 1, 1 } }, { { 2, 3 } }, { 8 } }, 239 { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_NV16, 1, 240 { { 1, 1 } }, { { 1, 2 } }, { 8 } }, 241 { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_NV16, 1, 242 { { 1, 1 } }, { { 1, 2 } }, { 8 } }, 243 { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_NV16, 1, 244 { { 1, 1 } }, { { 1, 2 } }, { 8 } }, 245 { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_NV16, 1, 246 { { 1, 1 } }, { { 1, 2 } }, { 8 } }, 247 { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_NV61, 1, 248 { { 1, 1 } }, { { 1, 2 } }, { 8 } }, 249 { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_NV61, 1, 250 { { 1, 1 } }, { { 1, 2 } }, { 8 } }, 251 { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_NV61, 1, 252 { { 1, 1 } }, { { 1, 2 } }, { 8 } }, 253 { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_NV61, 1, 254 { { 1, 1 } }, { { 1, 2 } }, { 8 } }, 255 { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_UYVY, 1, 256 { { 1, 1 } }, { { 1, 1 } }, { 16 } }, 257 { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_VYUY, 1, 258 { { 1, 1 } }, { { 1, 1 } }, { 16 } }, 259 { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_YUYV, 1, 260 { { 1, 1 } }, { { 1, 1 } }, { 16 } }, 261 { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_YVYU, 1, 262 { { 1, 1 } }, { { 1, 1 } }, { 16 } }, 263 }; 264 265 /* ----------------------------------------------------------------------------- 266 * Helper functions 267 */ 268 269 static int video_find_format(u32 code, u32 pixelformat, 270 const struct camss_format_info *formats, 271 unsigned int nformats) 272 { 273 int i; 274 275 for (i = 0; i < nformats; i++) { 276 if (formats[i].code == code && 277 formats[i].pixelformat == pixelformat) 278 return i; 279 } 280 281 for (i = 0; i < nformats; i++) 282 if (formats[i].code == code) 283 return i; 284 285 WARN_ON(1); 286 287 return -EINVAL; 288 } 289 290 /* 291 * video_mbus_to_pix_mp - Convert v4l2_mbus_framefmt to v4l2_pix_format_mplane 292 * @mbus: v4l2_mbus_framefmt format (input) 293 * @pix: v4l2_pix_format_mplane format (output) 294 * @f: a pointer to formats array element to be used for the conversion 295 * @alignment: bytesperline alignment value 296 * 297 * Fill the output pix structure with information from the input mbus format. 298 * 299 * Return 0 on success or a negative error code otherwise 300 */ 301 static int video_mbus_to_pix_mp(const struct v4l2_mbus_framefmt *mbus, 302 struct v4l2_pix_format_mplane *pix, 303 const struct camss_format_info *f, 304 unsigned int alignment) 305 { 306 unsigned int i; 307 u32 bytesperline; 308 309 memset(pix, 0, sizeof(*pix)); 310 v4l2_fill_pix_format_mplane(pix, mbus); 311 pix->pixelformat = f->pixelformat; 312 pix->num_planes = f->planes; 313 for (i = 0; i < pix->num_planes; i++) { 314 bytesperline = pix->width / f->hsub[i].numerator * 315 f->hsub[i].denominator * f->bpp[i] / 8; 316 bytesperline = ALIGN(bytesperline, alignment); 317 pix->plane_fmt[i].bytesperline = bytesperline; 318 pix->plane_fmt[i].sizeimage = pix->height / 319 f->vsub[i].numerator * f->vsub[i].denominator * 320 bytesperline; 321 } 322 323 return 0; 324 } 325 326 static struct v4l2_subdev *video_remote_subdev(struct camss_video *video, 327 u32 *pad) 328 { 329 struct media_pad *remote; 330 331 remote = media_pad_remote_pad_first(&video->pad); 332 333 if (!remote || !is_media_entity_v4l2_subdev(remote->entity)) 334 return NULL; 335 336 if (pad) 337 *pad = remote->index; 338 339 return media_entity_to_v4l2_subdev(remote->entity); 340 } 341 342 static int video_get_subdev_format(struct camss_video *video, 343 struct v4l2_format *format) 344 { 345 struct v4l2_subdev_format fmt = { 346 .which = V4L2_SUBDEV_FORMAT_ACTIVE, 347 }; 348 struct v4l2_subdev *subdev; 349 u32 pad; 350 int ret; 351 352 subdev = video_remote_subdev(video, &pad); 353 if (subdev == NULL) 354 return -EPIPE; 355 356 memset(&fmt, 0, sizeof(fmt)); 357 fmt.pad = pad; 358 359 ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt); 360 if (ret) 361 return ret; 362 363 ret = video_find_format(fmt.format.code, 364 format->fmt.pix_mp.pixelformat, 365 video->formats, video->nformats); 366 if (ret < 0) 367 return ret; 368 369 format->type = video->type; 370 371 return video_mbus_to_pix_mp(&fmt.format, &format->fmt.pix_mp, 372 &video->formats[ret], video->bpl_alignment); 373 } 374 375 /* ----------------------------------------------------------------------------- 376 * Video queue operations 377 */ 378 379 static int video_queue_setup(struct vb2_queue *q, 380 unsigned int *num_buffers, unsigned int *num_planes, 381 unsigned int sizes[], struct device *alloc_devs[]) 382 { 383 struct camss_video *video = vb2_get_drv_priv(q); 384 const struct v4l2_pix_format_mplane *format = 385 &video->active_fmt.fmt.pix_mp; 386 unsigned int i; 387 388 if (*num_planes) { 389 if (*num_planes != format->num_planes) 390 return -EINVAL; 391 392 for (i = 0; i < *num_planes; i++) 393 if (sizes[i] < format->plane_fmt[i].sizeimage) 394 return -EINVAL; 395 396 return 0; 397 } 398 399 *num_planes = format->num_planes; 400 401 for (i = 0; i < *num_planes; i++) 402 sizes[i] = format->plane_fmt[i].sizeimage; 403 404 return 0; 405 } 406 407 static int video_buf_init(struct vb2_buffer *vb) 408 { 409 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 410 struct camss_video *video = vb2_get_drv_priv(vb->vb2_queue); 411 struct camss_buffer *buffer = container_of(vbuf, struct camss_buffer, 412 vb); 413 const struct v4l2_pix_format_mplane *format = 414 &video->active_fmt.fmt.pix_mp; 415 struct sg_table *sgt; 416 unsigned int i; 417 418 for (i = 0; i < format->num_planes; i++) { 419 sgt = vb2_dma_sg_plane_desc(vb, i); 420 if (!sgt) 421 return -EFAULT; 422 423 buffer->addr[i] = sg_dma_address(sgt->sgl); 424 } 425 426 if (format->pixelformat == V4L2_PIX_FMT_NV12 || 427 format->pixelformat == V4L2_PIX_FMT_NV21 || 428 format->pixelformat == V4L2_PIX_FMT_NV16 || 429 format->pixelformat == V4L2_PIX_FMT_NV61) 430 buffer->addr[1] = buffer->addr[0] + 431 format->plane_fmt[0].bytesperline * 432 format->height; 433 434 return 0; 435 } 436 437 static int video_buf_prepare(struct vb2_buffer *vb) 438 { 439 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 440 struct camss_video *video = vb2_get_drv_priv(vb->vb2_queue); 441 const struct v4l2_pix_format_mplane *format = 442 &video->active_fmt.fmt.pix_mp; 443 unsigned int i; 444 445 for (i = 0; i < format->num_planes; i++) { 446 if (format->plane_fmt[i].sizeimage > vb2_plane_size(vb, i)) 447 return -EINVAL; 448 449 vb2_set_plane_payload(vb, i, format->plane_fmt[i].sizeimage); 450 } 451 452 vbuf->field = V4L2_FIELD_NONE; 453 454 return 0; 455 } 456 457 static void video_buf_queue(struct vb2_buffer *vb) 458 { 459 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 460 struct camss_video *video = vb2_get_drv_priv(vb->vb2_queue); 461 struct camss_buffer *buffer = container_of(vbuf, struct camss_buffer, 462 vb); 463 464 video->ops->queue_buffer(video, buffer); 465 } 466 467 static int video_check_format(struct camss_video *video) 468 { 469 struct v4l2_pix_format_mplane *pix = &video->active_fmt.fmt.pix_mp; 470 struct v4l2_format format; 471 struct v4l2_pix_format_mplane *sd_pix = &format.fmt.pix_mp; 472 int ret; 473 474 sd_pix->pixelformat = pix->pixelformat; 475 ret = video_get_subdev_format(video, &format); 476 if (ret < 0) 477 return ret; 478 479 if (pix->pixelformat != sd_pix->pixelformat || 480 pix->height != sd_pix->height || 481 pix->width != sd_pix->width || 482 pix->num_planes != sd_pix->num_planes || 483 pix->field != format.fmt.pix_mp.field) 484 return -EPIPE; 485 486 return 0; 487 } 488 489 static int video_start_streaming(struct vb2_queue *q, unsigned int count) 490 { 491 struct camss_video *video = vb2_get_drv_priv(q); 492 struct video_device *vdev = &video->vdev; 493 struct media_entity *entity; 494 struct media_pad *pad; 495 struct v4l2_subdev *subdev; 496 int ret; 497 498 ret = video_device_pipeline_alloc_start(vdev); 499 if (ret < 0) { 500 dev_err(video->camss->dev, "Failed to start media pipeline: %d\n", ret); 501 goto flush_buffers; 502 } 503 504 ret = video_check_format(video); 505 if (ret < 0) 506 goto error; 507 508 entity = &vdev->entity; 509 while (1) { 510 pad = &entity->pads[0]; 511 if (!(pad->flags & MEDIA_PAD_FL_SINK)) 512 break; 513 514 pad = media_pad_remote_pad_first(pad); 515 if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) 516 break; 517 518 entity = pad->entity; 519 subdev = media_entity_to_v4l2_subdev(entity); 520 521 ret = v4l2_subdev_call(subdev, video, s_stream, 1); 522 if (ret < 0 && ret != -ENOIOCTLCMD) 523 goto error; 524 } 525 526 return 0; 527 528 error: 529 video_device_pipeline_stop(vdev); 530 531 flush_buffers: 532 video->ops->flush_buffers(video, VB2_BUF_STATE_QUEUED); 533 534 return ret; 535 } 536 537 static void video_stop_streaming(struct vb2_queue *q) 538 { 539 struct camss_video *video = vb2_get_drv_priv(q); 540 struct video_device *vdev = &video->vdev; 541 struct media_entity *entity; 542 struct media_pad *pad; 543 struct v4l2_subdev *subdev; 544 int ret; 545 546 entity = &vdev->entity; 547 while (1) { 548 pad = &entity->pads[0]; 549 if (!(pad->flags & MEDIA_PAD_FL_SINK)) 550 break; 551 552 pad = media_pad_remote_pad_first(pad); 553 if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) 554 break; 555 556 entity = pad->entity; 557 subdev = media_entity_to_v4l2_subdev(entity); 558 559 ret = v4l2_subdev_call(subdev, video, s_stream, 0); 560 561 if (entity->use_count > 1) { 562 /* Don't stop if other instances of the pipeline are still running */ 563 dev_dbg(video->camss->dev, "Video pipeline still used, don't stop streaming.\n"); 564 return; 565 } 566 567 if (ret) { 568 dev_err(video->camss->dev, "Video pipeline stop failed: %d\n", ret); 569 return; 570 } 571 } 572 573 video_device_pipeline_stop(vdev); 574 575 video->ops->flush_buffers(video, VB2_BUF_STATE_ERROR); 576 } 577 578 static const struct vb2_ops msm_video_vb2_q_ops = { 579 .queue_setup = video_queue_setup, 580 .wait_prepare = vb2_ops_wait_prepare, 581 .wait_finish = vb2_ops_wait_finish, 582 .buf_init = video_buf_init, 583 .buf_prepare = video_buf_prepare, 584 .buf_queue = video_buf_queue, 585 .start_streaming = video_start_streaming, 586 .stop_streaming = video_stop_streaming, 587 }; 588 589 /* ----------------------------------------------------------------------------- 590 * V4L2 ioctls 591 */ 592 593 static int video_querycap(struct file *file, void *fh, 594 struct v4l2_capability *cap) 595 { 596 strscpy(cap->driver, "qcom-camss", sizeof(cap->driver)); 597 strscpy(cap->card, "Qualcomm Camera Subsystem", sizeof(cap->card)); 598 599 return 0; 600 } 601 602 static int video_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f) 603 { 604 struct camss_video *video = video_drvdata(file); 605 int i, j, k; 606 u32 mcode = f->mbus_code; 607 608 if (f->type != video->type) 609 return -EINVAL; 610 611 if (f->index >= video->nformats) 612 return -EINVAL; 613 614 /* 615 * Find index "i" of "k"th unique pixelformat in formats array. 616 * 617 * If f->mbus_code passed to video_enum_fmt() is not zero, a device 618 * with V4L2_CAP_IO_MC capability restricts enumeration to only the 619 * pixel formats that can be produced from that media bus code. 620 * This is implemented by skipping video->formats[] entries with 621 * code != f->mbus_code (if f->mbus_code is not zero). 622 * If the f->mbus_code passed to video_enum_fmt() is not supported, 623 * -EINVAL is returned. 624 * If f->mbus_code is zero, all the pixel formats are enumerated. 625 */ 626 k = -1; 627 for (i = 0; i < video->nformats; i++) { 628 if (mcode != 0 && video->formats[i].code != mcode) 629 continue; 630 631 for (j = 0; j < i; j++) { 632 if (mcode != 0 && video->formats[j].code != mcode) 633 continue; 634 if (video->formats[i].pixelformat == 635 video->formats[j].pixelformat) 636 break; 637 } 638 639 if (j == i) 640 k++; 641 642 if (k == f->index) 643 break; 644 } 645 646 if (k == -1 || k < f->index) 647 /* 648 * All the unique pixel formats matching the arguments 649 * have been enumerated (k >= 0 and f->index > 0), or 650 * no pixel formats match the non-zero f->mbus_code (k == -1). 651 */ 652 return -EINVAL; 653 654 f->pixelformat = video->formats[i].pixelformat; 655 656 return 0; 657 } 658 659 static int video_enum_framesizes(struct file *file, void *fh, 660 struct v4l2_frmsizeenum *fsize) 661 { 662 struct camss_video *video = video_drvdata(file); 663 int i; 664 665 if (fsize->index) 666 return -EINVAL; 667 668 /* Only accept pixel format present in the formats[] table */ 669 for (i = 0; i < video->nformats; i++) { 670 if (video->formats[i].pixelformat == fsize->pixel_format) 671 break; 672 } 673 674 if (i == video->nformats) 675 return -EINVAL; 676 677 fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS; 678 fsize->stepwise.min_width = CAMSS_FRAME_MIN_WIDTH; 679 fsize->stepwise.max_width = CAMSS_FRAME_MAX_WIDTH; 680 fsize->stepwise.min_height = CAMSS_FRAME_MIN_HEIGHT; 681 fsize->stepwise.max_height = (video->line_based) ? 682 CAMSS_FRAME_MAX_HEIGHT_PIX : CAMSS_FRAME_MAX_HEIGHT_RDI; 683 fsize->stepwise.step_width = 1; 684 fsize->stepwise.step_height = 1; 685 686 return 0; 687 } 688 689 static int video_g_fmt(struct file *file, void *fh, struct v4l2_format *f) 690 { 691 struct camss_video *video = video_drvdata(file); 692 693 *f = video->active_fmt; 694 695 return 0; 696 } 697 698 static int __video_try_fmt(struct camss_video *video, struct v4l2_format *f) 699 { 700 struct v4l2_pix_format_mplane *pix_mp; 701 const struct camss_format_info *fi; 702 struct v4l2_plane_pix_format *p; 703 u32 bytesperline[3] = { 0 }; 704 u32 sizeimage[3] = { 0 }; 705 u32 width, height; 706 u32 bpl, lines; 707 int i, j; 708 709 pix_mp = &f->fmt.pix_mp; 710 711 if (video->line_based) 712 for (i = 0; i < pix_mp->num_planes && i < 3; i++) { 713 p = &pix_mp->plane_fmt[i]; 714 bytesperline[i] = clamp_t(u32, p->bytesperline, 715 1, 65528); 716 sizeimage[i] = clamp_t(u32, p->sizeimage, 717 bytesperline[i], 718 bytesperline[i] * CAMSS_FRAME_MAX_HEIGHT_PIX); 719 } 720 721 for (j = 0; j < video->nformats; j++) 722 if (pix_mp->pixelformat == video->formats[j].pixelformat) 723 break; 724 725 if (j == video->nformats) 726 j = 0; /* default format */ 727 728 fi = &video->formats[j]; 729 width = pix_mp->width; 730 height = pix_mp->height; 731 732 memset(pix_mp, 0, sizeof(*pix_mp)); 733 734 pix_mp->pixelformat = fi->pixelformat; 735 pix_mp->width = clamp_t(u32, width, 1, CAMSS_FRAME_MAX_WIDTH); 736 pix_mp->height = clamp_t(u32, height, 1, CAMSS_FRAME_MAX_HEIGHT_RDI); 737 pix_mp->num_planes = fi->planes; 738 for (i = 0; i < pix_mp->num_planes; i++) { 739 bpl = pix_mp->width / fi->hsub[i].numerator * 740 fi->hsub[i].denominator * fi->bpp[i] / 8; 741 bpl = ALIGN(bpl, video->bpl_alignment); 742 pix_mp->plane_fmt[i].bytesperline = bpl; 743 pix_mp->plane_fmt[i].sizeimage = pix_mp->height / 744 fi->vsub[i].numerator * fi->vsub[i].denominator * bpl; 745 } 746 747 pix_mp->field = V4L2_FIELD_NONE; 748 pix_mp->colorspace = V4L2_COLORSPACE_SRGB; 749 pix_mp->flags = 0; 750 pix_mp->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(pix_mp->colorspace); 751 pix_mp->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true, 752 pix_mp->colorspace, pix_mp->ycbcr_enc); 753 pix_mp->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(pix_mp->colorspace); 754 755 if (video->line_based) 756 for (i = 0; i < pix_mp->num_planes; i++) { 757 p = &pix_mp->plane_fmt[i]; 758 p->bytesperline = clamp_t(u32, p->bytesperline, 759 1, 65528); 760 p->sizeimage = clamp_t(u32, p->sizeimage, 761 p->bytesperline, 762 p->bytesperline * CAMSS_FRAME_MAX_HEIGHT_PIX); 763 lines = p->sizeimage / p->bytesperline; 764 765 if (p->bytesperline < bytesperline[i]) 766 p->bytesperline = ALIGN(bytesperline[i], 8); 767 768 if (p->sizeimage < p->bytesperline * lines) 769 p->sizeimage = p->bytesperline * lines; 770 771 if (p->sizeimage < sizeimage[i]) 772 p->sizeimage = sizeimage[i]; 773 } 774 775 return 0; 776 } 777 778 static int video_try_fmt(struct file *file, void *fh, struct v4l2_format *f) 779 { 780 struct camss_video *video = video_drvdata(file); 781 782 return __video_try_fmt(video, f); 783 } 784 785 static int video_s_fmt(struct file *file, void *fh, struct v4l2_format *f) 786 { 787 struct camss_video *video = video_drvdata(file); 788 int ret; 789 790 if (vb2_is_busy(&video->vb2_q)) 791 return -EBUSY; 792 793 ret = __video_try_fmt(video, f); 794 if (ret < 0) 795 return ret; 796 797 video->active_fmt = *f; 798 799 return 0; 800 } 801 802 static int video_enum_input(struct file *file, void *fh, 803 struct v4l2_input *input) 804 { 805 if (input->index > 0) 806 return -EINVAL; 807 808 strscpy(input->name, "camera", sizeof(input->name)); 809 input->type = V4L2_INPUT_TYPE_CAMERA; 810 811 return 0; 812 } 813 814 static int video_g_input(struct file *file, void *fh, unsigned int *input) 815 { 816 *input = 0; 817 818 return 0; 819 } 820 821 static int video_s_input(struct file *file, void *fh, unsigned int input) 822 { 823 return input == 0 ? 0 : -EINVAL; 824 } 825 826 static const struct v4l2_ioctl_ops msm_vid_ioctl_ops = { 827 .vidioc_querycap = video_querycap, 828 .vidioc_enum_fmt_vid_cap = video_enum_fmt, 829 .vidioc_enum_framesizes = video_enum_framesizes, 830 .vidioc_g_fmt_vid_cap_mplane = video_g_fmt, 831 .vidioc_s_fmt_vid_cap_mplane = video_s_fmt, 832 .vidioc_try_fmt_vid_cap_mplane = video_try_fmt, 833 .vidioc_reqbufs = vb2_ioctl_reqbufs, 834 .vidioc_querybuf = vb2_ioctl_querybuf, 835 .vidioc_qbuf = vb2_ioctl_qbuf, 836 .vidioc_expbuf = vb2_ioctl_expbuf, 837 .vidioc_dqbuf = vb2_ioctl_dqbuf, 838 .vidioc_create_bufs = vb2_ioctl_create_bufs, 839 .vidioc_prepare_buf = vb2_ioctl_prepare_buf, 840 .vidioc_streamon = vb2_ioctl_streamon, 841 .vidioc_streamoff = vb2_ioctl_streamoff, 842 .vidioc_enum_input = video_enum_input, 843 .vidioc_g_input = video_g_input, 844 .vidioc_s_input = video_s_input, 845 }; 846 847 /* ----------------------------------------------------------------------------- 848 * V4L2 file operations 849 */ 850 851 static int video_open(struct file *file) 852 { 853 struct video_device *vdev = video_devdata(file); 854 struct camss_video *video = video_drvdata(file); 855 struct v4l2_fh *vfh; 856 int ret; 857 858 mutex_lock(&video->lock); 859 860 vfh = kzalloc(sizeof(*vfh), GFP_KERNEL); 861 if (vfh == NULL) { 862 ret = -ENOMEM; 863 goto error_alloc; 864 } 865 866 v4l2_fh_init(vfh, vdev); 867 v4l2_fh_add(vfh); 868 869 file->private_data = vfh; 870 871 ret = v4l2_pipeline_pm_get(&vdev->entity); 872 if (ret < 0) { 873 dev_err(video->camss->dev, "Failed to power up pipeline: %d\n", 874 ret); 875 goto error_pm_use; 876 } 877 878 mutex_unlock(&video->lock); 879 880 return 0; 881 882 error_pm_use: 883 v4l2_fh_release(file); 884 885 error_alloc: 886 mutex_unlock(&video->lock); 887 888 return ret; 889 } 890 891 static int video_release(struct file *file) 892 { 893 struct video_device *vdev = video_devdata(file); 894 895 vb2_fop_release(file); 896 897 v4l2_pipeline_pm_put(&vdev->entity); 898 899 file->private_data = NULL; 900 901 return 0; 902 } 903 904 static const struct v4l2_file_operations msm_vid_fops = { 905 .owner = THIS_MODULE, 906 .unlocked_ioctl = video_ioctl2, 907 .open = video_open, 908 .release = video_release, 909 .poll = vb2_fop_poll, 910 .mmap = vb2_fop_mmap, 911 .read = vb2_fop_read, 912 }; 913 914 /* ----------------------------------------------------------------------------- 915 * CAMSS video core 916 */ 917 918 static void msm_video_release(struct video_device *vdev) 919 { 920 struct camss_video *video = video_get_drvdata(vdev); 921 922 media_entity_cleanup(&vdev->entity); 923 924 mutex_destroy(&video->q_lock); 925 mutex_destroy(&video->lock); 926 927 if (atomic_dec_and_test(&video->camss->ref_count)) 928 camss_delete(video->camss); 929 } 930 931 /* 932 * msm_video_init_format - Helper function to initialize format 933 * @video: struct camss_video 934 * 935 * Initialize pad format with default value. 936 * 937 * Return 0 on success or a negative error code otherwise 938 */ 939 static int msm_video_init_format(struct camss_video *video) 940 { 941 int ret; 942 struct v4l2_format format = { 943 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, 944 .fmt.pix_mp = { 945 .width = 1920, 946 .height = 1080, 947 .pixelformat = video->formats[0].pixelformat, 948 }, 949 }; 950 951 ret = __video_try_fmt(video, &format); 952 if (ret < 0) 953 return ret; 954 955 video->active_fmt = format; 956 957 return 0; 958 } 959 960 /* 961 * msm_video_register - Register a video device node 962 * @video: struct camss_video 963 * @v4l2_dev: V4L2 device 964 * @name: name to be used for the video device node 965 * 966 * Initialize and register a video device node to a V4L2 device. Also 967 * initialize the vb2 queue. 968 * 969 * Return 0 on success or a negative error code otherwise 970 */ 971 972 int msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev, 973 const char *name, int is_pix) 974 { 975 struct media_pad *pad = &video->pad; 976 struct video_device *vdev; 977 struct vb2_queue *q; 978 int ret; 979 980 vdev = &video->vdev; 981 982 mutex_init(&video->q_lock); 983 984 q = &video->vb2_q; 985 q->drv_priv = video; 986 q->mem_ops = &vb2_dma_sg_memops; 987 q->ops = &msm_video_vb2_q_ops; 988 q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; 989 q->io_modes = VB2_DMABUF | VB2_MMAP | VB2_READ; 990 q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; 991 q->buf_struct_size = sizeof(struct camss_buffer); 992 q->dev = video->camss->dev; 993 q->lock = &video->q_lock; 994 ret = vb2_queue_init(q); 995 if (ret < 0) { 996 dev_err(v4l2_dev->dev, "Failed to init vb2 queue: %d\n", ret); 997 goto error_vb2_init; 998 } 999 1000 pad->flags = MEDIA_PAD_FL_SINK; 1001 ret = media_entity_pads_init(&vdev->entity, 1, pad); 1002 if (ret < 0) { 1003 dev_err(v4l2_dev->dev, "Failed to init video entity: %d\n", 1004 ret); 1005 goto error_vb2_init; 1006 } 1007 1008 mutex_init(&video->lock); 1009 1010 if (video->camss->version == CAMSS_8x16) { 1011 if (is_pix) { 1012 video->formats = formats_pix_8x16; 1013 video->nformats = ARRAY_SIZE(formats_pix_8x16); 1014 } else { 1015 video->formats = formats_rdi_8x16; 1016 video->nformats = ARRAY_SIZE(formats_rdi_8x16); 1017 } 1018 } else if (video->camss->version == CAMSS_8x96 || 1019 video->camss->version == CAMSS_660) { 1020 if (is_pix) { 1021 video->formats = formats_pix_8x96; 1022 video->nformats = ARRAY_SIZE(formats_pix_8x96); 1023 } else { 1024 video->formats = formats_rdi_8x96; 1025 video->nformats = ARRAY_SIZE(formats_rdi_8x96); 1026 } 1027 } else if (video->camss->version == CAMSS_845 || 1028 video->camss->version == CAMSS_8250) { 1029 video->formats = formats_rdi_845; 1030 video->nformats = ARRAY_SIZE(formats_rdi_845); 1031 } else { 1032 ret = -EINVAL; 1033 goto error_video_register; 1034 } 1035 1036 ret = msm_video_init_format(video); 1037 if (ret < 0) { 1038 dev_err(v4l2_dev->dev, "Failed to init format: %d\n", ret); 1039 goto error_video_register; 1040 } 1041 1042 vdev->fops = &msm_vid_fops; 1043 vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_STREAMING 1044 | V4L2_CAP_READWRITE | V4L2_CAP_IO_MC; 1045 vdev->ioctl_ops = &msm_vid_ioctl_ops; 1046 vdev->release = msm_video_release; 1047 vdev->v4l2_dev = v4l2_dev; 1048 vdev->vfl_dir = VFL_DIR_RX; 1049 vdev->queue = &video->vb2_q; 1050 vdev->lock = &video->lock; 1051 strscpy(vdev->name, name, sizeof(vdev->name)); 1052 1053 ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); 1054 if (ret < 0) { 1055 dev_err(v4l2_dev->dev, "Failed to register video device: %d\n", 1056 ret); 1057 goto error_video_register; 1058 } 1059 1060 video_set_drvdata(vdev, video); 1061 atomic_inc(&video->camss->ref_count); 1062 1063 return 0; 1064 1065 error_video_register: 1066 media_entity_cleanup(&vdev->entity); 1067 mutex_destroy(&video->lock); 1068 error_vb2_init: 1069 mutex_destroy(&video->q_lock); 1070 1071 return ret; 1072 } 1073 1074 void msm_video_unregister(struct camss_video *video) 1075 { 1076 atomic_inc(&video->camss->ref_count); 1077 vb2_video_unregister_device(&video->vdev); 1078 atomic_dec(&video->camss->ref_count); 1079 } 1080